import fs from 'fs';
import path from 'path';
import { DatabaseSync } from 'node:sqlite';
import { fileURLToPath } from 'url';
import { mergeLegacyAttachmentEventsByDay } from './lib/merge-attachment-events.js';

const __dirname = path.dirname(fileURLToPath(import.meta.url));
const dbPath =
  process.env.SQLITE_PATH || path.join(__dirname, '..', 'data', 'crm.db');

fs.mkdirSync(path.dirname(dbPath), { recursive: true });

const db = new DatabaseSync(dbPath);
db.exec('PRAGMA foreign_keys = ON');

const machineCols = db.prepare('PRAGMA table_info(machines)').all();
if (!machineCols.some((c) => c.name === 'extras')) {
  db.exec('ALTER TABLE machines ADD COLUMN extras TEXT');
}
const machineCols2 = db.prepare('PRAGMA table_info(machines)').all();
if (!machineCols2.some((c) => c.name === 'list_status')) {
  db.exec(
    "ALTER TABLE machines ADD COLUMN list_status TEXT NOT NULL DEFAULT ''",
  );
}

const hasCustomerId = machineCols.some((c) => c.name === 'customer_id');
const tables = db
  .prepare(
    "SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%'",
  )
  .all()
  .map((r) => r.name);
const hasCustomersTable = tables.includes('customers');

const eventCols = db.prepare('PRAGMA table_info(events)').all();
if (eventCols.length > 0 && !eventCols.some((c) => c.name === 'remote_duration_seconds')) {
  db.exec('ALTER TABLE events ADD COLUMN remote_duration_seconds INTEGER');
}
if (eventCols.length > 0 && !eventCols.some((c) => c.name === 'teamviewer_notes')) {
  db.exec('ALTER TABLE events ADD COLUMN teamviewer_notes TEXT');
}
const hasEventExtras = eventCols.some((c) => c.name === 'callback_number');
if (eventCols.length > 0 && !hasEventExtras) {
  db.exec('BEGIN');
  try {
    db.exec(`
      CREATE TABLE events_new (
        "id" TEXT NOT NULL PRIMARY KEY,
        "ticket_id" TEXT NOT NULL,
        "type" TEXT NOT NULL CHECK ("type" IN ('NOTE', 'CALL', 'REMOTE', 'PART', 'SYSTEM')),
        "description" TEXT NOT NULL,
        "callback_number" TEXT,
        "teamviewer_id" TEXT,
        "article_number" TEXT,
        "remote_duration_seconds" INTEGER,
        "teamviewer_notes" TEXT,
        "created_at" TEXT NOT NULL DEFAULT (datetime('now')),
        FOREIGN KEY ("ticket_id") REFERENCES "tickets" ("id") ON DELETE CASCADE ON UPDATE CASCADE
      );
      INSERT INTO events_new (id, ticket_id, type, description, callback_number, teamviewer_id, article_number, remote_duration_seconds, teamviewer_notes, created_at)
      SELECT
        id,
        ticket_id,
        CASE WHEN type = 'WORK' THEN 'REMOTE' ELSE type END,
        description,
        NULL,
        NULL,
        NULL,
        NULL,
        NULL,
        created_at
      FROM events;
      DROP TABLE events;
      ALTER TABLE events_new RENAME TO events;
    `);
    db.exec(
      'CREATE INDEX IF NOT EXISTS events_ticket_id_idx ON "events" ("ticket_id")',
    );
    db.exec(
      'CREATE INDEX IF NOT EXISTS events_created_at_idx ON "events" ("created_at")',
    );
    db.exec('COMMIT');
  } catch (e) {
    db.exec('ROLLBACK');
    throw e;
  }
}

if (hasCustomerId || hasCustomersTable) {
  db.exec('BEGIN');
  try {
    db.exec(`
      CREATE TABLE machines_new (
        "id" TEXT NOT NULL PRIMARY KEY,
        "name" TEXT NOT NULL,
        "typ" TEXT NOT NULL,
        "seriennummer" TEXT NOT NULL,
        "standort" TEXT NOT NULL,
        "list_status" TEXT NOT NULL DEFAULT '',
        "extras" TEXT,
        "created_at" TEXT NOT NULL DEFAULT (datetime('now')),
        "updated_at" TEXT NOT NULL DEFAULT (datetime('now'))
      );
      INSERT INTO machines_new (id, name, typ, seriennummer, standort, list_status, extras, created_at, updated_at)
      SELECT id, name, typ, seriennummer, standort, COALESCE(list_status, ''), extras, created_at, updated_at FROM machines;
      DROP TABLE machines;
      ALTER TABLE machines_new RENAME TO machines;
    `);
    if (hasCustomersTable) {
      db.exec('DROP TABLE customers');
    }
    db.exec('COMMIT');
  } catch (e) {
    db.exec('ROLLBACK');
    throw e;
  }
}

const tbl = db
  .prepare(
    "SELECT name FROM sqlite_master WHERE type='table' AND name='users'",
  )
  .get();
if (!tbl) {
  db.exec(`
    CREATE TABLE "users" (
      "id" TEXT NOT NULL PRIMARY KEY,
      "username" TEXT NOT NULL UNIQUE,
      "password_hash" TEXT,
      "role" TEXT NOT NULL DEFAULT 'user' CHECK ("role" IN ('admin', 'user')),
      "source" TEXT NOT NULL DEFAULT 'local' CHECK ("source" IN ('local', 'ldap')),
      "ldap_dn" TEXT,
      "active" INTEGER NOT NULL DEFAULT 1 CHECK ("active" IN (0, 1)),
      "created_at" TEXT NOT NULL DEFAULT (datetime('now')),
      "updated_at" TEXT NOT NULL DEFAULT (datetime('now'))
    );
    CREATE INDEX IF NOT EXISTS users_username_idx ON "users" ("username");
  `);
}

const tblSet = db
  .prepare(
    "SELECT name FROM sqlite_master WHERE type='table' AND name='app_settings'",
  )
  .get();
if (!tblSet) {
  db.exec(`
    CREATE TABLE "app_settings" (
      "key" TEXT NOT NULL PRIMARY KEY,
      "value" TEXT NOT NULL
    );
  `);
}

const ldapLogTbl = db
  .prepare(
    "SELECT name FROM sqlite_master WHERE type='table' AND name='ldap_sync_log'",
  )
  .get();
if (!ldapLogTbl) {
  db.exec(`
    CREATE TABLE "ldap_sync_log" (
      "id" TEXT NOT NULL PRIMARY KEY,
      "started_at" TEXT NOT NULL,
      "finished_at" TEXT NOT NULL,
      "trigger_type" TEXT NOT NULL CHECK ("trigger_type" IN ('manual', 'automatic')),
      "status" TEXT NOT NULL CHECK ("status" IN ('success', 'error')),
      "users_synced" INTEGER NOT NULL DEFAULT 0,
      "error_message" TEXT
    );
    CREATE INDEX ldap_sync_log_finished_idx ON "ldap_sync_log" ("finished_at" DESC);
  `);
}

const ticketAttachmentsTbl = db
  .prepare(
    "SELECT name FROM sqlite_master WHERE type='table' AND name='ticket_attachments'",
  )
  .get();
if (!ticketAttachmentsTbl) {
  db.exec('BEGIN');
  try {
    db.exec(`
      CREATE TABLE events_new (
        "id" TEXT NOT NULL PRIMARY KEY,
        "ticket_id" TEXT NOT NULL,
        "type" TEXT NOT NULL CHECK ("type" IN ('NOTE', 'CALL', 'REMOTE', 'PART', 'SYSTEM', 'ATTACHMENT')),
        "description" TEXT NOT NULL,
        "callback_number" TEXT,
        "teamviewer_id" TEXT,
        "article_number" TEXT,
        "remote_duration_seconds" INTEGER,
        "teamviewer_notes" TEXT,
        "created_at" TEXT NOT NULL DEFAULT (datetime('now')),
        FOREIGN KEY ("ticket_id") REFERENCES "tickets" ("id") ON DELETE CASCADE ON UPDATE CASCADE
      );
      INSERT INTO events_new (
        id, ticket_id, type, description, callback_number, teamviewer_id, article_number,
        remote_duration_seconds, teamviewer_notes, created_at
      )
      SELECT
        id, ticket_id, type, description, callback_number, teamviewer_id, article_number,
        remote_duration_seconds, teamviewer_notes, created_at
      FROM events;
      DROP TABLE events;
      ALTER TABLE events_new RENAME TO events;
    `);
    db.exec(
      'CREATE INDEX IF NOT EXISTS events_ticket_id_idx ON "events" ("ticket_id")',
    );
    db.exec(
      'CREATE INDEX IF NOT EXISTS events_created_at_idx ON "events" ("created_at")',
    );
    db.exec(`
      CREATE TABLE "ticket_attachments" (
        "id" TEXT NOT NULL PRIMARY KEY,
        "event_id" TEXT NOT NULL,
        "original_name" TEXT NOT NULL,
        "stored_path" TEXT NOT NULL,
        "mime_type" TEXT,
        "size_bytes" INTEGER NOT NULL,
        "created_at" TEXT NOT NULL DEFAULT (datetime('now')),
        FOREIGN KEY ("event_id") REFERENCES "events" ("id") ON DELETE CASCADE ON UPDATE CASCADE
      );
      CREATE INDEX IF NOT EXISTS ticket_attachments_event_idx ON "ticket_attachments" ("event_id");
    `);
    db.exec('COMMIT');
  } catch (e) {
    db.exec('ROLLBACK');
    throw e;
  }
}

const hasTicketAttachments = db
  .prepare(
    "SELECT name FROM sqlite_master WHERE type='table' AND name='ticket_attachments'",
  )
  .get();
const attachmentMergeDone = db
  .prepare('SELECT 1 AS ok FROM app_settings WHERE key = ?')
  .get('attachment_events_merge_day_v1');
if (hasTicketAttachments && !attachmentMergeDone) {
  try {
    mergeLegacyAttachmentEventsByDay(db);
    db.prepare('INSERT OR REPLACE INTO app_settings (key, value) VALUES (?, ?)').run(
      'attachment_events_merge_day_v1',
      '1',
    );
  } catch (e) {
    console.error('CRM: Zusammenführung Anhang-Events fehlgeschlagen:', e);
  }
}

const ticketCols = db.prepare('PRAGMA table_info(tickets)').all();
if (!ticketCols.some((c) => c.name === 'sla_days')) {
  db.exec('ALTER TABLE tickets ADD COLUMN sla_days INTEGER');
}
if (!ticketCols.some((c) => c.name === 'sla_anchor_at')) {
  db.exec('ALTER TABLE tickets ADD COLUMN sla_anchor_at TEXT');
}
const ticketCols2 = db.prepare('PRAGMA table_info(tickets)').all();
if (ticketCols2.some((c) => c.name === 'sla_anchor_at')) {
  db.prepare(
    'UPDATE tickets SET sla_anchor_at = created_at WHERE sla_anchor_at IS NULL',
  ).run();
}

export default db;
