import { getDb } from '../database/database';
import { getSystemConfig, updateSystemConfig } from '../admin/system-config.service';
import { formatLocalDate, formatLocalDateTime } from '../utils/time';
import { QuarkDriver } from './drivers/quark.driver';
import { BaiduDriver } from './drivers/baidu.driver';

// ═══════════════════════════════════════════════════════════════════════════
//  CloudCleanupDriver — contract that each cloud driver must fulfill
//  to participate in the cleanup cycle.
//
//  To add a new cloud type (e.g. Baidu, Aliyun), implement these three
//  methods in the driver and register it in getDriverForCleanup() below.
//  The controller (this file) handles WHEN and WITH WHAT parameters;
//  the driver handles HOW.
// ═══════════════════════════════════════════════════════════════════════════

/** Each cleanup operation returns { trashed: number; errors: string[] } */
interface CleanupOpResult { trashed: number; errors: string[] }

interface CloudCleanupDriver {
  /** Trash date folders (YYYY-MM-DD) older than `days`. */
  cleanupOldDateFolders(days: number): Promise<CleanupOpResult>;
  /**
   * If used space exceeds thresholdPercent% of TOTAL capacity,
   * delete oldest date folders until totalBytes * deletePercent/100
   * of TOTAL capacity is freed.
   * @param thresholdPercent — trigger when usage >= this % of total
   * @param deletePercent   — free this % of total capacity
   */
  cleanupBySpaceThreshold(thresholdPercent: number, deletePercent: number): Promise<CleanupOpResult>;
  /** Permanently empty the recycle bin. */
  emptyTrash(): Promise<boolean>;
}

// ═══════════════════════════════════════════════════════════════════════════
//  Driver factory — create the right driver for a given cloud config.
//  When adding a new cloud type, add a case here.
// ═══════════════════════════════════════════════════════════════════════════

function getDriverForCleanup(config: { cloud_type: string; cookie: string }): CloudCleanupDriver | null {
  switch (config.cloud_type) {
    case 'quark':
      return new QuarkDriver({ cookie: config.cookie });
    case 'baidu':
      return new BaiduDriver({ cookie: config.cookie });
    // case 'aliyun': return new AliyunDriver({ cookie: config.cookie });
    default:
      return null;
  }
}

// ═══════════════════════════════════════════════════════════════════════════
//  Cleanup controller — reads system configs and dispatches to each
//  active cloud driver. Every driver receives the same parameters;
//  the driver decides whether/how to act.
// ═══════════════════════════════════════════════════════════════════════════

interface CleanupStats {
  filesTrashed: number;
  logsDeleted: number;
  trashEmptied: boolean;
  errors: string[];
}

/** Get all active cloud configs (any type). Used by the orchestrator. */
function getActiveCleanupConfigs(): Array<{ id: number; cloud_type: string; cookie: string; nickname?: string }> {
  const db = getDb();
  return db.prepare(
    `SELECT id, cloud_type, cookie, nickname FROM cloud_configs
     WHERE is_active = 1 AND cookie IS NOT NULL AND cookie != ''`
  ).all() as Array<{ id: number; cloud_type: string; cookie: string; nickname?: string }>;
}

/**
 * Dispatch cleanupOldDateFolders to every active driver.
 * Each driver receives the same `days` parameter.
 */
async function cleanupCloudFiles(days: number): Promise<CleanupOpResult> {
  const configs = getActiveCleanupConfigs();
  const errors: string[] = [];
  let totalTrashed = 0;

  for (const cfg of configs) {
    const driver = getDriverForCleanup(cfg);
    if (!driver) {
      console.log(`[Cleanup] No driver for cloud_type="${cfg.cloud_type}", skipping config #${cfg.id}`);
      continue;
    }
    try {
      const result = await driver.cleanupOldDateFolders(days);
      totalTrashed += result.trashed;
      errors.push(...result.errors.map(e => `[${cfg.cloud_type}#${cfg.id}] ${e}`));
    } catch (err: any) {
      errors.push(`[${cfg.cloud_type}#${cfg.id}] cleanupOldDateFolders: ${err.message}`);
    }
    await new Promise(r => setTimeout(r, 1000));
  }

  return { trashed: totalTrashed, errors };
}

/**
 * Dispatch cleanupBySpaceThreshold to every active driver.
 * Each driver receives the same threshold/delete percentages.
 */
async function cleanupAllBySpaceThreshold(
  thresholdPercent: number,
  deletePercent: number,
): Promise<CleanupOpResult> {
  const configs = getActiveCleanupConfigs();
  const errors: string[] = [];
  let totalTrashed = 0;

  for (const cfg of configs) {
    const driver = getDriverForCleanup(cfg);
    if (!driver) {
      console.log(`[Cleanup] No driver for cloud_type="${cfg.cloud_type}", skipping config #${cfg.id}`);
      continue;
    }
    try {
      const result = await driver.cleanupBySpaceThreshold(thresholdPercent, deletePercent);
      totalTrashed += result.trashed;
      errors.push(...result.errors.map(e => `[${cfg.cloud_type}#${cfg.id}] ${e}`));
    } catch (err: any) {
      errors.push(`[${cfg.cloud_type}#${cfg.id}] cleanupBySpaceThreshold: ${err.message}`);
    }
    await new Promise(r => setTimeout(r, 1000));
  }

  return { trashed: totalTrashed, errors };
}

/**
 * Dispatch emptyTrash to every active driver.
 */
export async function emptyAllTrash(): Promise<{ emptied: boolean; errors: string[] }> {
  const configs = getActiveCleanupConfigs();
  const errors: string[] = [];
  let emptied = false;

  for (const cfg of configs) {
    const driver = getDriverForCleanup(cfg);
    if (!driver) continue;
    try {
      const ok = await driver.emptyTrash();
      if (ok) {
        emptied = true;
        console.log(`[Cleanup] ✅ Emptied trash for [${cfg.cloud_type}#${cfg.id}]`);
      } else {
        errors.push(`[${cfg.cloud_type}#${cfg.id}] empty trash failed`);
      }
    } catch (err: any) {
      errors.push(`[${cfg.cloud_type}#${cfg.id}]: ${err.message}`);
    }
  }

  return { emptied, errors };
}

/**
 * Delete save_records older than the specified number of days.
 */
function cleanupLogs(days: number): number {
  const db = getDb();
  const cutoffStr = formatLocalDateTime(new Date(Date.now() - days * 24 * 60 * 60 * 1000));

  const result = db.prepare('DELETE FROM save_records WHERE created_at < ?').run(cutoffStr);
  console.log(`[Cleanup] Deleted ${result.changes} save records older than ${days} days (before ${cutoffStr})`);
  return result.changes;
}

/**
 * Run full cleanup cycle:
 *   0. Force-clean by space threshold (if enabled & exceeded) — priority highest
 *   1. Delete old save_records
 *   2. Trash old date folders by retention days
 *   3. Empty recycle bin (permanently free space)
 */
export async function runFullCleanup(): Promise<CleanupStats> {
  const fileDays = parseInt(getSystemConfig('cleanup_file_retention_days') || '7', 10);
  const logDays = parseInt(getSystemConfig('cleanup_log_retention_days') || '30', 10);
  const emptyTrashEnabled = getSystemConfig('cleanup_empty_trash') !== 'false';

  const stats: CleanupStats = { filesTrashed: 0, logsDeleted: 0, trashEmptied: false, errors: [] };

  // 0. Space threshold (highest priority)
  const thresholdEnabled = getSystemConfig('cleanup_space_threshold_enabled');
  if (thresholdEnabled === 'true') {
    const thresholdPercent = parseInt(getSystemConfig('cleanup_space_threshold_percent') || '90', 10);
    const deletePercent = parseInt(getSystemConfig('cleanup_space_threshold_delete_percent') || '10', 10);
    if (thresholdPercent > 0 && thresholdPercent < 100) {
      try {
        const result = await cleanupAllBySpaceThreshold(thresholdPercent, deletePercent);
        stats.filesTrashed += result.trashed;
        stats.errors.push(...result.errors);
      } catch (err: any) {
        stats.errors.push(`空间阈值清理失败: ${err.message}`);
      }
    }
  }

  // 1. Delete old save_records
  try {
    stats.logsDeleted = cleanupLogs(logDays);
  } catch (err: any) {
    stats.errors.push(`日志清理失败: ${err.message}`);
  }

  // 2. Trash old files from cloud drives
  try {
    const result = await cleanupCloudFiles(fileDays);
    stats.filesTrashed += result.trashed;
    stats.errors.push(...result.errors);
  } catch (err: any) {
    stats.errors.push(`文件清理失败: ${err.message}`);
  }

  // 3. Empty recycle bin (only if enabled, and only if we trashed something)
  if (emptyTrashEnabled && stats.filesTrashed > 0) {
    try {
      const result = await emptyAllTrash();
      stats.trashEmptied = result.emptied;
      stats.errors.push(...result.errors);
    } catch (err: any) {
      stats.errors.push(`清空回收站失败: ${err.message}`);
    }
  }

  // Save last run timestamp and stats
  updateSystemConfig('cleanup_last_run', formatLocalDateTime());
  updateSystemConfig('cleanup_last_stats',
    JSON.stringify({ filesTrashed: stats.filesTrashed, logsDeleted: stats.logsDeleted, trashEmptied: stats.trashEmptied, errors: stats.errors.length })
  );

  return stats;
}

/**
 * Check if a daily cleanup is due and run it.
 * Called periodically by the scheduler (setInterval).
 */
export async function checkAndRunScheduledCleanup(): Promise<void> {
  const enabled = getSystemConfig('cleanup_enabled');
  if (enabled !== 'true') return;

  const lastRun = getSystemConfig('cleanup_last_run');
  const todayStr = formatLocalDate();

  if (lastRun && lastRun.startsWith(todayStr)) return;

  console.log(`[Cleanup] Scheduled cleanup starting at ${new Date().toISOString()}...`);
  const stats = await runFullCleanup();
  console.log(`[Cleanup] Done: trashed ${stats.filesTrashed} folders, deleted ${stats.logsDeleted} logs, emptied trash: ${stats.trashEmptied}, errors: ${stats.errors.length}`);
}
