import { db } from "../db";
import type { MonthClosure } from "../types";
import { eventsInRange, summarize } from "./attendance";
import { getRateAt } from "./payRates";
import { parseRange } from "../util/dateRange";

export interface ClosureSummary {
  worked_minutes: number;
  shift_count: number;
  earned_estimate: number;
}

export function getClosureSummary(employeeId: number, period: string): ClosureSummary {
  const { fromIso, toIso } = parseRange({ month: period });
  const events = eventsInRange(employeeId, fromIso, toIso);
  const { sessions } = summarize(events, new Date());

  let workedMs = 0;
  let earned = 0;
  let shiftCount = 0;

  for (const session of sessions) {
    workedMs += session.workedMs;
    if (session.workedMs > 0) shiftCount++;
    const rate = getRateAt(employeeId, session.clockIn.slice(0, 10));
    earned += (session.workedMs / 3_600_000) * rate;
  }

  return {
    worked_minutes: Math.round(workedMs / 60_000),
    shift_count: shiftCount,
    earned_estimate: Math.round(earned),
  };
}

export function hasOpenSessionInPeriod(employeeId: number, period: string): boolean {
  const { fromIso, toIso } = parseRange({ month: period });
  const events = eventsInRange(employeeId, fromIso, toIso);
  const { sessions } = summarize(events, new Date());
  return sessions.some((s) => s.open);
}

export function findClosure(employeeId: number, period: string): MonthClosure | undefined {
  return db
    .prepare<[number, string], MonthClosure>("SELECT * FROM month_closures WHERE employee_id = ? AND period = ?")
    .get(employeeId, period);
}

export function getOrCreateClosure(employeeId: number, period: string): MonthClosure {
  const existing = findClosure(employeeId, period);
  if (existing) return existing;
  db.prepare("INSERT INTO month_closures (employee_id, period, status) VALUES (?, ?, 'waiting_employee')").run(
    employeeId,
    period
  );
  return findClosure(employeeId, period)!;
}

export function confirmClosure(employeeId: number, period: string): void {
  const closure = getOrCreateClosure(employeeId, period);
  if (closure.status === "locked") {
    throw new Error("Docházka je už uzamčena.");
  }
  if (closure.status === "confirmed") {
    return;
  }
  if (hasOpenSessionInPeriod(employeeId, period)) {
    throw new Error("V tomto měsíci máš stále otevřenou směnu.");
  }

  db.prepare(
    "UPDATE month_closures SET status = 'confirmed', employee_confirmed_at = strftime('%Y-%m-%dT%H:%M:%fZ', 'now') WHERE id = ?"
  ).run(closure.id);
}

export function lockClosure(employeeId: number, period: string): void {
  const closure = findClosure(employeeId, period);
  if (!closure || closure.status !== "confirmed") {
    throw new Error("Docházku zatím nepotvrdil zaměstnanec.");
  }
  if (hasOpenSessionInPeriod(employeeId, period)) {
    throw new Error("Zaměstnanec má stále otevřenou směnu.");
  }

  db.prepare(
    "UPDATE month_closures SET status = 'locked', locked_at = strftime('%Y-%m-%dT%H:%M:%fZ', 'now') WHERE id = ?"
  ).run(closure.id);
}
