import { buildServer } from './server.js';
import { createAppModules, wireHandlers, wireBotHandlers } from './wiring.js';
import { config, validateConfigWarnings } from './utils/config.js';
import { ensureDir } from './modules/data-store/file-ops.js';
import { createModuleLogger } from './utils/logger.js';
import { startKIEPoller } from './kie-poller.js';
import { startTelegramPoller } from './telegram-poller.js';
import { createKIEClient } from './modules/image-engine/kie-client.js';
import { getImageProvider } from './modules/image-engine/image-provider.js';
import { sanitizePrompt } from './modules/image-engine/prompt-safety.js';
import { readJSON } from './modules/data-store/file-ops.js';
import { startAutoBackup, stopAutoBackup } from './modules/data-store/backup.js';
import { fetch } from 'undici';
import { resolve } from 'path';
import { readdir } from 'fs/promises';
import type { CharacterDNA, MasterJSONPrompt } from './types/character.js';
import type { Message } from './types/conversation.js';
import type { KIECreateTaskRequest } from './types/api.js';

const log = createModuleLogger('main');

async function main() {
  // Ensure data directories exist
  await ensureDir(config.dataDir);
  await ensureDir(`${config.dataDir}/config`);
  await ensureDir(`${config.dataDir}/characters`);
  await ensureDir(`${config.dataDir}/templates`);
  await ensureDir(`${config.dataDir}/queue`);
  await ensureDir(`${config.dataDir}/analytics`);
  await ensureDir(`${config.dataDir}/stars`);
  await ensureDir(`${config.dataDir}/logs`);
  await ensureDir(`${config.dataDir}/backups`);
  await ensureDir(`${config.dataDir}/translations`);

  // Check config warnings
  const warnings = validateConfigWarnings(config);
  for (const w of warnings) {
    log.warn(w);
  }

  // Initialize all modules
  log.info('Initializing application modules...');
  const modules = await createAppModules();

  // Wire queue processor and KIE webhook handlers
  wireHandlers(modules);

  // Start KIE task poller
  const kiePoller = startKIEPoller(modules);
  log.info('KIE task poller started');

  // Build server with all routes registered
  const app = await buildServer(modules);

  // Start TelegramManager (loads persisted bot tokens)
  await modules.telegramManager.start();
  log.info('TelegramManager started');

  // Wire bot-specific handlers (must be after telegramManager.start() so tokens are loaded)
  await wireBotHandlers(modules);

  // Initialize automation status for all active characters (including userbot-only ones)
  try {
    const allChars = await modules.characterEngine.listCharacters();
    let activatedCount = 0;
    for (const char of allChars) {
      if (char.status === 'active') {
        const currentStatus = modules.automationManager.getAutomationStatus(char.id);
        if (currentStatus !== 'active') {
          modules.automationManager.setAutomationStatus(char.id, 'active');
          activatedCount++;
        }
      }
    }
    log.info({ activatedCount, totalChars: allChars.length }, 'Automation status initialized for active characters');
  } catch (err: any) {
    log.error({ err: err.message }, 'Failed to initialize automation statuses');
  }

  // Start Telegram long-polling for local development (no webhook needed)
  const telegramPoller = startTelegramPoller(modules);

  // Wire userbot message handler to conversation engine
  modules.userbotManager.setMessageHandler(async (characterId, senderId, senderName, text, chatId, isPrivate, photo) => {
    if (!isPrivate) return null;
    
    // Check automation status
    const status = modules.automationManager.getAutomationStatus(characterId);
    if (status !== 'active') {
      log.warn({ characterId, status }, 'Ignoring userbot message — automation not active');
      return null;
    }

    try {
      // Save user message to conversation history
      const { conversationManager } = await import('./modules/conversation-engine/history.js');
      if (senderName) {
        await conversationManager.updateUserInfo(characterId, senderId, { name: senderName });
      }

      // Determine message type and photo info for saving
      const hasPhoto = !!photo;
      const hasText = !!text;
      let messageType: 'text' | 'photo' | 'text_photo' = 'text';
      if (hasPhoto && hasText) {
        messageType = 'text_photo';
      } else if (hasPhoto) {
        messageType = 'photo';
      }

      const photoInfo = hasPhoto
        ? { messageType, imagePath: photo!.imagePath, imageUrl: photo!.imageUrl }
        : hasText ? undefined : undefined;

      const messageContent = text || (hasPhoto ? '[Fotoğraf]' : '');
      await conversationManager.addMessage(characterId, senderId, 'user', messageContent, undefined, photoInfo);

      // Fire-and-forget notification for new userbot message
      try {
        const character = await modules.dataStore.getCharacter(characterId);
        const characterName = character?.identity?.name || characterId;
        const userName = senderName || 'Kullanıcı';
        await modules.notificationService.create({
          type: 'new_message',
          title: 'Yeni mesaj',
          body: `${characterName} karakterine ${userName} mesaj gönderdi`,
          characterId,
          telegramUserId: senderId,
          link: `/characters/${characterId}/conversations/${senderId}`,
        });
      } catch (notifErr: any) {
        log.warn({ characterId, err: notifErr.message }, 'Failed to create userbot message notification');
      }

      // Generate AI response
      const response = await modules.conversationEngine.generateResponse(characterId, senderId);

      // Save assistant response
      await conversationManager.addMessage(characterId, senderId, 'assistant', response);

      // Check for [FOTO] tag
      const hasFoto = response.includes('[FOTO]');
      const cleanResponse = response.replace(/\s*\[FOTO\]\s*/g, '').trim();

      if (hasFoto) {
        // Fire and forget — don't block the text response
        (async () => {
          try {
            log.info({ characterId, senderId }, 'FOTO etiketi algılandı, fotoğraf üretiliyor...');

            // Load character DNA
            const dnaPath = resolve(config.dataDir, 'characters', characterId, 'dna.json');
            const dna = await readJSON<CharacterDNA>(dnaPath);

            // Load master prompt for negative prompt
            const masterPromptPath = resolve(config.dataDir, 'characters', characterId, 'master-prompt.json');
            const masterPrompt = await readJSON<MasterJSONPrompt>(masterPromptPath);
            const negativePrompt = masterPrompt?.negative_prompt || 'deformed, blurry, bad anatomy, low quality';

            // Use AI prompt generator (includes Turkey timezone awareness)
            const { generateImagePrompt } = await import('./modules/image-engine/ai-prompt-generator.js');
            const { conversationManager } = await import('./modules/conversation-engine/history.js');

            // Get recent user messages for context
            const recentMessages = await conversationManager.getRecentMessages(characterId, senderId, 24);
            const userTexts = recentMessages
              .filter((m: Message) => m.role === 'user')
              .slice(-5)
              .map((m: Message) => m.content);

            let imagePrompt: string;
            let aspectRatio = '9:16';
            let useRefs = true;

            if (dna) {
              try {
                const generated = await generateImagePrompt(dna, {
                  context: userTexts,
                });
                imagePrompt = generated.prompt;
                aspectRatio = generated.aspectRatio;
                useRefs = generated.useRefs;
                log.info({ characterId, category: generated.category, safetyModified: generated.safetyModified }, 'AI prompt generator ile üretildi (saat bilgisi dahil)');
              } catch (genErr: any) {
                log.warn({ characterId, error: genErr.message }, 'AI prompt generator başarısız, fallback kullanılıyor');
                // Fallback: Türkiye saatine göre basit ortam ekle
                const turkeyHour = new Date(Date.now() + 3 * 60 * 60 * 1000).getUTCHours();
                let timeScene: string;
                if (turkeyHour >= 6 && turkeyHour < 12) timeScene = 'morning sunlight, bright natural light';
                else if (turkeyHour >= 12 && turkeyHour < 17) timeScene = 'afternoon sun, bright daylight';
                else if (turkeyHour >= 17 && turkeyHour < 20) timeScene = 'golden hour, warm sunset light';
                else if (turkeyHour >= 20 && turkeyHour < 23) timeScene = 'city lights, nighttime, warm artificial lighting';
                else timeScene = 'dim lamp light, cozy bedroom, late night vibe';

                const subject = masterPrompt?.subject || 'young woman';
                imagePrompt = `${subject}, casual selfie, ${timeScene}, instagram style photo, high quality, realistic`;
              }
            } else {
              const turkeyHour = new Date(Date.now() + 3 * 60 * 60 * 1000).getUTCHours();
              let timeScene: string;
              if (turkeyHour >= 6 && turkeyHour < 17) timeScene = 'natural daylight';
              else if (turkeyHour >= 17 && turkeyHour < 20) timeScene = 'golden hour sunset';
              else timeScene = 'dim warm lamp light, nighttime';

              const subject = masterPrompt?.subject || 'young woman';
              imagePrompt = `${subject}, casual selfie, ${timeScene}, smiling at camera, instagram style photo, high quality, realistic`;
            }

            log.info({ characterId, imagePrompt: imagePrompt.slice(0, 100) }, 'KIE görüntü üretim isteği gönderiliyor');

            // Sanitize prompt for Google policy compliance
            const safetyResult = sanitizePrompt(imagePrompt);
            if (safetyResult.wasModified) {
              log.info({ changes: safetyResult.changes }, 'Prompt policy-safe hale getirildi');
              imagePrompt = safetyResult.sanitizedPrompt;
            }
            if (safetyResult.warnings.length > 0) {
              log.warn({ warnings: safetyResult.warnings }, 'Prompt riskli kelime kombinasyonları içeriyor');
            }

            // Generate image via image provider (KIE → Gemini fallback) with quality control retry loop
            const imageProvider = getImageProvider();
            const { getQualityController } = await import('./modules/image-engine/quality-control.js');
            const qualityController = getQualityController();
            const MAX_QC_ATTEMPTS = 3;
            const QC_THRESHOLD = 7.0;

            // Load reference image URLs for character consistency
            const refUrlsPath = resolve(config.dataDir, 'characters', characterId, 'reference-urls.json');
            const refUrls = await readJSON<Record<string, string>>(refUrlsPath);
            const referenceImageUrls = refUrls ? Object.values(refUrls).filter(Boolean) : [];
            if (referenceImageUrls.length > 0) {
              log.info({ characterId, refCount: referenceImageUrls.length }, 'Referans görseller yüklendi, tutarlılık için eklenecek');
            }

            let finalImageBuffer: Buffer | null = null;
            let currentPrompt = imagePrompt;

            for (let attempt = 1; attempt <= MAX_QC_ATTEMPTS; attempt++) {
              log.info({ characterId, attempt, maxAttempts: MAX_QC_ATTEMPTS }, 'Görsel üretim denemesi');

              const genResult = await imageProvider.generateAndWait({
                model: 'nano-banana-2',
                prompt: currentPrompt,
                negativePrompt,
                aspectRatio: aspectRatio as KIECreateTaskRequest['aspectRatio'],
                imageInput: useRefs && referenceImageUrls.length > 0 ? referenceImageUrls : undefined,
              });
              const imageUrl = genResult.imageUrl;
              if (genResult.provider !== 'kie') {
                log.info({ characterId, provider: genResult.provider }, 'Görsel alternatif provider ile üretildi');
              }

              log.info({ characterId, imageUrl, attempt }, 'Fotoğraf üretildi, kalite kontrol yapılıyor...');

              // Quality control with VLM
              if (dna) {
                try {
                  const imageId = `photo_${Date.now()}_${attempt}`;
                  const taskId = `qc_${characterId}_${senderId}_${Date.now()}`;
                  const report = await qualityController.checkQuality(
                    imageUrl, characterId, imageId, taskId, QC_THRESHOLD
                  );

                  log.info({
                    characterId, attempt, totalScore: report.totalScore,
                    passed: report.passed, feedback: report.feedback?.slice(0, 100)
                  }, 'Kalite kontrol sonucu');

                  if (report.passed) {
                    // Quality check passed — download and send
                    const imgResponse = await fetch(imageUrl);
                    if (!imgResponse.ok) {
                      throw new Error(`Fotoğraf indirilemedi: ${imgResponse.status}`);
                    }
                    finalImageBuffer = Buffer.from(await imgResponse.arrayBuffer());
                    log.info({ characterId, attempt, score: report.totalScore }, 'Görsel kalite kontrolünü geçti');
                    break;
                  } else {
                    log.warn({ characterId, attempt, score: report.totalScore, feedback: report.feedback },
                      'Görsel kalite kontrolünü geçemedi, tekrar üretiliyor...');
                    // Append feedback to prompt for better next attempt
                    if (report.feedback && attempt < MAX_QC_ATTEMPTS) {
                      currentPrompt = `${imagePrompt}, improved quality, ${report.feedback}`;
                    }
                  }
                } catch (qcErr: any) {
                  log.warn({ characterId, attempt, error: qcErr.message },
                    'Kalite kontrol hatası, görsel yine de gönderilecek');
                  // If QC fails, still send the image
                  const imgResponse = await fetch(imageUrl);
                  if (imgResponse.ok) {
                    finalImageBuffer = Buffer.from(await imgResponse.arrayBuffer());
                  }
                  break;
                }
              } else {
                // No DNA for QC, just download
                const imgResponse = await fetch(imageUrl);
                if (imgResponse.ok) {
                  finalImageBuffer = Buffer.from(await imgResponse.arrayBuffer());
                }
                break;
              }
            }

            // If all QC attempts failed, download the last generated image anyway
            if (!finalImageBuffer) {
              log.warn({ characterId }, 'Tüm kalite kontrol denemeleri başarısız, son görsel gönderiliyor');
              const lastResult = await imageProvider.generateAndWait({
                model: 'nano-banana-2',
                prompt: imagePrompt,
                negativePrompt,
                aspectRatio: aspectRatio as KIECreateTaskRequest['aspectRatio'],
                imageInput: useRefs && referenceImageUrls.length > 0 ? referenceImageUrls : undefined,
              });
              const imgResponse = await fetch(lastResult.imageUrl);
              if (imgResponse.ok) {
                finalImageBuffer = Buffer.from(await imgResponse.arrayBuffer());
              }
            }

            // Send photo via userbot
            if (finalImageBuffer) {
              const userbotClient = modules.userbotManager.getClient(characterId);
              if (userbotClient && userbotClient.isConnected()) {
                await userbotClient.sendPhotoFromBuffer(chatId, finalImageBuffer, `defne_${Date.now()}.jpg`);
                log.info({ characterId, senderId, chatId }, 'Fotoğraf başarıyla gönderildi');

                // Save photo to disk and mark in conversation history
                const photoFilename = `photo_${Date.now()}.jpg`;
                const photoDir = resolve(config.dataDir, 'characters', characterId, 'generated-images');
                const { ensureDir: ensureDirFn } = await import('./modules/data-store/file-ops.js');
                await ensureDirFn(photoDir);
                const photoPath = resolve(photoDir, photoFilename);
                const { writeFile: writeFileFn } = await import('fs/promises');
                await writeFileFn(photoPath, finalImageBuffer);
                const imageServePath = `/static/characters/${characterId}/generated-images/${photoFilename}`;
                await conversationManager.addMessage(characterId, senderId, 'assistant', '[Fotoğraf gönderildi]', { photoSent: true });
                // Update last message with image info
                const hist = await conversationManager.getHistory(characterId, senderId);
                if (hist && hist.messages.length > 0) {
                  const lastMsg = hist.messages[hist.messages.length - 1];
                  lastMsg.messageType = 'photo';
                  lastMsg.imagePath = imageServePath;
                  const { dataStore: ds } = await import('./modules/data-store/index.js');
                  await ds.saveConversationHistory(hist);
                }
              } else {
                log.warn({ characterId }, 'Userbot bağlı değil, fotoğraf gönderilemedi');
              }
            } else {
              log.error({ characterId }, 'Fotoğraf buffer oluşturulamadı');
            }
          } catch (err: any) {
            log.error({ characterId, error: err.message, stack: err.stack }, 'Fotoğraf üretme/gönderme hatası');
          }
        })();
      }

      return cleanResponse;
    } catch (err: any) {
      log.error({ characterId, senderId, error: err.message }, 'Failed to generate userbot response');
      return null;
    }
  });

  // Reconnect saved userbot sessions
  await modules.userbotManager.reconnectAll();
  log.info('Userbot sessions reconnected');

  // Add all active bots to poller
  const activeBots = modules.telegramManager.getActiveBots();
  for (const [characterId] of activeBots) {
    const token = await modules.encryptedStore.getKey(`bot-token:${characterId}`);
    if (token) {
      telegramPoller.addBot(characterId, token);
    }
  }
  telegramPoller.start();
  log.info('Telegram long-polling started');

  // Start analytics periodic calculation (daily at midnight)
  modules.analyticsEngine.startPeriodicCalculation();
  log.info('Analytics periodic calculation started');

  // Start automation manager (content cycles)
  modules.automationManager.startAutomation();
  log.info('Automation manager started');

  // Start automatic daily backup (03:00 every day, keep last 7)
  startAutoBackup();
  log.info('Automatic backup scheduler started');

  // Graceful shutdown
  const shutdown = async () => {
    log.info('Shutting down gracefully...');
    stopAutoBackup();
    kiePoller.stop();
    telegramPoller.stop();
    modules.automationManager.stopAutomation();
    modules.analyticsEngine.stopPeriodicCalculation();
    await modules.userbotManager.disconnectAll();
    await modules.telegramManager.stop();
    await app.close();
    process.exit(0);
  };
  process.on('SIGINT', shutdown);
  process.on('SIGTERM', shutdown);

  await app.listen({ port: config.port, host: '0.0.0.0' });
  log.info({ port: config.port }, 'Server started');
}

main().catch((err) => {
  log.error({ err }, 'Failed to start server');
  console.error(err);
  process.exit(1);
});