import Database from "better-sqlite3";
import path from "path";
import type { SiteContent, TeamMember, RichListItem, VictoryItem } from "@/types/content";
import { MS_PER_DAY } from "@/lib/constants";

const DB_PATH =
  process.env.DATABASE_PATH ||
  path.join(process.cwd(), "db", "blackheart.db");

let _db: Database.Database | null = null;

export function getDb(): Database.Database {
  if (!_db) {
    _db = new Database(DB_PATH);
    _db.pragma("journal_mode = WAL");
    _db.pragma("foreign_keys = ON");
    runMigrations(_db);
  }
  return _db;
}

// --- Migrations ---
// Each migration has a unique version number and runs exactly once.
// Add new migrations to the end of the array. Never modify existing ones.

interface Migration {
  version: number;
  name: string;
  up: (db: Database.Database) => void;
}

const migrations: Migration[] = [
  {
    version: 1,
    name: "create_sections_and_team_members",
    up: (db) => {
      db.exec(`
        CREATE TABLE IF NOT EXISTS sections (
          key TEXT PRIMARY KEY,
          data TEXT NOT NULL,
          updated_at TEXT DEFAULT (datetime('now'))
        );
        CREATE TABLE IF NOT EXISTS team_members (
          id INTEGER PRIMARY KEY AUTOINCREMENT,
          name TEXT NOT NULL,
          role TEXT NOT NULL,
          image TEXT NOT NULL,
          instagram TEXT,
          description TEXT,
          sort_order INTEGER NOT NULL DEFAULT 0,
          created_at TEXT DEFAULT (datetime('now')),
          updated_at TEXT DEFAULT (datetime('now'))
        );
      `);
    },
  },
  {
    version: 2,
    name: "add_team_bio_columns",
    up: (db) => {
      const cols = db.prepare("PRAGMA table_info(team_members)").all() as { name: string }[];
      const colNames = new Set(cols.map((c) => c.name));
      if (!colNames.has("experience")) db.exec("ALTER TABLE team_members ADD COLUMN experience TEXT");
      if (!colNames.has("victories")) db.exec("ALTER TABLE team_members ADD COLUMN victories TEXT");
      if (!colNames.has("education")) db.exec("ALTER TABLE team_members ADD COLUMN education TEXT");
    },
  },
  {
    version: 3,
    name: "create_mc_registrations",
    up: (db) => {
      db.exec(`
        CREATE TABLE IF NOT EXISTS mc_registrations (
          id INTEGER PRIMARY KEY AUTOINCREMENT,
          master_class_title TEXT NOT NULL,
          name TEXT NOT NULL,
          instagram TEXT NOT NULL,
          telegram TEXT,
          created_at TEXT DEFAULT (datetime('now'))
        );
      `);
    },
  },
  {
    version: 4,
    name: "add_mc_notification_tracking",
    up: (db) => {
      const cols = db.prepare("PRAGMA table_info(mc_registrations)").all() as { name: string }[];
      const colNames = new Set(cols.map((c) => c.name));
      if (!colNames.has("notified_confirm"))
        db.exec("ALTER TABLE mc_registrations ADD COLUMN notified_confirm INTEGER NOT NULL DEFAULT 0");
      if (!colNames.has("notified_reminder"))
        db.exec("ALTER TABLE mc_registrations ADD COLUMN notified_reminder INTEGER NOT NULL DEFAULT 0");
    },
  },
  {
    version: 5,
    name: "create_group_bookings",
    up: (db) => {
      db.exec(`
        CREATE TABLE IF NOT EXISTS group_bookings (
          id INTEGER PRIMARY KEY AUTOINCREMENT,
          name TEXT NOT NULL,
          phone TEXT NOT NULL,
          group_info TEXT,
          notified_confirm INTEGER NOT NULL DEFAULT 0,
          notified_reminder INTEGER NOT NULL DEFAULT 0,
          created_at TEXT DEFAULT (datetime('now'))
        );
      `);
    },
  },
  {
    version: 6,
    name: "create_open_day_tables",
    up: (db) => {
      db.exec(`
        CREATE TABLE IF NOT EXISTS open_day_events (
          id INTEGER PRIMARY KEY AUTOINCREMENT,
          date TEXT NOT NULL,
          title TEXT NOT NULL DEFAULT 'День открытых дверей',
          description TEXT,
          price_per_class INTEGER NOT NULL DEFAULT 30,
          discount_price INTEGER NOT NULL DEFAULT 20,
          discount_threshold INTEGER NOT NULL DEFAULT 3,
          min_bookings INTEGER NOT NULL DEFAULT 4,
          active INTEGER NOT NULL DEFAULT 1,
          created_at TEXT DEFAULT (datetime('now')),
          updated_at TEXT DEFAULT (datetime('now'))
        );
        CREATE TABLE IF NOT EXISTS open_day_classes (
          id INTEGER PRIMARY KEY AUTOINCREMENT,
          event_id INTEGER NOT NULL REFERENCES open_day_events(id) ON DELETE CASCADE,
          hall TEXT NOT NULL,
          start_time TEXT NOT NULL,
          end_time TEXT NOT NULL,
          trainer TEXT NOT NULL,
          style TEXT NOT NULL,
          cancelled INTEGER NOT NULL DEFAULT 0,
          sort_order INTEGER NOT NULL DEFAULT 0,
          UNIQUE(event_id, hall, start_time)
        );
        CREATE TABLE IF NOT EXISTS open_day_bookings (
          id INTEGER PRIMARY KEY AUTOINCREMENT,
          class_id INTEGER NOT NULL REFERENCES open_day_classes(id) ON DELETE CASCADE,
          event_id INTEGER NOT NULL REFERENCES open_day_events(id) ON DELETE CASCADE,
          name TEXT NOT NULL,
          phone TEXT NOT NULL,
          instagram TEXT,
          telegram TEXT,
          notified_confirm INTEGER NOT NULL DEFAULT 0,
          notified_reminder INTEGER NOT NULL DEFAULT 0,
          created_at TEXT DEFAULT (datetime('now')),
          UNIQUE(class_id, phone)
        );
      `);
    },
  },
  {
    version: 7,
    name: "unify_booking_fields",
    up: (db) => {
      // Add phone to mc_registrations
      const mcCols = db.prepare("PRAGMA table_info(mc_registrations)").all() as { name: string }[];
      const mcColNames = new Set(mcCols.map((c) => c.name));
      if (!mcColNames.has("phone")) db.exec("ALTER TABLE mc_registrations ADD COLUMN phone TEXT");

      // Add instagram/telegram to group_bookings
      const gbCols = db.prepare("PRAGMA table_info(group_bookings)").all() as { name: string }[];
      const gbColNames = new Set(gbCols.map((c) => c.name));
      if (!gbColNames.has("instagram")) db.exec("ALTER TABLE group_bookings ADD COLUMN instagram TEXT");
      if (!gbColNames.has("telegram")) db.exec("ALTER TABLE group_bookings ADD COLUMN telegram TEXT");
    },
  },
  {
    version: 8,
    name: "add_reminder_status",
    up: (db) => {
      // reminder_status: null = not reminded, 'pending' = reminded but no answer, 'coming' = confirmed, 'cancelled' = not coming
      for (const table of ["mc_registrations", "group_bookings", "open_day_bookings"]) {
        const cols = db.prepare(`PRAGMA table_info(${table})`).all() as { name: string }[];
        if (!cols.some((c) => c.name === "reminder_status")) {
          db.exec(`ALTER TABLE ${table} ADD COLUMN reminder_status TEXT`);
        }
      }
    },
  },
  {
    version: 9,
    name: "add_performance_indexes",
    up: (db) => {
      db.exec(`
        CREATE INDEX IF NOT EXISTS idx_mc_registrations_title ON mc_registrations(master_class_title);
        CREATE INDEX IF NOT EXISTS idx_mc_registrations_created ON mc_registrations(created_at DESC);
        CREATE INDEX IF NOT EXISTS idx_group_bookings_created ON group_bookings(created_at DESC);
        CREATE INDEX IF NOT EXISTS idx_open_day_bookings_event ON open_day_bookings(event_id);
        CREATE INDEX IF NOT EXISTS idx_open_day_bookings_class ON open_day_bookings(class_id);
        CREATE INDEX IF NOT EXISTS idx_open_day_bookings_phone ON open_day_bookings(event_id, phone);
        CREATE INDEX IF NOT EXISTS idx_open_day_bookings_class_phone ON open_day_bookings(class_id, phone);
        CREATE INDEX IF NOT EXISTS idx_open_day_classes_event ON open_day_classes(event_id);
      `);
    },
  },
  {
    version: 10,
    name: "add_group_booking_status",
    up: (db) => {
      const cols = db.prepare("PRAGMA table_info(group_bookings)").all() as { name: string }[];
      if (!cols.some((c) => c.name === "status")) {
        db.exec("ALTER TABLE group_bookings ADD COLUMN status TEXT NOT NULL DEFAULT 'new'");
      }
      if (!cols.some((c) => c.name === "confirmed_date")) {
        db.exec("ALTER TABLE group_bookings ADD COLUMN confirmed_date TEXT");
      }
      if (!cols.some((c) => c.name === "confirmed_group")) {
        db.exec("ALTER TABLE group_bookings ADD COLUMN confirmed_group TEXT");
      }
      if (!cols.some((c) => c.name === "confirmed_comment")) {
        db.exec("ALTER TABLE group_bookings ADD COLUMN confirmed_comment TEXT");
      }
    },
  },
  {
    version: 11,
    name: "add_team_short_description",
    up: (db) => {
      const cols = db.prepare("PRAGMA table_info(team_members)").all() as { name: string }[];
      if (!cols.some((c) => c.name === "short_description")) {
        db.exec("ALTER TABLE team_members ADD COLUMN short_description TEXT");
      }
    },
  },
  {
    version: 12,
    name: "add_status_to_mc_and_openday",
    up: (db) => {
      for (const table of ["mc_registrations", "open_day_bookings"]) {
        const cols = db.prepare(`PRAGMA table_info(${table})`).all() as { name: string }[];
        const colNames = new Set(cols.map((c) => c.name));
        if (!colNames.has("status")) {
          db.exec(`ALTER TABLE ${table} ADD COLUMN status TEXT NOT NULL DEFAULT 'new'`);
        }
      }
    },
  },
  {
    version: 13,
    name: "add_booking_notes",
    up: (db) => {
      for (const table of ["mc_registrations", "group_bookings", "open_day_bookings"]) {
        const cols = db.prepare(`PRAGMA table_info(${table})`).all() as { name: string }[];
        if (!cols.some((c) => c.name === "notes")) {
          db.exec(`ALTER TABLE ${table} ADD COLUMN notes TEXT`);
        }
      }
    },
  },
];

function runMigrations(db: Database.Database) {
  // Create migrations tracking table
  db.exec(`
    CREATE TABLE IF NOT EXISTS _migrations (
      version INTEGER PRIMARY KEY,
      name TEXT NOT NULL,
      applied_at TEXT DEFAULT (datetime('now'))
    );
  `);

  const applied = new Set(
    (db.prepare("SELECT version FROM _migrations").all() as { version: number }[])
      .map((r) => r.version)
  );

  const pending = migrations.filter((m) => !applied.has(m.version));
  if (pending.length === 0) return;

  const insertMigration = db.prepare(
    "INSERT INTO _migrations (version, name) VALUES (?, ?)"
  );

  const tx = db.transaction(() => {
    for (const m of pending) {
      m.up(db);
      insertMigration.run(m.version, m.name);
    }
  });
  tx();
}

// --- Sections ---

export function getSection<T = unknown>(key: string): T | null {
  const db = getDb();
  const row = db.prepare("SELECT data FROM sections WHERE key = ?").get(key) as
    | { data: string }
    | undefined;
  return row ? (JSON.parse(row.data) as T) : null;
}

export function setSection(key: string, data: unknown): void {
  const db = getDb();
  db.prepare(
    `INSERT INTO sections (key, data, updated_at) VALUES (?, ?, datetime('now'))
     ON CONFLICT(key) DO UPDATE SET data = excluded.data, updated_at = excluded.updated_at`
  ).run(key, JSON.stringify(data));
}

// --- Team Members ---

interface TeamMemberRow {
  id: number;
  name: string;
  role: string;
  image: string;
  instagram: string | null;
  short_description: string | null;
  description: string | null;
  experience: string | null;
  victories: string | null;
  education: string | null;
  sort_order: number;
}

function parseJsonArray(val: string | null): string[] | undefined {
  if (!val) return undefined;
  try { const arr = JSON.parse(val); return Array.isArray(arr) && arr.length > 0 ? arr : undefined; } catch { return undefined; }
}

function parseRichList(val: string | null): RichListItem[] | undefined {
  if (!val) return undefined;
  try {
    const arr = JSON.parse(val);
    if (!Array.isArray(arr) || arr.length === 0) return undefined;
    // Handle both old string[] and new RichListItem[] formats
    return arr.map((item: string | RichListItem) =>
      typeof item === "string" ? { text: item } : item
    );
  } catch { return undefined; }
}

function parseVictories(val: string | null): VictoryItem[] | undefined {
  if (!val) return undefined;
  try {
    const arr = JSON.parse(val);
    if (!Array.isArray(arr) || arr.length === 0) return undefined;
    // Handle old string[], old RichListItem[], and new VictoryItem[] formats
    return arr.map((item: string | Record<string, unknown>) => {
      if (typeof item === "string") return { place: "", category: "", competition: item };
      if ("text" in item && !("competition" in item)) return { place: "", category: "", competition: item.text as string, image: item.image as string | undefined, link: item.link as string | undefined };
      return item as unknown as VictoryItem;
    });
  } catch { return undefined; }
}

export function getTeamMembers(): (TeamMember & { id: number })[] {
  const db = getDb();
  const rows = db
    .prepare("SELECT * FROM team_members ORDER BY sort_order ASC, id ASC")
    .all() as TeamMemberRow[];
  return rows.map((r) => ({
    id: r.id,
    name: r.name,
    role: r.role,
    image: r.image,
    instagram: r.instagram ?? undefined,
    shortDescription: r.short_description ?? undefined,
    description: r.description ?? undefined,
    experience: parseJsonArray(r.experience),
    victories: parseVictories(r.victories),
    education: parseRichList(r.education),
  }));
}

export function getTeamMember(
  id: number
): (TeamMember & { id: number }) | null {
  const db = getDb();
  const r = db
    .prepare("SELECT * FROM team_members WHERE id = ?")
    .get(id) as TeamMemberRow | undefined;
  if (!r) return null;
  return {
    id: r.id,
    name: r.name,
    role: r.role,
    image: r.image,
    instagram: r.instagram ?? undefined,
    shortDescription: r.short_description ?? undefined,
    description: r.description ?? undefined,
    experience: parseJsonArray(r.experience),
    victories: parseVictories(r.victories),
    education: parseRichList(r.education),
  };
}

export function createTeamMember(
  data: Omit<TeamMember, "id">
): number {
  const db = getDb();
  const maxOrder = db
    .prepare("SELECT COALESCE(MAX(sort_order), -1) as max FROM team_members")
    .get() as { max: number };
  const result = db
    .prepare(
      `INSERT INTO team_members (name, role, image, instagram, short_description, description, experience, victories, education, sort_order)
       VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
    )
    .run(
      data.name,
      data.role,
      data.image,
      data.instagram ?? null,
      data.shortDescription ?? null,
      data.description ?? null,
      data.experience?.length ? JSON.stringify(data.experience) : null,
      data.victories?.length ? JSON.stringify(data.victories) : null,
      data.education?.length ? JSON.stringify(data.education) : null,
      maxOrder.max + 1
    );
  return result.lastInsertRowid as number;
}

export function updateTeamMember(
  id: number,
  data: Partial<Omit<TeamMember, "id">>
): void {
  const db = getDb();
  const fields: string[] = [];
  const values: unknown[] = [];

  if (data.name !== undefined) { fields.push("name = ?"); values.push(data.name); }
  if (data.role !== undefined) { fields.push("role = ?"); values.push(data.role); }
  if (data.image !== undefined) { fields.push("image = ?"); values.push(data.image); }
  if (data.instagram !== undefined) { fields.push("instagram = ?"); values.push(data.instagram || null); }
  if (data.shortDescription !== undefined) { fields.push("short_description = ?"); values.push(data.shortDescription || null); }
  if (data.description !== undefined) { fields.push("description = ?"); values.push(data.description || null); }
  if (data.experience !== undefined) { fields.push("experience = ?"); values.push(data.experience?.length ? JSON.stringify(data.experience) : null); }
  if (data.victories !== undefined) { fields.push("victories = ?"); values.push(data.victories?.length ? JSON.stringify(data.victories) : null); }
  if (data.education !== undefined) { fields.push("education = ?"); values.push(data.education?.length ? JSON.stringify(data.education) : null); }

  if (fields.length === 0) return;
  fields.push("updated_at = datetime('now')");
  values.push(id);

  db.prepare(`UPDATE team_members SET ${fields.join(", ")} WHERE id = ?`).run(
    ...values
  );
}

export function deleteTeamMember(id: number): void {
  const db = getDb();
  db.prepare("DELETE FROM team_members WHERE id = ?").run(id);
}

export function reorderTeamMembers(ids: number[]): void {
  const db = getDb();
  const stmt = db.prepare(
    "UPDATE team_members SET sort_order = ? WHERE id = ?"
  );
  const tx = db.transaction(() => {
    ids.forEach((id, index) => stmt.run(index, id));
  });
  tx();
}

// --- Full site content ---

const SECTION_KEYS = [
  "meta",
  "hero",
  "about",
  "classes",
  "masterClasses",
  "faq",
  "pricing",
  "schedule",
  "news",
  "contact",
] as const;

export function getSiteContent(): SiteContent | null {
  const db = getDb();
  const rows = db.prepare("SELECT key, data FROM sections").all() as {
    key: string;
    data: string;
  }[];

  if (rows.length === 0) return null;

  const sections: Record<string, unknown> = {};
  for (const row of rows) {
    sections[row.key] = JSON.parse(row.data);
  }

  // Merge team members from dedicated table
  const members = getTeamMembers();
  const teamSection = (sections.team as { title?: string }) || {};

  return {
    meta: sections.meta,
    hero: sections.hero,
    about: sections.about,
    classes: sections.classes,
    masterClasses: sections.masterClasses ?? { title: "Мастер-классы", items: [] },
    faq: sections.faq,
    pricing: sections.pricing,
    schedule: sections.schedule,
    news: sections.news ?? { title: "Новости", items: [] },
    contact: sections.contact,
    team: {
      title: teamSection.title || "",
      members: members.map(({ id, ...rest }) => rest),
    },
  } as SiteContent;
}

export function isDatabaseSeeded(): boolean {
  const db = getDb();
  const row = db
    .prepare("SELECT COUNT(*) as count FROM sections")
    .get() as { count: number };
  return row.count > 0;
}

// --- MC Registrations ---

interface McRegistrationRow {
  id: number;
  master_class_title: string;
  name: string;
  instagram: string;
  phone: string | null;
  telegram: string | null;
  created_at: string;
  notified_confirm: number;
  notified_reminder: number;
  reminder_status: string | null;
  status: string;
  notes: string | null;
}

export interface McRegistration {
  id: number;
  masterClassTitle: string;
  name: string;
  instagram: string;
  phone?: string;
  telegram?: string;
  createdAt: string;
  notifiedConfirm: boolean;
  notifiedReminder: boolean;
  reminderStatus?: string;
  status: string;
  notes?: string;
}

export function addMcRegistration(
  masterClassTitle: string,
  name: string,
  instagram: string,
  telegram?: string,
  phone?: string
): number {
  const db = getDb();
  const result = db
    .prepare(
      `INSERT INTO mc_registrations (master_class_title, name, instagram, telegram, phone)
       VALUES (?, ?, ?, ?, ?)`
    )
    .run(masterClassTitle, name, instagram, telegram || null, phone || null);
  return result.lastInsertRowid as number;
}

export function getMcRegistrations(masterClassTitle: string): McRegistration[] {
  const db = getDb();
  const rows = db
    .prepare(
      "SELECT * FROM mc_registrations WHERE master_class_title = ? ORDER BY created_at DESC"
    )
    .all(masterClassTitle) as McRegistrationRow[];
  return rows.map(mapMcRow);
}

export function getAllMcRegistrations(): McRegistration[] {
  const db = getDb();
  const rows = db
    .prepare("SELECT * FROM mc_registrations ORDER BY created_at DESC")
    .all() as McRegistrationRow[];
  return rows.map(mapMcRow);
}

function mapMcRow(r: McRegistrationRow): McRegistration {
  return {
    id: r.id,
    masterClassTitle: r.master_class_title,
    name: r.name,
    instagram: r.instagram,
    phone: r.phone ?? undefined,
    telegram: r.telegram ?? undefined,
    createdAt: r.created_at,
    notifiedConfirm: !!r.notified_confirm,
    notifiedReminder: !!r.notified_reminder,
    reminderStatus: r.reminder_status ?? undefined,
    status: r.status || "new",
    notes: r.notes ?? undefined,
  };
}

export function setMcRegistrationStatus(id: number, status: string): void {
  const db = getDb();
  db.prepare("UPDATE mc_registrations SET status = ?, notified_confirm = 1 WHERE id = ?").run(status, id);
}

export function updateMcRegistration(
  id: number,
  name: string,
  instagram: string,
  telegram?: string
): void {
  const db = getDb();
  db.prepare(
    "UPDATE mc_registrations SET name = ?, instagram = ?, telegram = ? WHERE id = ?"
  ).run(name, instagram, telegram || null, id);
}

export function toggleMcNotification(
  id: number,
  field: "notified_confirm" | "notified_reminder",
  value: boolean
): void {
  const db = getDb();
  db.prepare(
    `UPDATE mc_registrations SET ${field} = ? WHERE id = ?`
  ).run(value ? 1 : 0, id);
}

export function deleteMcRegistration(id: number): void {
  const db = getDb();
  db.prepare("DELETE FROM mc_registrations WHERE id = ?").run(id);
}

// --- Group Bookings ---

interface GroupBookingRow {
  id: number;
  name: string;
  phone: string;
  group_info: string | null;
  instagram: string | null;
  telegram: string | null;
  notified_confirm: number;
  notified_reminder: number;
  reminder_status: string | null;
  status: string;
  confirmed_date: string | null;
  confirmed_group: string | null;
  confirmed_comment: string | null;
  notes: string | null;
  created_at: string;
}

export type BookingStatus = "new" | "contacted" | "confirmed" | "declined";

export interface GroupBooking {
  id: number;
  name: string;
  phone: string;
  groupInfo?: string;
  instagram?: string;
  telegram?: string;
  notifiedConfirm: boolean;
  notifiedReminder: boolean;
  reminderStatus?: string;
  status: BookingStatus;
  confirmedDate?: string;
  confirmedGroup?: string;
  confirmedComment?: string;
  notes?: string;
  createdAt: string;
}

export function addGroupBooking(
  name: string,
  phone: string,
  groupInfo?: string,
  instagram?: string,
  telegram?: string
): number {
  const db = getDb();
  const result = db
    .prepare(
      "INSERT INTO group_bookings (name, phone, group_info, instagram, telegram) VALUES (?, ?, ?, ?, ?)"
    )
    .run(name, phone, groupInfo || null, instagram || null, telegram || null);
  return result.lastInsertRowid as number;
}

export function getGroupBookings(): GroupBooking[] {
  const db = getDb();
  const rows = db
    .prepare("SELECT * FROM group_bookings ORDER BY created_at DESC")
    .all() as GroupBookingRow[];
  return rows.map((r) => ({
    id: r.id,
    name: r.name,
    phone: r.phone,
    groupInfo: r.group_info ?? undefined,
    instagram: r.instagram ?? undefined,
    telegram: r.telegram ?? undefined,
    notifiedConfirm: !!r.notified_confirm,
    notifiedReminder: !!r.notified_reminder,
    reminderStatus: r.reminder_status ?? undefined,
    status: (r.status || "new") as BookingStatus,
    confirmedDate: r.confirmed_date ?? undefined,
    confirmedGroup: r.confirmed_group ?? undefined,
    confirmedComment: r.confirmed_comment ?? undefined,
    notes: r.notes ?? undefined,
    createdAt: r.created_at,
  }));
}

export function setGroupBookingStatus(
  id: number,
  status: BookingStatus,
  confirmation?: { date: string; group: string; comment?: string }
): void {
  const db = getDb();
  if (status === "confirmed" && confirmation) {
    // Auto-set reminder to 'coming' only if confirmed for today/tomorrow
    const today = new Date().toISOString().split("T")[0];
    const tomorrow = new Date(Date.now() + MS_PER_DAY).toISOString().split("T")[0];
    const reminderStatus = (confirmation.date === today || confirmation.date === tomorrow) ? "coming" : null;
    db.prepare(
      "UPDATE group_bookings SET status = ?, confirmed_date = ?, confirmed_group = ?, confirmed_comment = ?, notified_confirm = 1, reminder_status = ? WHERE id = ?"
    ).run(status, confirmation.date, confirmation.group, confirmation.comment || null, reminderStatus, id);
  } else {
    db.prepare(
      "UPDATE group_bookings SET status = ?, confirmed_date = NULL, confirmed_group = NULL, confirmed_comment = NULL, notified_confirm = 1 WHERE id = ?"
    ).run(status, id);
  }
}

export function updateGroupBooking(
  id: number,
  name: string,
  phone: string,
  groupInfo?: string
): void {
  const db = getDb();
  db.prepare(
    "UPDATE group_bookings SET name = ?, phone = ?, group_info = ? WHERE id = ?"
  ).run(name, phone, groupInfo || null, id);
}

export function toggleGroupBookingNotification(
  id: number,
  field: "notified_confirm" | "notified_reminder",
  value: boolean
): void {
  const db = getDb();
  db.prepare(`UPDATE group_bookings SET ${field} = ? WHERE id = ?`).run(
    value ? 1 : 0,
    id
  );
}

export function deleteGroupBooking(id: number): void {
  const db = getDb();
  db.prepare("DELETE FROM group_bookings WHERE id = ?").run(id);
}

// --- Unread booking counts (lightweight) ---

export interface UnreadCounts {
  groupBookings: number;
  mcRegistrations: number;
  openDayBookings: number;
  total: number;
}

// --- Reminder status ---

export type ReminderStatus = "pending" | "coming" | "cancelled";

export function setReminderStatus(
  table: "mc_registrations" | "group_bookings" | "open_day_bookings",
  id: number,
  status: ReminderStatus | null
): void {
  const db = getDb();
  db.prepare(`UPDATE ${table} SET reminder_status = ? WHERE id = ?`).run(status, id);
}

export function updateBookingNotes(
  table: "mc_registrations" | "group_bookings" | "open_day_bookings",
  id: number,
  notes: string
): void {
  const db = getDb();
  db.prepare(`UPDATE ${table} SET notes = ? WHERE id = ?`).run(notes || null, id);
}

export interface ReminderItem {
  id: number;
  type: "class" | "master-class" | "open-day";
  table: "mc_registrations" | "group_bookings" | "open_day_bookings";
  name: string;
  phone?: string;
  instagram?: string;
  telegram?: string;
  reminderStatus?: string;
  eventLabel: string;
  eventDate: string;
}

export function getUpcomingReminders(): ReminderItem[] {
  const db = getDb();
  const items: ReminderItem[] = [];

  // Tomorrow and today dates
  const now = new Date();
  const today = now.toISOString().split("T")[0];
  const tomorrow = new Date(now.getTime() + 24 * 60 * 60 * 1000).toISOString().split("T")[0];

  // MC registrations — match slots from sections JSON
  try {
    const mcSection = db.prepare("SELECT data FROM sections WHERE key = 'masterClasses'").get() as { data: string } | undefined;
    if (mcSection) {
      const mcData = JSON.parse(mcSection.data) as { items: { title: string; slots: { date: string; startTime?: string }[] }[] };
      // Find MC titles with slots today or tomorrow
      const upcomingTitles: { title: string; date: string; time?: string }[] = [];
      for (const mc of mcData.items || []) {
        for (const slot of mc.slots || []) {
          if (slot.date === today || slot.date === tomorrow) {
            upcomingTitles.push({ title: mc.title, date: slot.date, time: slot.startTime });
          }
        }
      }
      if (upcomingTitles.length > 0) {
        const uniqueTitles = [...new Set(upcomingTitles.map((t) => t.title))];
        const placeholders = uniqueTitles.map(() => "?").join(", ");
        const rows = db.prepare(
          `SELECT * FROM mc_registrations WHERE master_class_title IN (${placeholders})`
        ).all(...uniqueTitles) as McRegistrationRow[];

        // Build a lookup: title → { date, time }
        const titleInfo = new Map<string, { date: string; time?: string }>();
        for (const t of upcomingTitles) {
          titleInfo.set(t.title, { date: t.date, time: t.time });
        }

        for (const r of rows) {
          const info = titleInfo.get(r.master_class_title);
          if (!info) continue;
          items.push({
            id: r.id,
            type: "master-class",
            table: "mc_registrations",
            name: r.name,
            phone: r.phone ?? undefined,
            instagram: r.instagram ?? undefined,
            telegram: r.telegram ?? undefined,
            reminderStatus: r.reminder_status ?? undefined,
            eventLabel: `${r.master_class_title}${info.time ? ` · ${info.time}` : ""}`,
            eventDate: info.date,
          });
        }
      }
    }
  } catch { /* ignore */ }

  // Group bookings — confirmed with date today/tomorrow
  try {
    const gbRows = db.prepare(
      "SELECT * FROM group_bookings WHERE status IN ('confirmed', 'contacted') AND confirmed_date IN (?, ?)"
    ).all(today, tomorrow) as GroupBookingRow[];
    for (const r of gbRows) {
      items.push({
        id: r.id,
        type: "class",
        table: "group_bookings",
        name: r.name,
        phone: r.phone ?? undefined,
        instagram: r.instagram ?? undefined,
        telegram: r.telegram ?? undefined,
        reminderStatus: r.reminder_status ?? undefined,
        eventLabel: r.confirmed_group || "Занятие",
        eventDate: r.confirmed_date!,
      });
    }
  } catch { /* ignore */ }

  // Open Day bookings — check event date
  try {
    const events = db.prepare(
      "SELECT id, date, title FROM open_day_events WHERE date IN (?, ?) AND active = 1"
    ).all(today, tomorrow) as { id: number; date: string; title: string }[];
    for (const ev of events) {
      const rows = db.prepare(
        `SELECT b.*, c.style as class_style, c.trainer as class_trainer, c.start_time as class_time, c.hall as class_hall
         FROM open_day_bookings b
         JOIN open_day_classes c ON c.id = b.class_id
         WHERE b.event_id = ? AND c.cancelled = 0`
      ).all(ev.id) as OpenDayBookingRow[];
      for (const r of rows) {
        items.push({
          id: r.id,
          type: "open-day",
          table: "open_day_bookings",
          name: r.name,
          phone: r.phone ?? undefined,
          instagram: r.instagram ?? undefined,
          telegram: r.telegram ?? undefined,
          reminderStatus: r.reminder_status ?? undefined,
          eventLabel: `${r.class_style} · ${r.class_trainer} · ${r.class_time} (${r.class_hall})`,
          eventDate: ev.date,
        });
      }
    }
  } catch { /* ignore */ }

  return items;
}

export function getUnreadBookingCounts(): UnreadCounts {
  const db = getDb();
  const gb = (db.prepare("SELECT COUNT(*) as c FROM group_bookings WHERE notified_confirm = 0").get() as { c: number }).c;
  const mc = (db.prepare("SELECT COUNT(*) as c FROM mc_registrations WHERE notified_confirm = 0").get() as { c: number }).c;

  let od = 0;
  // Check if open_day_bookings table exists (might not if no migration yet)
  try {
    od = (db.prepare("SELECT COUNT(*) as c FROM open_day_bookings WHERE notified_confirm = 0").get() as { c: number }).c;
  } catch { /* table doesn't exist yet */ }

  return { groupBookings: gb, mcRegistrations: mc, openDayBookings: od, total: gb + mc + od };
}

// --- Open Day Events ---

interface OpenDayEventRow {
  id: number;
  date: string;
  title: string;
  description: string | null;
  price_per_class: number;
  discount_price: number;
  discount_threshold: number;
  min_bookings: number;
  active: number;
  created_at: string;
  updated_at: string;
}

export interface OpenDayEvent {
  id: number;
  date: string;
  title: string;
  description?: string;
  pricePerClass: number;
  discountPrice: number;
  discountThreshold: number;
  minBookings: number;
  active: boolean;
}

interface OpenDayClassRow {
  id: number;
  event_id: number;
  hall: string;
  start_time: string;
  end_time: string;
  trainer: string;
  style: string;
  cancelled: number;
  sort_order: number;
  booking_count?: number;
}

export interface OpenDayClass {
  id: number;
  eventId: number;
  hall: string;
  startTime: string;
  endTime: string;
  trainer: string;
  style: string;
  cancelled: boolean;
  sortOrder: number;
  bookingCount: number;
}

interface OpenDayBookingRow {
  id: number;
  class_id: number;
  event_id: number;
  name: string;
  phone: string;
  instagram: string | null;
  telegram: string | null;
  notified_confirm: number;
  notified_reminder: number;
  reminder_status: string | null;
  status: string;
  created_at: string;
  class_style?: string;
  class_trainer?: string;
  class_time?: string;
  class_hall?: string;
}

export interface OpenDayBooking {
  id: number;
  classId: number;
  eventId: number;
  name: string;
  phone: string;
  instagram?: string;
  telegram?: string;
  notifiedConfirm: boolean;
  notifiedReminder: boolean;
  reminderStatus?: string;
  status: string;
  createdAt: string;
  classStyle?: string;
  classTrainer?: string;
  classTime?: string;
  classHall?: string;
}

function mapEventRow(r: OpenDayEventRow): OpenDayEvent {
  return {
    id: r.id,
    date: r.date,
    title: r.title,
    description: r.description ?? undefined,
    pricePerClass: r.price_per_class,
    discountPrice: r.discount_price,
    discountThreshold: r.discount_threshold,
    minBookings: r.min_bookings,
    active: !!r.active,
  };
}

function mapClassRow(r: OpenDayClassRow): OpenDayClass {
  return {
    id: r.id,
    eventId: r.event_id,
    hall: r.hall,
    startTime: r.start_time,
    endTime: r.end_time,
    trainer: r.trainer,
    style: r.style,
    cancelled: !!r.cancelled,
    sortOrder: r.sort_order,
    bookingCount: r.booking_count ?? 0,
  };
}

export function setOpenDayBookingStatus(id: number, status: string): void {
  const db = getDb();
  db.prepare("UPDATE open_day_bookings SET status = ?, notified_confirm = 1 WHERE id = ?").run(status, id);
}

function mapBookingRow(r: OpenDayBookingRow): OpenDayBooking {
  return {
    id: r.id,
    classId: r.class_id,
    eventId: r.event_id,
    name: r.name,
    phone: r.phone,
    instagram: r.instagram ?? undefined,
    telegram: r.telegram ?? undefined,
    notifiedConfirm: !!r.notified_confirm,
    notifiedReminder: !!r.notified_reminder,
    reminderStatus: r.reminder_status ?? undefined,
    status: r.status || "new",
    createdAt: r.created_at,
    classStyle: r.class_style ?? undefined,
    classTrainer: r.class_trainer ?? undefined,
    classTime: r.class_time ?? undefined,
    classHall: r.class_hall ?? undefined,
  };
}

export function createOpenDayEvent(data: {
  date: string;
  title?: string;
  description?: string;
  pricePerClass?: number;
  discountPrice?: number;
  discountThreshold?: number;
  minBookings?: number;
}): number {
  const db = getDb();
  const result = db
    .prepare(
      `INSERT INTO open_day_events (date, title, description, price_per_class, discount_price, discount_threshold, min_bookings)
       VALUES (?, ?, ?, ?, ?, ?, ?)`
    )
    .run(
      data.date,
      data.title || "День открытых дверей",
      data.description || null,
      data.pricePerClass ?? 30,
      data.discountPrice ?? 20,
      data.discountThreshold ?? 3,
      data.minBookings ?? 4
    );
  return result.lastInsertRowid as number;
}

export function getOpenDayEvents(): OpenDayEvent[] {
  const db = getDb();
  const rows = db
    .prepare("SELECT * FROM open_day_events ORDER BY date DESC")
    .all() as OpenDayEventRow[];
  return rows.map(mapEventRow);
}

export function getOpenDayEvent(id: number): OpenDayEvent | null {
  const db = getDb();
  const row = db
    .prepare("SELECT * FROM open_day_events WHERE id = ?")
    .get(id) as OpenDayEventRow | undefined;
  return row ? mapEventRow(row) : null;
}

export function getActiveOpenDayEvent(): OpenDayEvent | null {
  const db = getDb();
  const row = db
    .prepare(
      "SELECT * FROM open_day_events WHERE active = 1 AND date >= date('now') ORDER BY date ASC LIMIT 1"
    )
    .get() as OpenDayEventRow | undefined;
  return row ? mapEventRow(row) : null;
}

export function updateOpenDayEvent(
  id: number,
  data: Partial<{
    date: string;
    title: string;
    description: string;
    pricePerClass: number;
    discountPrice: number;
    discountThreshold: number;
    minBookings: number;
    active: boolean;
  }>
): void {
  const db = getDb();
  const sets: string[] = [];
  const vals: unknown[] = [];
  if (data.date !== undefined) { sets.push("date = ?"); vals.push(data.date); }
  if (data.title !== undefined) { sets.push("title = ?"); vals.push(data.title); }
  if (data.description !== undefined) { sets.push("description = ?"); vals.push(data.description || null); }
  if (data.pricePerClass !== undefined) { sets.push("price_per_class = ?"); vals.push(data.pricePerClass); }
  if (data.discountPrice !== undefined) { sets.push("discount_price = ?"); vals.push(data.discountPrice); }
  if (data.discountThreshold !== undefined) { sets.push("discount_threshold = ?"); vals.push(data.discountThreshold); }
  if (data.minBookings !== undefined) { sets.push("min_bookings = ?"); vals.push(data.minBookings); }
  if (data.active !== undefined) { sets.push("active = ?"); vals.push(data.active ? 1 : 0); }
  if (sets.length === 0) return;
  sets.push("updated_at = datetime('now')");
  vals.push(id);
  db.prepare(`UPDATE open_day_events SET ${sets.join(", ")} WHERE id = ?`).run(...vals);
}

export function deleteOpenDayEvent(id: number): void {
  const db = getDb();
  db.prepare("DELETE FROM open_day_events WHERE id = ?").run(id);
}

// --- Open Day Classes ---

export function addOpenDayClass(
  eventId: number,
  data: { hall: string; startTime: string; endTime: string; trainer: string; style: string }
): number {
  const db = getDb();
  const maxOrder = (
    db.prepare("SELECT MAX(sort_order) as m FROM open_day_classes WHERE event_id = ?").get(eventId) as { m: number | null }
  ).m ?? -1;
  const result = db
    .prepare(
      `INSERT INTO open_day_classes (event_id, hall, start_time, end_time, trainer, style, sort_order)
       VALUES (?, ?, ?, ?, ?, ?, ?)`
    )
    .run(eventId, data.hall, data.startTime, data.endTime, data.trainer, data.style, maxOrder + 1);
  return result.lastInsertRowid as number;
}

export function getOpenDayClasses(eventId: number): OpenDayClass[] {
  const db = getDb();
  const rows = db
    .prepare(
      `SELECT c.*, COALESCE(b.cnt, 0) as booking_count
       FROM open_day_classes c
       LEFT JOIN (SELECT class_id, COUNT(*) as cnt FROM open_day_bookings GROUP BY class_id) b ON b.class_id = c.id
       WHERE c.event_id = ?
       ORDER BY c.hall, c.start_time`
    )
    .all(eventId) as OpenDayClassRow[];
  return rows.map(mapClassRow);
}

export function updateOpenDayClass(
  id: number,
  data: Partial<{ hall: string; startTime: string; endTime: string; trainer: string; style: string; cancelled: boolean; sortOrder: number }>
): void {
  const db = getDb();
  const sets: string[] = [];
  const vals: unknown[] = [];
  if (data.hall !== undefined) { sets.push("hall = ?"); vals.push(data.hall); }
  if (data.startTime !== undefined) { sets.push("start_time = ?"); vals.push(data.startTime); }
  if (data.endTime !== undefined) { sets.push("end_time = ?"); vals.push(data.endTime); }
  if (data.trainer !== undefined) { sets.push("trainer = ?"); vals.push(data.trainer); }
  if (data.style !== undefined) { sets.push("style = ?"); vals.push(data.style); }
  if (data.cancelled !== undefined) { sets.push("cancelled = ?"); vals.push(data.cancelled ? 1 : 0); }
  if (data.sortOrder !== undefined) { sets.push("sort_order = ?"); vals.push(data.sortOrder); }
  if (sets.length === 0) return;
  vals.push(id);
  db.prepare(`UPDATE open_day_classes SET ${sets.join(", ")} WHERE id = ?`).run(...vals);
}

export function deleteOpenDayClass(id: number): void {
  const db = getDb();
  db.prepare("DELETE FROM open_day_classes WHERE id = ?").run(id);
}

// --- Open Day Bookings ---

export function addOpenDayBooking(
  classId: number,
  eventId: number,
  data: { name: string; phone: string; instagram?: string; telegram?: string }
): number {
  const db = getDb();
  const result = db
    .prepare(
      `INSERT INTO open_day_bookings (class_id, event_id, name, phone, instagram, telegram)
       VALUES (?, ?, ?, ?, ?, ?)`
    )
    .run(classId, eventId, data.name, data.phone, data.instagram || null, data.telegram || null);
  return result.lastInsertRowid as number;
}

export function getOpenDayBookings(eventId: number): OpenDayBooking[] {
  const db = getDb();
  const rows = db
    .prepare(
      `SELECT b.*, c.style as class_style, c.trainer as class_trainer, c.start_time as class_time, c.hall as class_hall
       FROM open_day_bookings b
       JOIN open_day_classes c ON c.id = b.class_id
       WHERE b.event_id = ?
       ORDER BY b.created_at DESC`
    )
    .all(eventId) as OpenDayBookingRow[];
  return rows.map(mapBookingRow);
}

export function getOpenDayBookingCountsByClass(eventId: number): Record<number, number> {
  const db = getDb();
  const rows = db
    .prepare("SELECT class_id, COUNT(*) as cnt FROM open_day_bookings WHERE event_id = ? GROUP BY class_id")
    .all(eventId) as { class_id: number; cnt: number }[];
  const result: Record<number, number> = {};
  for (const r of rows) result[r.class_id] = r.cnt;
  return result;
}

export function getPersonOpenDayBookings(eventId: number, phone: string): number {
  const db = getDb();
  const row = db
    .prepare("SELECT COUNT(*) as cnt FROM open_day_bookings WHERE event_id = ? AND phone = ?")
    .get(eventId, phone) as { cnt: number };
  return row.cnt;
}

export function toggleOpenDayNotification(
  id: number,
  field: "notified_confirm" | "notified_reminder",
  value: boolean
): void {
  const db = getDb();
  db.prepare(`UPDATE open_day_bookings SET ${field} = ? WHERE id = ?`).run(value ? 1 : 0, id);
}

export function deleteOpenDayBooking(id: number): void {
  const db = getDb();
  db.prepare("DELETE FROM open_day_bookings WHERE id = ?").run(id);
}

export function isOpenDayClassBookedByPhone(classId: number, phone: string): boolean {
  const db = getDb();
  const row = db
    .prepare("SELECT id FROM open_day_bookings WHERE class_id = ? AND phone = ? LIMIT 1")
    .get(classId, phone) as { id: number } | undefined;
  return !!row;
}

export { SECTION_KEYS };
