import type Database from 'better-sqlite3';
import type { WeeklyContinuity } from '@shared/types';
import { KST_OFFSET_MS } from '../../shared/util/kstDate.js';
const ONE_DAY_MS = 24 * 60 * 60 * 1000;
const WEEK_TARGET = 7;
const RECOVERY_GAP_DAYS = 7;

function toKstDateKey(d: Date): string {
  const k = new Date(d.getTime() + KST_OFFSET_MS);
  return k.toISOString().slice(0, 10);
}

function kstMondayOf(d: Date): string {
  const k = new Date(d.getTime() + KST_OFFSET_MS);
  const dayIdx = (k.getUTCDay() + 6) % 7;
  k.setUTCDate(k.getUTCDate() - dayIdx);
  return k.toISOString().slice(0, 10);
}

function addDaysIso(iso: string, days: number): string {
  const d = new Date(iso + 'T00:00:00Z');
  d.setUTCDate(d.getUTCDate() + days);
  return d.toISOString().slice(0, 10);
}

export class ContinuityService {
  constructor(
    private db: Database.Database,
    private now: () => Date = () => new Date()
  ) {}

  get(): WeeklyContinuity {
    const rows = this.db
      .prepare(
        `SELECT created_at FROM notes WHERE deleted_at IS NULL ORDER BY created_at ASC`
      )
      .all() as Array<{ created_at: string }>;
    const dates = rows.map((r) => new Date(r.created_at));
    if (dates.length === 0) {
      return {
        weekStart: kstMondayOf(this.now()),
        weekCount: 0,
        weekTarget: WEEK_TARGET,
        consecutiveCompleteWeeks: 0,
        showRecoveryToast: false,
        lastNoteAt: null
      };
    }

    const byWeek = new Map<string, number>();
    for (const d of dates) {
      const wk = kstMondayOf(d);
      byWeek.set(wk, (byWeek.get(wk) ?? 0) + 1);
    }

    const currentWeek = kstMondayOf(this.now());
    const weekCount = byWeek.get(currentWeek) ?? 0;

    let consecutive = 0;
    let cursor = weekCount >= WEEK_TARGET ? currentWeek : addDaysIso(currentWeek, -7);
    while ((byWeek.get(cursor) ?? 0) >= WEEK_TARGET) {
      consecutive += 1;
      cursor = addDaysIso(cursor, -7);
    }

    const last = dates[dates.length - 1]!;
    const todayKst = toKstDateKey(this.now());
    const lastIsToday = toKstDateKey(last) === todayKst;
    let showRecoveryToast = false;
    if (lastIsToday && dates.length >= 2) {
      const prev = dates[dates.length - 2]!;
      const gapMs = last.getTime() - prev.getTime();
      if (gapMs >= RECOVERY_GAP_DAYS * ONE_DAY_MS) showRecoveryToast = true;
    }

    return {
      weekStart: currentWeek,
      weekCount,
      weekTarget: WEEK_TARGET,
      consecutiveCompleteWeeks: consecutive,
      showRecoveryToast,
      lastNoteAt: last.toISOString()
    };
  }
}
