import Database from 'better-sqlite3';
import path from 'path';
import bcrypt from 'bcryptjs';
import config from '../config';
import { formatLocalDateTime } from '../utils/time';

let db: Database.Database | null = null;

export function getDb(): Database.Database {
  if (db) return db;

  const dbDir = path.dirname(config.dbPath);
  const fs = require('fs');
  if (!fs.existsSync(dbDir)) {
    fs.mkdirSync(dbDir, { recursive: true });
  }

  db = new Database(config.dbPath);
  db.pragma('journal_mode = WAL');
  db.pragma('foreign_keys = ON');

  // Performance indexes (IF NOT EXISTS ensures idempotent)
  db.exec(`
  CREATE INDEX IF NOT EXISTS idx_cc_type_active ON cloud_configs(cloud_type, is_active);
  CREATE INDEX IF NOT EXISTS idx_cc_uid ON cloud_configs(cookie_uid);
  CREATE INDEX IF NOT EXISTS idx_cc_verification ON cloud_configs(verification_status);
`);

  runMigrations(db);
  seedAdmin(db);

  return db;
}

function runMigrations(db: Database.Database): void {
  db.exec(`
    CREATE TABLE IF NOT EXISTS admins (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      username TEXT UNIQUE NOT NULL,
      password_hash TEXT NOT NULL,
      created_at TEXT NOT NULL DEFAULT (datetime('now', 'localtime')),
      last_login TEXT
    );

    CREATE TABLE IF NOT EXISTS cloud_configs (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      cloud_type TEXT NOT NULL,
      cookie TEXT,
      nickname TEXT,
      is_active INTEGER NOT NULL DEFAULT 1,
      storage_used TEXT,
      storage_total TEXT,
      checkin_status TEXT NOT NULL DEFAULT 'none',
      last_checkin_at TEXT,
      checkin_message TEXT,
      consecutive_failures INTEGER DEFAULT 0,
      last_used_at TEXT,
      total_saves INTEGER DEFAULT 0,
      created_at TEXT NOT NULL DEFAULT (datetime('now', 'localtime')),
      updated_at TEXT NOT NULL DEFAULT (datetime('now', 'localtime'))
    );

    CREATE TABLE IF NOT EXISTS promotions (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      title TEXT NOT NULL,
      description TEXT,
      image_url TEXT,
      link_url TEXT,
      position TEXT,
      sort_order INTEGER NOT NULL DEFAULT 0,
      active INTEGER NOT NULL DEFAULT 1,
      click_count INTEGER NOT NULL DEFAULT 0,
      start_time TEXT,
      end_time TEXT,
      created_at TEXT NOT NULL DEFAULT (datetime('now', 'localtime')),
      updated_at TEXT NOT NULL DEFAULT (datetime('now', 'localtime'))
    );

    CREATE TABLE IF NOT EXISTS save_records (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      source_type TEXT,
      source_title TEXT,
      source_url TEXT,
      target_cloud TEXT,
      share_url TEXT,
      share_pwd TEXT,
      file_size TEXT,
      file_count INTEGER DEFAULT 0,
      duration_ms INTEGER DEFAULT 0,
      status TEXT NOT NULL DEFAULT '',
      error_message TEXT,
      ip_address TEXT,
      created_at TEXT NOT NULL DEFAULT (datetime('now', 'localtime'))
    );

    CREATE TABLE IF NOT EXISTS search_stats (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      keyword TEXT,
      intent TEXT,
      result_count INTEGER DEFAULT 0,
      ip_address TEXT,
      created_at TEXT NOT NULL DEFAULT (datetime('now', 'localtime'))
    );

    CREATE TABLE IF NOT EXISTS hot_keywords (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      keyword TEXT UNIQUE NOT NULL,
      search_count INTEGER NOT NULL DEFAULT 1,
      updated_at TEXT NOT NULL DEFAULT (datetime('now', 'localtime'))
    );

    CREATE TABLE IF NOT EXISTS system_configs (
      key TEXT PRIMARY KEY,
      value TEXT NOT NULL DEFAULT '',
      description TEXT,
      updated_at TEXT NOT NULL DEFAULT (datetime('now', 'localtime'))
    );

    CREATE TABLE IF NOT EXISTS content_cache (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      keyword TEXT UNIQUE NOT NULL,
      title TEXT,
      description TEXT,
      tags TEXT,
      cover TEXT,
      source TEXT,
      updated_at TEXT NOT NULL DEFAULT (datetime('now', 'localtime'))
    );
  `);
  seedSystemConfigs(db);
  migrateSaveRecords(db);
  migrateContentCache(db);
  migrateCloudConfigs(db);
  cleanupOldSaveRecords(db);
}

/** 迁移: 给已有 save_records 表补充新列 */
function migrateSaveRecords(db: Database.Database): void {
  const newCols: { col: string; def: string }[] = [
    { col: 'share_pwd', def: 'TEXT' },
    { col: 'file_count', def: 'INTEGER DEFAULT 0' },
    { col: 'folder_count', def: 'INTEGER DEFAULT 0' },
    { col: 'duration_ms', def: 'INTEGER DEFAULT 0' },
    { col: 'status', def: "TEXT NOT NULL DEFAULT ''" },
    { col: 'error_message', def: 'TEXT' },
    { col: 'folder_name', def: 'TEXT' },
    { col: 'request_url', def: 'TEXT' },
    { col: 'ip_location', def: 'TEXT' },
    { col: 'original_folder_name', def: 'TEXT' },
  ];
  for (const { col, def } of newCols) {
    try {
      db.exec(`ALTER TABLE save_records ADD COLUMN ${col} ${def}`);
    } catch {
      // Column already exists — ignore
    }
  }
}

/** 迁移: 给 content_cache 表加 douban_url 列 */
function migrateContentCache(db: Database.Database): void {
  const columns: { col: string; def: string }[] = [
    { col: 'douban_url', def: 'TEXT' },
    { col: 'rating', def: 'TEXT' },
    { col: 'rating_count', def: 'TEXT' },
    { col: 'year', def: 'TEXT' },
    { col: 'genres', def: 'TEXT' },
    { col: 'directors', def: 'TEXT' },
    { col: 'actors', def: 'TEXT' },
    { col: 'region', def: 'TEXT' },
    { col: 'duration', def: 'TEXT' },
  ];
  for (const { col, def } of columns) {
    try {
      db.exec(`ALTER TABLE content_cache ADD COLUMN ${col} ${def}`);
    } catch {
      // Column already exists — ignore
    }
  }
  // 修复旧记录：source 为 NULL 但实际有 TMDB 数据的，标记为 tmdb
  db.exec(`UPDATE content_cache SET source = 'tmdb' WHERE source IS NULL AND title IS NOT NULL AND title != ''`);
}

/** 迁移: 给 cloud_configs 表去UNIQUE约束 + 加签到/轮训字段 */
function migrateCloudConfigs(db: Database.Database): void {
  // 加新列
  const newCols: { col: string; def: string }[] = [
    { col: 'checkin_status', def: "TEXT NOT NULL DEFAULT 'none'" },
    { col: 'last_checkin_at', def: 'TEXT' },
    { col: 'checkin_message', def: 'TEXT' },
    { col: 'consecutive_failures', def: 'INTEGER DEFAULT 0' },
    { col: 'last_used_at', def: 'TEXT' },
    { col: 'total_saves', def: 'INTEGER DEFAULT 0' },
  ];
  for (const { col, def } of newCols) {
    try { db.exec(`ALTER TABLE cloud_configs ADD COLUMN ${col} ${def}`); } catch {}
  }
  // 检查旧表是否有 UNIQUE 约束，有则重建表
  const row = db.prepare(`SELECT sql FROM sqlite_master WHERE type='table' AND name='cloud_configs'`).get() as any;
  if (row && row.sql && row.sql.includes('cloud_type TEXT UNIQUE')) {
    db.exec(`
      CREATE TABLE IF NOT EXISTS cloud_configs_v2 (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        cloud_type TEXT NOT NULL,
        cookie TEXT,
        nickname TEXT,
        is_active INTEGER NOT NULL DEFAULT 1,
        storage_used TEXT,
        storage_total TEXT,
        checkin_status TEXT NOT NULL DEFAULT 'none',
        last_checkin_at TEXT,
        checkin_message TEXT,
        consecutive_failures INTEGER DEFAULT 0,
        last_used_at TEXT,
        total_saves INTEGER DEFAULT 0,
        created_at TEXT NOT NULL DEFAULT (datetime('now', 'localtime')),
        updated_at TEXT NOT NULL DEFAULT (datetime('now', 'localtime'))
      );
      INSERT INTO cloud_configs_v2 (id, cloud_type, cookie, nickname, is_active, storage_used, storage_total, checkin_status, last_checkin_at, checkin_message, consecutive_failures, last_used_at, total_saves, created_at, updated_at)
      SELECT id, cloud_type, cookie, nickname, is_active, storage_used, storage_total, COALESCE(checkin_status,'none'), last_checkin_at, checkin_message, COALESCE(consecutive_failures,0), last_used_at, COALESCE(total_saves,0), created_at, updated_at FROM cloud_configs;
      DROP TABLE cloud_configs;
      ALTER TABLE cloud_configs_v2 RENAME TO cloud_configs;
    `);
    console.log('[DB] cloud_configs migration: UNIQUE constraint removed, new fields added');
  }

  // Migration 2: Add verification_status column
  const row2 = db.prepare("SELECT sql FROM sqlite_master WHERE name='cloud_configs' AND sql LIKE '%verification_status%'").get();
  if (!row2) {
    db.exec("ALTER TABLE cloud_configs ADD COLUMN verification_status TEXT DEFAULT NULL");
    console.log('[DB] cloud_configs migration: verification_status column added');
  }

  // Migration 3: Add cookie_uid column
  const hasCookieUid = db.prepare("SELECT sql FROM sqlite_master WHERE name='cloud_configs' AND sql LIKE '%cookie_uid%'").get();
  if (!hasCookieUid) {
    db.exec("ALTER TABLE cloud_configs ADD COLUMN cookie_uid TEXT DEFAULT NULL");
    console.log('[DB] cloud_configs migration: cookie_uid column added');
  }

  // Migration 4: Add promotion_account column
  const hasPromotionAccount = db.prepare("SELECT sql FROM sqlite_master WHERE name='cloud_configs' AND sql LIKE '%promotion_account%'").get();
  if (!hasPromotionAccount) {
    db.exec("ALTER TABLE cloud_configs ADD COLUMN promotion_account TEXT DEFAULT NULL");
    console.log('[DB] cloud_configs migration: promotion_account column added');
  }
}

function seedAdmin(db: Database.Database): void {
  const existing = db.prepare('SELECT id FROM admins WHERE username = ?').get(config.adminUsername);
  if (existing) return;

  const salt = bcrypt.genSaltSync(10);
  const hash = bcrypt.hashSync(config.adminPassword, salt);

  db.prepare(
    'INSERT INTO admins (username, password_hash) VALUES (?, ?)'
  ).run(config.adminUsername, hash);

  console.log(`[DB] Admin user "${config.adminUsername}" created`);
}

function seedSystemConfigs(db: Database.Database): void {
  const defaults: { key: string; value: string; description: string }[] = [
    { key: 'pansou_url', value: config.pansouUrl, description: 'PanSou 搜索引擎服务地址' },
    { key: 'video_parser_url', value: config.videoParserUrl, description: '视频解析服务地址' },
    { key: 'validation_concurrency', value: String(config.validation.concurrency), description: '链接验证并发数' },
    { key: 'validation_timeout', value: String(config.validation.timeout), description: '链接验证超时(ms)' },
    { key: 'validation_cache_ttl_valid', value: String(config.validation.cacheTtlValid), description: '有效链接缓存时间(s)' },
    { key: 'validation_cache_ttl_invalid', value: String(config.validation.cacheTtlInvalid), description: '无效链接缓存时间(s)' },
    { key: 'search_proxy_enabled', value: 'false', description: '搜索代理开关（true/false）' },
    { key: 'search_proxy_url', value: '', description: '搜索代理地址 (如 http://127.0.0.1:7890)' },
    { key: 'search_strategy', value: 'wait_all', description: '搜索结果展示方式: wait_all=等待全部后展示, stream_channel=频道逐步展示' },
    { key: 'link_validation_enabled', value: 'true', description: '资源链接有效性检测开关（true/false）' },
    { key: 'cloud_enabled_quark', value: 'true', description: '夸克网盘' },
    { key: 'cloud_enabled_baidu', value: 'true', description: '百度网盘' },
    { key: 'cloud_enabled_aliyun', value: 'true', description: '阿里云盘' },
    { key: 'cloud_enabled_115', value: 'true', description: '115 网盘' },
    { key: 'cloud_enabled_tianyi', value: 'true', description: '天翼云盘' },
    { key: 'cloud_enabled_123pan', value: 'true', description: '123 云盘' },
    { key: 'cloud_enabled_uc', value: 'true', description: 'UC 网盘' },
    { key: 'cloud_enabled_xunlei', value: 'true', description: '迅雷网盘' },
    { key: 'cloud_enabled_pikpak', value: 'true', description: 'PikPak 网盘' },
    { key: 'cloud_enabled_magnet', value: 'true', description: '磁力链接' },
    { key: 'cloud_enabled_ed2k', value: 'true', description: '电驴链接' },
    { key: 'cloud_enabled_others', value: 'false', description: '其他类型（默认关闭）' },
    { key: 'search_result_limit', value: '10', description: '每类网盘最多展示的有效结果数' },
    { key: 'search_fallback_image', value: '', description: '无图资源的兜底封面图 URL（留空使用渐变色）' },
    { key: 'site_logo', value: '', description: '网站 LOGO 图片 URL（留空使用默认图标/文字）' },
    { key: 'site_name', value: 'CloudSearch', description: '网站名称（显示在首页标题/页脚）' },
    { key: 'site_disclaimer', value: '本站为非盈利性个人站点，所有资源仅供学习、研究使用，版权归原作者所有。请于下载后24小时内删除，切勿用于商业或非法用途。若侵犯了您的权益，请联系我们（邮箱：3337598077@qq.com），我们将及时处理。', description: '网站底部免责声明' },
    { key: 'site_marquee', value: '📢 欢迎使用CloudSearch，所有资源仅供学习交流，请于下载后24小时内删除', description: '搜索栏下方滚动通知文字（从右往左滚动显示）' },
    { key: 'tmdb_api_token', value: '', description: 'TMDB API 读取令牌（用于增强豆瓣内容信息）' },
    { key: 'ip_geo_api_url', value: 'https://cn.apihz.cn/api/ip/chaapi.php?id=10014356&key=ca7ccb3b9ca044dd993c8604bc9afd93&ip={ip}&td=0', description: 'IP 归属地查询接口（{ip} 会被替换为实际IP）' },
    { key: 'ip_geo_api_key', value: '', description: 'IP 归属地备用 API Key（留空使用默认）' },
    { key: 'title_filter_rules', value: '', description: '搜索结果标题过滤规则（一行一条：纯文本直接移除 / 正则用/包围/）' },
    { key: 'timezone', value: 'Asia/Shanghai', description: '系统时区（如 Asia/Shanghai、America/New_York、UTC）' },
    { key: 'redis_url', value: 'redis://redis:6379', description: 'Redis 连接地址（用于缓存优化）' },
    { key: 'pansou_auth_token', value: '', description: 'PanSou API 认证令牌（用于私有搜索服务）' },
    { key: 'pansou_web_enabled', value: 'false', description: '启用 PanSou Web 端访问（在 /pansou 路径提供 PanSou 搜索引擎管理界面）' },
    { key: 'cleanup_enabled', value: 'true', description: '启用自动清理（每天检查一次，移入回收站+清空日志+清空回收站）' },
    { key: 'cleanup_file_retention_days', value: '7', description: '云盘文件保留天数（超过此天数的日期文件夹将被移入回收站）' },
    { key: 'cleanup_log_retention_days', value: '30', description: '转存日志保留天数' },
    { key: 'cleanup_empty_trash', value: 'true', description: '清理时是否清空回收站（永久删除释放空间）' },
    { key: 'cleanup_space_threshold_enabled', value: 'false', description: '启用空间阈值自动清理（已用空间超过XX%时按比例删除最旧的转存文件）' },
    { key: 'cleanup_space_threshold_percent', value: '90', description: '空间使用阈值百分比（超过此值时触发强制清理）' },
    { key: 'cleanup_space_threshold_delete_percent', value: '10', description: '触发阈值清理时释放总空间的百分比（如 10 表示累计删除最旧文件直到达到总空间的 10%，6TB 总空间 → 释放 ~600GB）' },
    { key: 'save_reuse_enabled', value: 'true', description: '启用分享链接复用（相同原始链接不再重复转存，直接复用之前的分享链接）' },
    { key: 'cleanup_last_run', value: '', description: '上次自动清理时间' },
    { key: 'cleanup_last_stats', value: '', description: '上次清理结果统计（JSON）' },
  ];
  const insert = db.prepare(
    'INSERT OR IGNORE INTO system_configs (key, value, description) VALUES (?, ?, ?)'
  );
  for (const entry of defaults) {
    insert.run(entry.key, entry.value, entry.description);
  }
}

/** 清理 60 天前的转存记录 */
function cleanupOldSaveRecords(db: Database.Database): void {
  const cutoff = formatLocalDateTime(new Date(Date.now() - 60 * 24 * 60 * 60 * 1000));
  const deleted = db.prepare('DELETE FROM save_records WHERE created_at < ?').run(cutoff);
  console.log(`[DB] Cleaned up ${deleted.changes} save records older than 60 days (before ${cutoff})`);
}

export default getDb;
