import fs from 'fs';
import { promises as fsp } from 'fs';
import path from 'path';
import Database from 'better-sqlite3';
import { config } from '../config';
import type { Annotation, CreateAnnotationInput, UpdateAnnotationInput } from '@abcvideo/shared';
import { v4 as uuidv4 } from 'uuid';

let db: Database.Database;

export function initDatabase(): void {
  db = new Database(config.dbPath);
  db.pragma('journal_mode = WAL');
  db.exec(`
    CREATE TABLE IF NOT EXISTS annotations (
      id TEXT PRIMARY KEY,
      video_id TEXT NOT NULL,
      type TEXT NOT NULL CHECK(type IN ('subtitle','memo')),
      time_start REAL NOT NULL,
      time_end REAL NOT NULL,
      text TEXT NOT NULL DEFAULT '',
      pos_x REAL NOT NULL DEFAULT 50,
      pos_y REAL NOT NULL DEFAULT 75,
      size_width REAL NOT NULL DEFAULT 30,
      size_height REAL NOT NULL DEFAULT 10,
      style_font_size INTEGER DEFAULT 16,
      style_color TEXT DEFAULT '#ffffff',
      style_bg_color TEXT DEFAULT 'rgba(0,0,0,0.7)',
      created_at TEXT NOT NULL,
      updated_at TEXT NOT NULL
    );
    CREATE INDEX IF NOT EXISTS idx_annotations_video ON annotations(video_id);
    CREATE INDEX IF NOT EXISTS idx_annotations_time ON annotations(video_id, time_start);
  `);
  console.log('[db] SQLite initialized');
}

export async function ensureStorageDirs(): Promise<void> {
  const dirs = [config.videosDir, config.hlsDir, config.framesDir, config.thumbnailsDir];
  for (const dir of dirs) {
    await fsp.mkdir(dir, { recursive: true });
  }
}

function rowToAnnotation(row: Record<string, unknown>): Annotation {
  return {
    id: row.id as string,
    videoId: row.video_id as string,
    type: row.type as 'subtitle' | 'memo',
    timeStart: row.time_start as number,
    timeEnd: row.time_end as number,
    text: row.text as string,
    position: { x: row.pos_x as number, y: row.pos_y as number },
    size: { width: row.size_width as number, height: row.size_height as number },
    style: {
      fontSize: row.style_font_size as number,
      color: row.style_color as string,
      backgroundColor: row.style_bg_color as string,
    },
    createdAt: row.created_at as string,
    updatedAt: row.updated_at as string,
  };
}

export function getAnnotations(videoId: string): Annotation[] {
  const rows = db
    .prepare('SELECT * FROM annotations WHERE video_id = ? ORDER BY time_start')
    .all(videoId) as Record<string, unknown>[];
  return rows.map(rowToAnnotation);
}

export function createAnnotation(input: CreateAnnotationInput): Annotation {
  const now = new Date().toISOString();
  const id = uuidv4();
  db.prepare(`
    INSERT INTO annotations
      (id, video_id, type, time_start, time_end, text, pos_x, pos_y,
       size_width, size_height, style_font_size, style_color, style_bg_color,
       created_at, updated_at)
    VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
  `).run(
    id, input.videoId, input.type,
    input.timeStart, input.timeEnd, input.text,
    input.position.x, input.position.y,
    input.size.width, input.size.height,
    input.style?.fontSize ?? 16,
    input.style?.color ?? '#ffffff',
    input.style?.backgroundColor ?? 'rgba(0,0,0,0.7)',
    now, now
  );
  return getAnnotation(id)!;
}

export function getAnnotation(id: string): Annotation | null {
  const row = db.prepare('SELECT * FROM annotations WHERE id = ?').get(id) as Record<string, unknown> | undefined;
  return row ? rowToAnnotation(row) : null;
}

export function updateAnnotation(id: string, input: UpdateAnnotationInput): Annotation | null {
  const existing = getAnnotation(id);
  if (!existing) return null;
  const now = new Date().toISOString();
  db.prepare(`
    UPDATE annotations SET
      type = ?, time_start = ?, time_end = ?, text = ?,
      pos_x = ?, pos_y = ?, size_width = ?, size_height = ?,
      style_font_size = ?, style_color = ?, style_bg_color = ?,
      updated_at = ?
    WHERE id = ?
  `).run(
    input.type ?? existing.type,
    input.timeStart ?? existing.timeStart,
    input.timeEnd ?? existing.timeEnd,
    input.text ?? existing.text,
    input.position?.x ?? existing.position.x,
    input.position?.y ?? existing.position.y,
    input.size?.width ?? existing.size.width,
    input.size?.height ?? existing.size.height,
    input.style?.fontSize ?? existing.style.fontSize,
    input.style?.color ?? existing.style.color,
    input.style?.backgroundColor ?? existing.style.backgroundColor,
    now, id
  );
  return getAnnotation(id);
}

export function deleteAnnotation(id: string): boolean {
  const result = db.prepare('DELETE FROM annotations WHERE id = ?').run(id);
  return result.changes > 0;
}

export async function cleanupOldTempFiles(): Promise<void> {
  const tmpDir = path.join(config.videosDir, 'tmp');
  if (!fs.existsSync(tmpDir)) return;
  const maxAge = 24 * 60 * 60 * 1000;
  try {
    const entries = await fsp.readdir(tmpDir, { withFileTypes: true });
    for (const entry of entries) {
      const filePath = path.join(tmpDir, entry.name);
      const stat = await fsp.stat(filePath);
      if (Date.now() - stat.mtimeMs > maxAge) {
        await fsp.rm(filePath, { recursive: true, force: true });
        console.log(`[cleanup] removed old temp: ${entry.name}`);
      }
    }
  } catch (err) {
    console.error('[cleanup] error:', err);
  }
}
