import { Router, Request, Response } from 'express';
// Native fetch available in Node 20+
import fs from "fs";
import { execSync } from 'child_process';
import { adminLimiter, loginLimiter } from '../middleware/rate-limit';
import { getSaveRecords } from '../cloud/cloud.service';
import { getCloudConfigs, getCloudConfigById, saveCloudConfig, deleteCloudConfig, getCloudConfigByType, testCloudConnection, testCloudConnectionWithCookie } from '../cloud/credential.service';
import { dailyCheckIn, skipCheckin, getCheckinSummary, getDrivesForCheckin } from '../cloud/checkin.service';
import { getAllCloudTypes } from '../cloud/cloud-types.service';
import { login, authMiddleware, verifyToken, changePassword } from '../admin/auth.service';
import { getStats } from '../admin/stats.service';
import { getAllSystemConfigs, updateSystemConfig, updateSystemConfigs, getSystemConfig } from '../admin/system-config.service';
import { getDb } from '../database/database';
import { reconnectRedis, testRedisConnection } from '../middleware/cache';
import { startQrLogin, getQrLoginStatus, cancelQrLogin } from '../cloud/qr-login.service';
import { BaiduDriver } from '../cloud/drivers/baidu.driver';

const router = Router();

// ═══════════════════════════════════════
//  Public routes (no auth required)
// ═══════════════════════════════════════

/**
 * POST /api/admin/login
 * Admin login
 */
router.post('/admin/login', loginLimiter, (req: Request, res: Response) => {
  try {
    const { username, password } = req.body;
    if (!username || !password) {
      res.status(400).json({ error: 'Username and password are required' });
      return;
    }

    const token = login(username, password);
    if (!token) {
      res.status(401).json({ error: 'Invalid credentials' });
      return;
    }

    res.json({ token });
  } catch (err: any) {
    console.error('[Login] Error:', err);
    res.status(500).json({ error: err.message || 'Internal server error' });
  }
});

/**
 * GET /api/admin/cloud-types
 * List all cloud types (public, read-only).
 */
router.get('/admin/cloud-types', (_req: Request, res: Response) => {
  try {
    const types = getAllCloudTypes();
    res.json({ types });
  } catch (err: any) {
    res.status(500).json({ error: err.message || 'Internal server error' });
  }
});

// ═══════════════════════════════════════
//  QR Login routes (no auth — user not logged in yet)
//  MUST be before authMiddleware!
// ═══════════════════════════════════════

// ===== 夸克扫码登录 =====
router.post('/admin/quark/qr-login/start', async (_req: Request, res: Response) => {
  try {
    const result = await startQrLogin();
    res.json({ ok: true, ...result });
  } catch (err: any) {
    res.status(500).json({ ok: false, error: err.message });
  }
});

router.get('/admin/quark/qr-login/:sessionId/status', async (req: Request, res: Response) => {
  try {
    const sessionId = req.params.sessionId as string;
    const result = await getQrLoginStatus(sessionId);
    res.json({ ok: true, ...result });
  } catch (err: any) {
    res.status(500).json({ ok: false, error: err.message });
  }
});

router.post('/admin/quark/qr-login/:sessionId/cancel', async (req: Request, res: Response) => {
  try {
    const sessionId = req.params.sessionId as string;
    await cancelQrLogin(sessionId);
    res.json({ ok: true });
  } catch (err: any) {
    res.status(500).json({ ok: false, error: err.message });
  }
});

// ===== 百度扫码登录 =====
router.post("/admin/baidu/qr-login/start", async (_req: Request, res: Response) => {
  try {
    const result = await BaiduDriver.startQrLogin();
    res.json({ ok: true, ...result });
  } catch (err: any) {
    res.status(500).json({ ok: false, error: err.message });
  }
});

router.get("/admin/baidu/qr-login/:sessionId/status", async (req: Request, res: Response) => {
  try {
    const sessionId = req.params.sessionId as string;
    const result: any = await BaiduDriver.getQrLoginStatus(sessionId);
    // Map to frontend-expected format (frontend reads data.cookie)
    res.json({
      ok: true,
      status: result.status,
      cookie: result.cookie || result.access_token || "",
      nickname: result.nickname || "",
      storage_used: result.storage_used || "",
      storage_total: result.storage_total || "",
    });
  } catch (err: any) {
    res.status(500).json({ ok: false, error: err.message });
  }
});

router.post("/admin/baidu/qr-login/:sessionId/cancel", async (req: Request, res: Response) => {
  try {
    BaiduDriver.cancelQrLogin(req.params.sessionId as string);
  } catch {}
  res.json({ ok: true });
});

// ═══════════════════════════════════════
//  Auth wall — all routes below require JWT
// ═══════════════════════════════════════
router.use('/admin', authMiddleware);

// ═══════════════════════════════════════
//  Cloud Configs CRUD
// ═══════════════════════════════════════

/** GET /api/admin/cloud-configs — list all cloud configs */
router.get('/admin/cloud-configs', (_req: Request, res: Response) => {
  try {
    const configs = getCloudConfigs();
    res.json(configs);
  } catch (err: any) {
    res.status(500).json({ error: err.message || 'Failed to fetch cloud configs' });
  }
});

/** POST /api/admin/cloud-configs — create or smart-replace a cloud config */
router.post('/admin/cloud-configs', (req: Request, res: Response) => {
  try {
    const data = req.body;
    if (!data.cloud_type) {
      res.status(400).json({ error: 'cloud_type is required' });
      return;
    }
    // Normalize is_active: frontend sends boolean, SQLite needs 0/1
    if (typeof data.is_active === 'boolean') data.is_active = data.is_active ? 1 : 0;
    const saved = saveCloudConfig(data);
    res.json(saved);
  } catch (err: any) {
    res.status(500).json({ error: err.message || 'Failed to save cloud config' });
  }
});

/** PUT /api/admin/cloud-configs/:id — update an existing cloud config */
router.put('/admin/cloud-configs/:id', (req: Request, res: Response) => {
  try {
    const id = parseInt(req.params.id as string);
    const existing = getCloudConfigById(id);
    if (!existing) {
      res.status(404).json({ error: 'Cloud config not found' });
      return;
    }
    const saved = saveCloudConfig({ ...req.body, id });
    res.json(saved);
  } catch (err: any) {
    res.status(500).json({ error: err.message || 'Failed to update cloud config' });
  }
});

/** DELETE /api/admin/cloud-configs/:id */
router.delete('/admin/cloud-configs/:id', (req: Request, res: Response) => {
  try {
    const id = parseInt(req.params.id as string);
    const ok = deleteCloudConfig(id);
    if (!ok) {
      res.status(404).json({ error: 'Cloud config not found' });
      return;
    }
    res.json({ success: true });
  } catch (err: any) {
    res.status(500).json({ error: err.message || 'Failed to delete cloud config' });
  }
});

/** POST /api/admin/cloud-configs/:type/test — test cloud connection (by type or id) */
router.post('/admin/cloud-configs/:type/test', async (req: Request, res: Response) => {
  try {
    const type = req.params.type as string;
    const { cookie, id } = req.body;

    // If cookie is provided directly, test with it (for new configs not yet saved)
    if (cookie) {
      const result = await testCloudConnectionWithCookie(type, cookie);
      res.json(result);
      return;
    }

    // Otherwise test by config id
    if (id) {
      const result = await testCloudConnection(parseInt(id));
      res.json(result);
      return;
    }

    res.status(400).json({ success: false, message: 'Provide either cookie or id' });
  } catch (err: any) {
    res.status(500).json({ success: false, message: err.message || 'Connection test failed' });
  }
});

// ═══════════════════════════════════════
//  Daily Check-in
// ═══════════════════════════════════════

/** POST /api/admin/cloud-configs/:id/checkin */
router.post('/admin/cloud-configs/:id/checkin', async (req: Request, res: Response) => {
  try {
    const id = parseInt(req.params.id as string);
    const result = await dailyCheckIn(id);
    res.json(result);
  } catch (err: any) {
    res.status(500).json({ success: false, message: err.message || 'Check-in failed' });
  }
});

/** POST /api/admin/cloud-configs/:id/skip-checkin */
router.post('/admin/cloud-configs/:id/skip-checkin', async (req: Request, res: Response) => {
  try {
    const id = parseInt(req.params.id as string);
    const ok = skipCheckin(id);
    res.json({ success: ok });
  } catch (err: any) {
    res.status(500).json({ success: false, message: err.message || 'Skip check-in failed' });
  }
});

/** POST /api/admin/cloud-configs/checkin-all */
router.post('/admin/cloud-configs/checkin-all', async (_req: Request, res: Response) => {
  try {
    const drives = getDrivesForCheckin();
    const results: { id: number; nickname: string; success: boolean; message: string }[] = [];
    let total = 0;
    for (const drive of drives) {
      total++;
      try {
        const result = await dailyCheckIn(drive.id);
        results.push({ id: drive.id, nickname: drive.nickname || '', success: result.success, message: result.message });
      } catch (err: any) {
        results.push({ id: drive.id, nickname: drive.nickname || '', success: false, message: err.message || 'Check-in failed' });
      }
    }
    res.json({ total, results });
  } catch (err: any) {
    res.status(500).json({ error: err.message || 'Check-in all failed' });
  }
});

/** GET /api/admin/cloud-configs/checkin-summary */
router.get('/admin/cloud-configs/checkin-summary', (_req: Request, res: Response) => {
  try {
    const summary = getCheckinSummary();
    res.json(summary);
  } catch (err: any) {
    res.status(500).json({ error: err.message || 'Failed to get check-in summary' });
  }
});

// ═══════════════════════════════════════
//  Stats
// ═══════════════════════════════════════

/** GET /api/admin/stats */
router.get('/admin/stats', (req: Request, res: Response) => {
  try {
    const days = req.query.days ? parseInt(req.query.days as string) : 7;
    const stats = getStats(days);
    res.json(stats);
  } catch (err: any) {
    res.status(500).json({ error: err.message || 'Failed to get stats' });
  }
});

// ═══════════════════════════════════════
//  Save Records (转存日志)
// ═══════════════════════════════════════

/** GET /api/admin/save-records */
router.get('/admin/save-records', (req: Request, res: Response) => {
  try {
    const page = parseInt(req.query.page as string) || 1;
    const pageSize = parseInt(req.query.pageSize as string) || 20;
    const startDate = req.query.startDate as string | undefined;
    const endDate = req.query.endDate as string | undefined;
    const status = req.query.status as string | undefined;
    const sourceType = req.query.sourceType as string | undefined;
    const keyword = req.query.keyword as string | undefined;
    const result = getSaveRecords(page, pageSize, startDate, endDate, status, sourceType, keyword);
    res.json(result);
  } catch (err: any) {
    res.status(500).json({ error: err.message || 'Failed to get save records' });
  }
});

// ═══════════════════════════════════════
//  System Configs
// ═══════════════════════════════════════

/** GET /api/admin/system-configs */
router.get('/admin/system-configs', (_req: Request, res: Response) => {
  try {
    const configs = getAllSystemConfigs();
    res.json(configs);
  } catch (err: any) {
    res.status(500).json({ error: err.message || 'Failed to get system configs' });
  }
});

/** PUT /api/admin/system-configs — batch update */
router.put('/admin/system-configs', (req: Request, res: Response) => {
  try {
    const { entries } = req.body;
    if (!entries || !Array.isArray(entries)) {
      res.status(400).json({ error: 'entries array is required' });
      return;
    }
    updateSystemConfigs(entries);
    res.json({ success: true });
  } catch (err: any) {
    res.status(500).json({ error: err.message || 'Failed to update system configs' });
  }
});

// ═══════════════════════════════════════
//  Cloud Types Toggle
// ═══════════════════════════════════════

/** PUT /api/admin/cloud-types — toggle cloud type enabled/disabled */
router.put('/admin/cloud-types', (req: Request, res: Response) => {
  try {
    const { type, enabled } = req.body;
    if (!type) {
      res.status(400).json({ error: 'type is required' });
      return;
    }
    const db = getDb();
    db.prepare(
      `INSERT INTO system_configs (key, value, description) VALUES (?, ?, ?)
       ON CONFLICT(key) DO UPDATE SET value = excluded.value`
    ).run(`cloud_type_${type}_enabled`, enabled ? '1' : '0', `Enable/disable ${type} cloud drive`);
    res.json({ success: true });
  } catch (err: any) {
    res.status(500).json({ error: err.message || 'Failed to toggle cloud type' });
  }
});

// ═══════════════════════════════════════
//  Change Password
// ═══════════════════════════════════════

/** POST /api/admin/change-password */
router.post('/admin/change-password', (req: Request, res: Response) => {
  try {
    const { oldPassword, newPassword } = req.body;
    if (!oldPassword || !newPassword) {
      res.status(400).json({ error: 'Both old and new passwords are required' });
      return;
    }
    // Get username from JWT
    const authHeader = req.headers.authorization || '';
    const token = authHeader.replace('Bearer ', '');
    const payload = verifyToken(token);
    if (!payload) {
      res.status(401).json({ error: 'Invalid token' });
      return;
    }
    const result = changePassword(payload.username, oldPassword, newPassword);
    res.json(result);
  } catch (err: any) {
    res.status(500).json({ error: err.message || 'Failed to change password' });
  }
});

// ═══════════════════════════════════════
//  DB Status
// ═══════════════════════════════════════

/** GET /api/admin/db-status */
router.get('/admin/db-status', async (_req: Request, res: Response) => {
  try {
    const dbFile = getSystemConfig('db_path') || '';
    let dbSize = 'N/A';
    if (dbFile) {
      try {
        const stats = fs.statSync(dbFile);
        dbSize = (stats.size / 1024 / 1024).toFixed(2) + ' MB';
      } catch {}
    }

    const db = getDb();
    const counts = {
      save_records: (db.prepare('SELECT COUNT(*) as c FROM save_records').get() as any)?.c || 0,
      search_stats: (db.prepare('SELECT COUNT(*) as c FROM search_stats').get() as any)?.c || 0,
      system_configs: (db.prepare('SELECT COUNT(*) as c FROM system_configs').get() as any)?.c || 0,
      cloud_configs: (db.prepare('SELECT COUNT(*) as c FROM cloud_configs').get() as any)?.c || 0,
      content_cache: (db.prepare('SELECT COUNT(*) as c FROM content_cache').get() as any)?.c || 0,
    };

    // Redis status
    let redis_status = 'disconnected';
    let redis_url = getSystemConfig('redis_url') || '';
    try {
      const testResult = await testRedisConnection(redis_url);
      redis_status = testResult.ok ? 'connected' : 'disconnected';
    } catch {
      redis_status = 'error';
    }

    res.json({
      db_size: dbSize,
      db_path: dbFile,
      ...counts,
      redis_status,
      redis_url,
    });
  } catch (err: any) {
    res.status(500).json({ error: err.message || 'Failed to get DB status' });
  }
});

// ═══════════════════════════════════════
//  Test Redis Connection
// ═══════════════════════════════════════

/** POST /api/admin/test-redis */
router.post('/admin/test-redis', (req: Request, res: Response) => {
  try {
    const { url } = req.body;
    if (!url) {
      res.status(400).json({ ok: false, info: 'Redis URL is required' });
      return;
    }
    const result = testRedisConnection(url);
    res.json(result);
  } catch (err: any) {
    res.status(500).json({ ok: false, info: err.message || 'Redis test failed' });
  }
});

// ═══════════════════════════════════════
//  Test External Service
// ═══════════════════════════════════════

/** POST /api/admin/test-external-service */
router.post('/admin/test-external-service', async (req: Request, res: Response) => {
  try {
    const { type, url, token } = req.body;
    const start = Date.now();

    switch (type) {
      case 'pansou': {
        const pansouUrl = url || getSystemConfig('pansou_url') || '';
        if (!pansouUrl) {
          res.json({ ok: false, info: 'PanSou URL not configured' });
          return;
        }
        const response = await fetch(pansouUrl + '/api/health', { signal: AbortSignal.timeout(8000) });
        const data: any = await response.json();
        const latency = Date.now() - start;
        res.json({
          ok: response.ok && data?.status === 'ok',
          latency,
          info: response.ok ? `连接成功 (${data?.channels_count || 0} 频道, ${data?.plugin_count || 0} 插件)` : '连接失败',
        });
        break;
      }
      case 'video_parser': {
        const parserUrl = url || getSystemConfig('video_parser_url') || '';
        if (!parserUrl) {
          res.json({ ok: false, info: 'Video Parser URL not configured' });
          return;
        }
        const response = await fetch(parserUrl + '/health', { signal: AbortSignal.timeout(8000) });
        const latency = Date.now() - start;
        res.json({
          ok: response.ok,
          latency,
          info: response.ok ? '连接成功' : `HTTP ${response.status}`,
        });
        break;
      }
      case 'tmdb': {
        const tmdbToken = token || getSystemConfig('tmdb_api_key') || '';
        if (!tmdbToken) {
          res.json({ ok: false, info: 'TMDB API Key not configured' });
          return;
        }
        const response = await fetch('https://api.themoviedb.org/3/configuration', {
          headers: { Authorization: `Bearer ${tmdbToken}` },
          signal: AbortSignal.timeout(8000),
        });
        const latency = Date.now() - start;
        res.json({
          ok: response.ok,
          latency,
          info: response.ok ? '连接成功' : `HTTP ${response.status}`,
        });
        break;
      }
      case 'proxy': {
        const proxyUrl = url || getSystemConfig('proxy_url') || '';
        if (!proxyUrl) {
          res.json({ ok: false, info: 'Proxy URL not configured' });
          return;
        }
        const response = await fetch(proxyUrl, { signal: AbortSignal.timeout(8000) });
        const latency = Date.now() - start;
        res.json({
          ok: response.ok,
          latency,
          info: response.ok ? '连接成功' : `HTTP ${response.status}`,
        });
        break;
      }
      case 'ip_geo': {
        const geoUrl = url || getSystemConfig('ip_geo_api_url') || '';
        if (!geoUrl) {
          res.json({ ok: false, info: '请先输入 IP 归属地查询 API 地址' });
          return;
        }
        const testUrl = geoUrl.replace('{ip}', '8.8.8.8');
        const response = await fetch(testUrl, { signal: AbortSignal.timeout(8000) });
        const data: any = await response.json();
        const latency = Date.now() - start;
        const valid = !!(data?.country || data?.region || data?.city || data?.countryCode);
        res.json({ ok: valid, latency, info: valid ? '连接成功' : '响应格式不符' });
        break;
      }
      default:
        res.json({ ok: false, info: `Unknown service type: ${type}` });
    }
  } catch (err: any) {
    res.status(500).json({ ok: false, info: err.message || 'External service test failed' });
  }
});

// ═══════════════════════════════════════
//  Pansou Info & Update
// ═══════════════════════════════════════

/** GET /api/admin/pansou-info — pansou health + version + update check */
router.get('/admin/pansou-info', async (_req: Request, res: Response) => {
  try {
    const baseUrl = getSystemConfig('pansou_url') || '';
    if (!baseUrl) {
      res.json({ status: 'disconnected', channelCount: 0, pluginCount: 0, diskCount: 0, version: '', hasUpdate: false, latestVersion: '' });
      return;
    }

    // Fetch PanSou health
    const healthUrl = baseUrl + '/api/health';
    const response = await fetch(healthUrl, { signal: AbortSignal.timeout(8000) });
    const healthData: any = await response.json();
    const channelCount = healthData.channels_count || 0;
    const pluginCount = healthData.plugin_count || 0;

    // Derive disk count from channel names
    const driveKeywords = ['aliyun', 'baidu', 'quark', '115', 'pikpak', 'xunlei', 'uc', '123', '139', '189', 'tianyi', 'netease'];
    const drives = new Set<string>();
    for (const ch of (healthData.channels || [])) {
      for (const kw of driveKeywords) {
        if (ch.toLowerCase().includes(kw)) { drives.add(kw); break; }
      }
    }
    const diskCount = drives.size || 5;

    // Get local version from docker label
    let version = '';
    let hasUpdate = false;
    let latestVersion = '';
    try {
      const created = execSync(
        `docker inspect CloudSearch_PanSou --format '{{index .Config.Labels "org.opencontainers.image.created"}}'`,
        { timeout: 5000, encoding: 'utf8' }
      ).trim();
      version = created ? created.slice(0, 10) : '';

      // Check update cache
      const cacheFile = '/tmp/pansou-update-cache.json';
      let cache: any = null;
      try { cache = JSON.parse(fs.readFileSync(cacheFile, 'utf8') || 'null'); } catch {}
      const threeDays = 3 * 24 * 3600 * 1000;

      if (!cache || (Date.now() - cache.checkedAt) > threeDays) {
        // Check GHCR for latest version
        try {
          const tokenRes = await fetch(
            'https://ghcr.io/token?scope=repository:fish2018/pansou-web:pull&service=ghcr.io'
          );
          const ghcrToken = (await tokenRes.json() as any).token;
          const manifestRes = await fetch(
            'https://ghcr.io/v2/fish2018/pansou-web/manifests/latest',
            { headers: { Authorization: `Bearer ${ghcrToken}`, Accept: 'application/vnd.oci.image.index.v1+json, application/vnd.docker.distribution.manifest.list.v2+json' } }
          );
          const manifestList: any = await manifestRes.json();
          const amd64 = manifestList.manifests?.find((m: any) => m.platform?.architecture === 'amd64' && m.platform?.os === 'linux');
          if (amd64) {
            const blobRes = await fetch(
              `https://ghcr.io/v2/fish2018/pansou-web/manifests/${amd64.digest}`,
              { headers: { Authorization: `Bearer ${ghcrToken}`, Accept: 'application/vnd.oci.image.manifest.v1+json' } }
            );
            const blobData: any = await blobRes.json();
            const cfgDigest = blobData.config?.digest;
            if (cfgDigest) {
              const cfgRes = await fetch(
                `https://ghcr.io/v2/fish2018/pansou-web/blobs/${cfgDigest}`,
                { headers: { Authorization: `Bearer ${ghcrToken}` } }
              );
              const cfgData: any = await cfgRes.json();
              const remoteCreated = cfgData.config?.Labels?.['org.opencontainers.image.created'];
              if (remoteCreated) {
                latestVersion = remoteCreated.slice(0, 10);
                if (version && latestVersion !== version) hasUpdate = true;
              }
            }
          }
        } catch {}
        fs.writeFileSync(cacheFile, JSON.stringify({ checkedAt: Date.now(), hasUpdate, latestVersion }));
      } else {
        hasUpdate = cache.hasUpdate;
        latestVersion = cache.latestVersion;
      }
    } catch {}

    res.json({
      status: response.ok ? 'connected' : 'disconnected',
      channelCount,
      pluginCount,
      diskCount,
      version,
      hasUpdate,
      latestVersion,
    });
  } catch (err: any) {
    res.json({ status: 'error', channelCount: 0, pluginCount: 0, diskCount: 0, version: '', hasUpdate: false, latestVersion: '', error: err.message });
  }
});

/** POST /api/admin/update-pansou — pull latest pansou image + recreate container */
router.post('/admin/update-pansou', async (_req: Request, res: Response) => {
  try {
    execSync('docker pull ghcr.io/fish2018/pansou-web:latest', { timeout: 120000 });
    execSync('docker compose -p cloudsearch -f /app/docker-compose.yml up -d pansou', { timeout: 60000 });
    try { fs.unlinkSync('/tmp/pansou-update-cache.json'); } catch {}
    res.json({ success: true, message: 'PanSou 更新成功' });
  } catch (err: any) {
    res.status(500).json({ success: false, error: err.message || 'PanSou 更新失败' });
  }
});

export default router;
