import { FastifyInstance, FastifyPluginOptions } from 'fastify';
import { readFile } from 'fs/promises';
import { existsSync } from 'fs';
import { resolve } from 'path';
import type { PriorityQueue } from '../modules/queue-system/index.js';
import type { TranslationModule } from '../modules/translation/index.js';
import type { TelegramManager } from '../modules/telegram-manager/index.js';
import type { DataStore } from '../modules/data-store/index.js';
import { createBackup, listBackups, restoreBackup } from '../modules/data-store/backup.js';
import { config } from '../utils/config.js';
import { writeFile } from 'fs/promises';

interface SystemRouteOpts extends FastifyPluginOptions {
  queue: PriorityQueue;
  translationModule: TranslationModule;
  telegramManager: TelegramManager;
  dataStore: DataStore;
  onBotAdded?: (characterId: string, token: string) => void | Promise<void>;
}

export default async function systemRoutes(app: FastifyInstance, opts: SystemRouteOpts) {
  const { queue, translationModule, telegramManager, dataStore } = opts;

  // ---- Queue routes ----

  // GET /queue/status — Queue status
  app.get('/queue/status', async (_request, reply) => {
    try {
      const stats = queue.getStats();
      return reply.status(200).send({ success: true, data: stats });
    } catch (err: any) {
      return reply.status(500).send({ success: false, error: err.message });
    }
  });

  // GET /queue/failed — Failed tasks
  app.get('/queue/failed', async (_request, reply) => {
    try {
      const failed = queue.getFailed();
      return reply.status(200).send({ success: true, data: failed });
    } catch (err: any) {
      return reply.status(500).send({ success: false, error: err.message });
    }
  });

  // POST /queue/failed/:id/retry — Retry failed task
  app.post('/queue/failed/:id/retry', async (request, reply) => {
    const { id } = request.params as { id: string };

    try {
      const retried = await queue.retry(id);
      if (!retried) {
        return reply.status(404).send({ success: false, error: 'Task not found or cannot be retried' });
      }
      return reply.status(200).send({ success: true, data: { retried: true } });
    } catch (err: any) {
      return reply.status(500).send({ success: false, error: err.message });
    }
  });

  // ---- System routes ----

  // GET /system/health — System health
  app.get('/system/health', async (_request, reply) => {
    try {
      const queueStats = queue.getStats();
      const activeBots = telegramManager.getActiveBots();
      return reply.status(200).send({
        success: true,
        data: {
          status: 'ok',
          timestamp: new Date().toISOString(),
          queue: queueStats,
          activeBots: activeBots.size,
          uptime: process.uptime(),
        },
      });
    } catch (err: any) {
      return reply.status(500).send({ success: false, error: err.message });
    }
  });

  // GET /system/errors — Recent errors
  app.get('/system/errors', async (request, reply) => {
    const { limit } = request.query as { limit?: string };
    const maxLines = limit ? Number(limit) : 50;

    try {
      const errorsLogPath = resolve(config.dataDir, 'logs', 'errors.log');
      if (!existsSync(errorsLogPath)) {
        return reply.status(200).send({ success: true, data: [] });
      }

      const content = await readFile(errorsLogPath, 'utf-8');
      const lines = content.trim().split('\n').filter(Boolean);
      const recent = lines.slice(-maxLines);

      const errors = recent.map((line) => {
        try {
          return JSON.parse(line);
        } catch {
          return { raw: line };
        }
      });

      return reply.status(200).send({ success: true, data: errors });
    } catch (err: any) {
      return reply.status(500).send({ success: false, error: err.message });
    }
  });

  // ---- Backup routes ----

  // POST /backup — Start backup
  app.post('/backup', async (_request, reply) => {
    try {
      const info = await createBackup();
      return reply.status(201).send({ success: true, data: info });
    } catch (err: any) {
      return reply.status(500).send({ success: false, error: err.message });
    }
  });

  // GET /backup/list — List backups
  app.get('/backup/list', async (_request, reply) => {
    try {
      const backups = await listBackups();
      return reply.status(200).send({ success: true, data: backups });
    } catch (err: any) {
      return reply.status(500).send({ success: false, error: err.message });
    }
  });

  // POST /backup/restore — Restore from backup
  app.post('/backup/restore', async (request, reply) => {
    const body = request.body as { filename?: string } | null;

    if (!body?.filename) {
      return reply.status(400).send({ success: false, error: 'filename is required' });
    }

    try {
      const backupPath = resolve(config.dataDir, 'backups', body.filename);
      if (!existsSync(backupPath)) {
        return reply.status(404).send({ success: false, error: 'Backup file not found' });
      }
      await restoreBackup(backupPath);
      return reply.status(200).send({ success: true, data: { restored: true, filename: body.filename } });
    } catch (err: any) {
      return reply.status(500).send({ success: false, error: err.message });
    }
  });

  // ---- Translation routes ----

  // POST /translate — Turkish → English translation
  app.post('/translate', async (request, reply) => {
    const body = request.body as { text?: string } | null;

    if (!body?.text) {
      return reply.status(400).send({ success: false, error: 'text is required' });
    }

    try {
      const result = await translationModule.translatePrompt(body.text);
      return reply.status(200).send({ success: true, data: result });
    } catch (err: any) {
      return reply.status(500).send({ success: false, error: err.message });
    }
  });

  // GET /translate/glossary — Get glossary
  app.get('/translate/glossary', async (_request, reply) => {
    try {
      const glossary = await translationModule.getGlossary();
      return reply.status(200).send({ success: true, data: glossary });
    } catch (err: any) {
      return reply.status(500).send({ success: false, error: err.message });
    }
  });

  // PUT /translate/glossary — Update glossary
  app.put('/translate/glossary', async (request, reply) => {
    const body = request.body as Record<string, string> | null;

    if (!body || typeof body !== 'object') {
      return reply.status(400).send({ success: false, error: 'Request body must be a JSON object of { turkish: english } pairs' });
    }

    try {
      await translationModule.updateGlossary(body);
      return reply.status(200).send({ success: true, data: { updated: true } });
    } catch (err: any) {
      return reply.status(500).send({ success: false, error: err.message });
    }
  });

  // ---- Bot token routes ----

  // GET /bot-tokens — List bot tokens (masked)
  app.get('/bot-tokens', async (_request, reply) => {
    try {
      const bots = telegramManager.getActiveBots();
      const tokens: Array<{ characterId: string; botInfo?: unknown; active: boolean }> = [];
      for (const [characterId, entry] of bots) {
        tokens.push({
          characterId,
          botInfo: entry.botInfo,
          active: true,
        });
      }
      return reply.status(200).send({ success: true, data: tokens });
    } catch (err: any) {
      return reply.status(500).send({ success: false, error: err.message });
    }
  });

  // POST /bot-tokens — Add bot token
  app.post('/bot-tokens', async (request, reply) => {
    const body = request.body as { characterId?: string; token?: string } | null;

    if (!body?.characterId || !body?.token) {
      return reply.status(400).send({ success: false, error: 'characterId and token are required' });
    }

    try {
      const botInfo = await telegramManager.addBot(body.characterId, body.token);
      if (opts.onBotAdded) {
        await opts.onBotAdded(body.characterId, body.token);
      }
      return reply.status(201).send({ success: true, data: { characterId: body.characterId, botInfo } });
    } catch (err: any) {
      return reply.status(400).send({ success: false, error: err.message });
    }
  });

  // PUT /bot-tokens/:characterId — Update bot token
  app.put('/bot-tokens/:characterId', async (request, reply) => {
    const { characterId } = request.params as { characterId: string };
    const body = request.body as { token?: string } | null;

    if (!body?.token) {
      return reply.status(400).send({ success: false, error: 'token is required' });
    }

    try {
      const botInfo = await telegramManager.updateBot(characterId, body.token);
      if (opts.onBotAdded) {
        await opts.onBotAdded(characterId, body.token);
      }
      return reply.status(200).send({ success: true, data: { characterId, botInfo } });
    } catch (err: any) {
      return reply.status(400).send({ success: false, error: err.message });
    }
  });

  // DELETE /bot-tokens/:characterId — Delete bot token
  app.delete('/bot-tokens/:characterId', async (request, reply) => {
    const { characterId } = request.params as { characterId: string };

    try {
      await telegramManager.removeBot(characterId);
      return reply.status(200).send({ success: true, data: { deleted: true } });
    } catch (err: any) {
      return reply.status(500).send({ success: false, error: err.message });
    }
  });

  // POST /bot-tokens/:characterId/validate — Validate token
  app.post('/bot-tokens/:characterId/validate', async (request, reply) => {
    const { characterId } = request.params as { characterId: string };

    try {
      const botInfo = await telegramManager.validateBot(characterId);
      return reply.status(200).send({ success: true, data: { characterId, botInfo, valid: true } });
    } catch (err: any) {
      return reply.status(400).send({ success: false, error: err.message });
    }
  });

  // ---- API Config routes ----

  // GET /system/api-config — Read current API keys (masked)
  app.get('/system/api-config', async (_request, reply) => {
    try {
      const mask = (val: string) => {
        if (!val) return '';
        if (val.length <= 8) return '••••••••';
        return val.slice(0, 4) + '••••••••' + val.slice(-4);
      };
      return reply.status(200).send({
        success: true,
        data: {
          kieApiKey: mask(config.kieApiKey),
          geminiApiKey: mask(config.geminiApiKey),
          openrouterApiKey: mask(config.openrouterApiKey),
          telegramApiId: config.telegramApiId ? String(config.telegramApiId) : '',
          telegramApiHash: mask(config.telegramApiHash),
        },
      });
    } catch (err: any) {
      return reply.status(500).send({ success: false, error: err.message });
    }
  });

  // PUT /system/api-config — Update API keys in .env
  app.put('/system/api-config', async (request, reply) => {
    const body = request.body as Partial<{
      kieApiKey: string;
      geminiApiKey: string;
      openrouterApiKey: string;
      telegramApiId: string;
      telegramApiHash: string;
    }> | null;

    if (!body) {
      return reply.status(400).send({ success: false, error: 'Request body is required' });
    }

    try {
      const envPath = resolve(process.cwd(), '.env');
      let envContent = '';
      try {
        const { readFile: readF } = await import('fs/promises');
        envContent = await readF(envPath, 'utf-8');
      } catch {
        envContent = '';
      }

      const envLines = envContent.split('\n');
      const envMap = new Map<string, string>();
      const keyOrder: string[] = [];

      for (const line of envLines) {
        const trimmed = line.trim();
        if (!trimmed || trimmed.startsWith('#')) continue;
        const eqIdx = trimmed.indexOf('=');
        if (eqIdx > 0) {
          const key = trimmed.slice(0, eqIdx);
          const val = trimmed.slice(eqIdx + 1);
          envMap.set(key, val);
          keyOrder.push(key);
        }
      }

      // Only update keys that are NOT masked (contain actual values, not ••••)
      const updates: Record<string, string> = {};
      if (body.kieApiKey && !body.kieApiKey.includes('••')) updates['KIE_API_KEY'] = body.kieApiKey;
      if (body.geminiApiKey && !body.geminiApiKey.includes('••')) updates['GEMINI_API_KEY'] = body.geminiApiKey;
      if (body.openrouterApiKey && !body.openrouterApiKey.includes('••')) updates['OPENROUTER_API_KEY'] = body.openrouterApiKey;
      if (body.telegramApiId && !body.telegramApiId.includes('••')) updates['TELEGRAM_API_ID'] = body.telegramApiId;
      if (body.telegramApiHash && !body.telegramApiHash.includes('••')) updates['TELEGRAM_API_HASH'] = body.telegramApiHash;

      for (const [key, val] of Object.entries(updates)) {
        envMap.set(key, val);
        if (!keyOrder.includes(key)) keyOrder.push(key);
      }

      // Rebuild .env
      const newEnv = keyOrder.map(k => `${k}=${envMap.get(k) ?? ''}`).join('\n') + '\n';
      await writeFile(envPath, newEnv, 'utf-8');

      // Update runtime config
      if (updates['KIE_API_KEY']) (config as any).kieApiKey = updates['KIE_API_KEY'];
      if (updates['GEMINI_API_KEY']) (config as any).geminiApiKey = updates['GEMINI_API_KEY'];
      if (updates['OPENROUTER_API_KEY']) (config as any).openrouterApiKey = updates['OPENROUTER_API_KEY'];

      // Refresh image provider if any image API key changed
      if (updates['KIE_API_KEY'] || updates['GEMINI_API_KEY']) {
        try {
          const { refreshImageProvider } = await import('../modules/image-engine/image-provider.js');
          refreshImageProvider();
        } catch {}
      }
      if (updates['TELEGRAM_API_ID']) (config as any).telegramApiId = parseInt(updates['TELEGRAM_API_ID'], 10);
      if (updates['TELEGRAM_API_HASH']) (config as any).telegramApiHash = updates['TELEGRAM_API_HASH'];

      return reply.status(200).send({ success: true, data: { updated: Object.keys(updates) } });
    } catch (err: any) {
      return reply.status(500).send({ success: false, error: err.message });
    }
  });

  // POST /system/test-api-key — Test connectivity for a provider
  app.post('/system/test-api-key', async (request, reply) => {
    const body = request.body as { provider?: string } | null;
    if (!body?.provider) {
      return reply.status(400).send({ success: false, error: 'provider is required (kie, openrouter, telegram)' });
    }

    try {
      const { provider } = body;

      if (provider === 'kie') {
        if (!config.kieApiKey) {
          return reply.status(200).send({ success: false, error: 'KIE API Key ayarlanmamis' });
        }
        // Test KIE API with a simple request
        const { fetch } = await import('undici');
        const res = await fetch('https://api.kie.ai/api/v1/jobs/recordInfo?taskId=test', {
          headers: { 'Authorization': `Bearer ${config.kieApiKey}` },
        });
        // 404 or 400 means API key works, just no task found
        const ok = res.status !== 401 && res.status !== 403;
        return reply.status(200).send({ success: ok, data: { provider, status: ok ? 'connected' : 'unauthorized' } });
      }

      if (provider === 'gemini') {
        if (!config.geminiApiKey) {
          return reply.status(200).send({ success: false, error: 'Gemini API Key ayarlanmamış' });
        }
        const { fetch } = await import('undici');
        const res = await fetch('https://geminiapi.codefast.app/v1/validate-key', {
          headers: { 'Authorization': `Bearer ${config.geminiApiKey}` },
        });
        const ok = res.status === 200;
        let credits: any = null;
        if (ok) {
          try {
            const json = await res.json() as any;
            credits = json.credits;
          } catch {}
        }
        return reply.status(200).send({ success: ok, data: { provider, status: ok ? 'connected' : 'unauthorized', credits } });
      }

      if (provider === 'openrouter') {
        if (!config.openrouterApiKey) {
          return reply.status(200).send({ success: false, error: 'OpenRouter API Key ayarlanmamis' });
        }
        const { fetch } = await import('undici');
        const res = await fetch('https://openrouter.ai/api/v1/models', {
          headers: { 'Authorization': `Bearer ${config.openrouterApiKey}` },
        });
        const ok = res.status === 200;
        return reply.status(200).send({ success: ok, data: { provider, status: ok ? 'connected' : 'unauthorized' } });
      }

      if (provider === 'telegram') {
        if (!config.telegramApiId || !config.telegramApiHash) {
          return reply.status(200).send({ success: false, error: 'Telegram API ID ve Hash ayarlanmamis' });
        }
        // We can't fully test Telegram API without a session, just verify values exist
        const ok = config.telegramApiId > 0 && config.telegramApiHash.length > 10;
        return reply.status(200).send({ success: ok, data: { provider, status: ok ? 'configured' : 'invalid' } });
      }

      return reply.status(400).send({ success: false, error: `Bilinmeyen provider: ${provider}` });
    } catch (err: any) {
      return reply.status(200).send({ success: false, error: err.message });
    }
  });
}
