import type { FastifyInstance } from 'fastify';
import { DataStore } from './modules/data-store/index.js';
import { EncryptedKeyStore } from './modules/data-store/encryption.js';
import { PriorityQueue, queue as singletonQueue } from './modules/queue-system/index.js';
import { QueuePersistence } from './modules/queue-system/persistence.js';
import { RateLimiter } from './modules/queue-system/rate-limiter.js';
import { CharacterEngine } from './modules/character-engine/index.js';
import { OpenRouterClient } from './modules/openrouter/client.js';
import { ConversationEngine } from './modules/conversation-engine/index.js';
import { DEFAULT_TIMER_CONFIG } from './modules/timer-system/index.js';
import type { TimerConfig } from './modules/timer-system/index.js';
import { ImageEngine } from './modules/image-engine/index.js';
import { TelegramManager } from './modules/telegram-manager/index.js';
import { TranslationModule } from './modules/translation/index.js';
import { AnalyticsEngine } from './modules/analytics/index.js';
import { AutomationManager } from './modules/automation/index.js';
import { UserbotManager } from './modules/userbot/index.js';
import { config } from './utils/config.js';
import { createModuleLogger } from './utils/logger.js';
import { createQueueProcessor } from './queue-processor.js';

import characterRoutes from './routes/characters.js';
import conversationRoutes from './routes/conversations.js';
import imageRoutes from './routes/images.js';
import templateRoutes from './routes/templates.js';
import starsRoutes from './routes/stars.js';
import telegramRoutes from './routes/telegram.js';
import analyticsRoutes from './routes/analytics.js';
import systemRoutes from './routes/system.js';
import webhookRoutes from './routes/webhooks.js';
import userbotRoutes from './routes/userbot.js';
import notificationRoutes from './routes/notifications.js';
import telegramManagementRoutes from './routes/telegram-management.js';
import { NotificationService } from './modules/notification/index.js';

const log = createModuleLogger('wiring');

export interface AppModules {
  dataStore: DataStore;
  encryptedStore: EncryptedKeyStore;
  queue: PriorityQueue;
  queuePersistence: QueuePersistence;
  rateLimiter: RateLimiter;
  characterEngine: CharacterEngine;
  openRouterClient: OpenRouterClient;
  conversationEngine: ConversationEngine;
  timerConfig: TimerConfig;
  imageEngine: ImageEngine;
  telegramManager: TelegramManager;
  translationModule: TranslationModule;
  analyticsEngine: AnalyticsEngine;
  automationManager: AutomationManager;
  userbotManager: UserbotManager;
  notificationService: NotificationService;
}

export async function createAppModules(): Promise<AppModules> {
  log.info('Initializing application modules');

  // 1. Data layer — no dependencies
  const dataStore = new DataStore();
  await dataStore.init();

  const encryptedStore = new EncryptedKeyStore();
  await encryptedStore.init();

  // 2. Queue & rate limiting — use the singleton instance so all modules share the same queue
  const queue = singletonQueue;
  const queuePersistence = new QueuePersistence();
  await queuePersistence.init();

  // Load persisted queue items
  const persistedItems = await queuePersistence.loadAll();
  if (persistedItems.length > 0) {
    queue.loadItems(persistedItems);
    log.info({ count: persistedItems.length }, 'Loaded persisted queue items');
  }

  // Wire persistence callback
  queue.setOnPersist(async (items) => {
    await queuePersistence.savePending(items);
  });

  const rateLimiter = new RateLimiter();

  // 3. OpenRouter client — depends on config
  const openRouterClient = new OpenRouterClient(config.openrouterApiKey);

  // 4. Character engine — uses dataStore (via singleton internally)
  const characterEngine = new CharacterEngine();

  // 5. Conversation engine — uses dataStore, openRouter, queue (via singletons internally)
  const conversationEngine = new ConversationEngine();

  // 6. Timer config
  const timerConfig: TimerConfig = { ...DEFAULT_TIMER_CONFIG };

  // 7. Image engine — uses KIE client, templates, queue, dataStore
  const imageEngine = new ImageEngine();

  // 8. Telegram manager — depends on dataStore, encryptedStore
  const telegramManager = new TelegramManager(dataStore, encryptedStore);

  // 9. Translation — depends on dataStore, openRouterClient
  const translationModule = new TranslationModule(dataStore, openRouterClient);

  // 10. Analytics — depends on dataStore
  const analyticsEngine = new AnalyticsEngine(dataStore);

  // 11. Automation — depends on most modules
  const automationManager = new AutomationManager(
    characterEngine,
    conversationEngine,
    imageEngine,
    telegramManager,
    queue,
    timerConfig,
    analyticsEngine,
  );

  // 12. Userbot manager — MTProto client for user accounts
  const userbotManager = new UserbotManager(dataStore);

  // 13. Notification service — file-based notification storage
  const notificationService = new NotificationService();
  await notificationService.init();

  log.info('All modules initialized');

  return {
    dataStore,
    encryptedStore,
    queue,
    queuePersistence,
    rateLimiter,
    characterEngine,
    openRouterClient,
    conversationEngine,
    timerConfig,
    imageEngine,
    telegramManager,
    translationModule,
    analyticsEngine,
    automationManager,
    userbotManager,
    notificationService,
  };
}

export async function registerRoutes(app: FastifyInstance, modules: AppModules): Promise<void> {
  log.info('Registering route plugins');

  const {
    dataStore,
    characterEngine,
    conversationEngine,
    imageEngine,
    telegramManager,
    analyticsEngine,
    queue,
    translationModule,
  } = modules;

  // Character management routes
  await app.register(characterRoutes, {
    prefix: '/api/v1',
    characterEngine,
    dataStore,
  });

  // Conversation routes
  await app.register(conversationRoutes, {
    prefix: '/api/v1',
    dataStore,
    conversationEngine,
  });

  // Image generation routes
  await app.register(imageRoutes, {
    prefix: '/api/v1',
    imageEngine,
    dataStore,
  });

  // Template management routes
  await app.register(templateRoutes, {
    prefix: '/api/v1',
    dataStore,
  });

  // Stars monetization routes
  await app.register(starsRoutes, {
    prefix: '/api/v1',
    starsManager: telegramManager.getStarsManager(),
  });

  // Telegram channel management routes
  await app.register(telegramRoutes, {
    prefix: '/api/v1',
    channelManager: telegramManager.getChannelManager(),
    telegramManager,
  });

  // Analytics routes
  await app.register(analyticsRoutes, {
    prefix: '/api/v1',
    analyticsEngine,
  });

  // System routes (queue, backup, translation, bot tokens)
  await app.register(systemRoutes, {
    prefix: '/api/v1',
    queue,
    translationModule,
    telegramManager,
    dataStore,
    onBotAdded: (characterId: string, token: string) => {
      registerBotHandlers(token, characterId, modules);
      modules.automationManager.setAutomationStatus(characterId, 'active');
    },
  });

  // Webhook routes (Telegram + KIE)
  await app.register(webhookRoutes, {
    prefix: '/api/v1',
    webhookHandler: telegramManager.getWebhookHandler(),
  });

  // Userbot routes
  await app.register(userbotRoutes, {
    prefix: '/api/v1',
    userbotManager: modules.userbotManager,
    conversationEngine: modules.conversationEngine,
  });

  // Notification routes
  await app.register(notificationRoutes, {
    prefix: '/api/v1',
    notificationService: modules.notificationService,
  });

    // Telegram management routes (entity CRUD + GramJS stubs)
  await app.register(telegramManagementRoutes, {
    prefix: '/api/v1',
    userbotManager: modules.userbotManager,
    dataStore: modules.dataStore,
  });

  log.info('All route plugins registered');
}


export function wireHandlers(modules: AppModules): void {
  const { queue, telegramManager, imageEngine } = modules;
  const webhookHandler = telegramManager.getWebhookHandler();

  // 1. Register queue processor
  const processor = createQueueProcessor(modules);
  queue.setProcessor(processor);
  log.info('Queue processor registered');

  // 2. Register KIE webhook handler
  webhookHandler.onKIEComplete(async (response) => {
    const { taskId, status, resultUrl, error } = response;

    if (status === 'completed') {
      if (resultUrl) {
        try {
          await imageEngine.handleWebhookResult(taskId, resultUrl);

          // Queue quality check after successful download
          const queueItem = queue.getById(taskId);
          if (queueItem) {
            await queue.add('quality_check', queueItem.characterId, {
              imageUrl: resultUrl,
              characterId: queueItem.characterId,
              imageId: taskId,
              taskId,
            });
            log.info({ taskId }, 'Quality check queued after image download');
          }
        } catch (err: any) {
          log.error({ taskId, err: err.message }, 'Failed to process KIE webhook result');
          await imageEngine.handleFailure(taskId, err.message);
        }
      } else {
        log.error({ taskId }, 'KIE webhook completed but resultUrl is missing');
        await imageEngine.handleFailure(taskId, 'Completed but resultUrl missing');
      }
    } else if (status === 'failed') {
      log.warn({ taskId, error }, 'KIE task failed');
      await imageEngine.handleFailure(taskId, error || 'KIE task failed');
    }
  });
  log.info('KIE webhook handler registered');
}

export function registerBotHandlers(
  botToken: string,
  characterId: string,
  modules: AppModules,
): void {
  const { telegramManager, automationManager } = modules;
  const webhookHandler = telegramManager.getWebhookHandler();

  // Message handler
  webhookHandler.onMessage(botToken, async (token, message) => {
    try {
      const charId = telegramManager.getCharacterIdByToken(token);
      if (!charId) {
        log.warn({ token: token.slice(-4) }, 'Could not resolve character ID from token');
        return;
      }
      const userId = message.from?.id ?? message.chat.id;
      const text = message.text ?? '';
      if (!text) return;
      await automationManager.handleIncomingMessage(charId, userId, text);

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

  // Pre-checkout query handler
  webhookHandler.onPreCheckoutQuery(botToken, async (token, query) => {
    try {
      const charId = telegramManager.getCharacterIdByToken(token);
      if (!charId) {
        log.warn({ token: token.slice(-4) }, 'Could not resolve character ID for pre-checkout');
        const botClient = telegramManager.getBotClient(characterId);
        if (botClient) {
          await botClient.answerPreCheckoutQuery(query.id, false, 'Internal error');
        }
        return;
      }
      const botClient = telegramManager.getBotClient(charId);
      if (!botClient) {
        log.warn({ characterId: charId }, 'No bot client for pre-checkout');
        return;
      }
      await botClient.answerPreCheckoutQuery(query.id, true);
    } catch (err: any) {
      log.error({ characterId, err: err.message }, 'Error handling pre-checkout query');
    }
  });

  // Successful payment handler
  webhookHandler.onSuccessfulPayment(botToken, async (token, payment, message) => {
    try {
      const charId = telegramManager.getCharacterIdByToken(token);
      if (!charId) {
        log.warn({ token: token.slice(-4) }, 'Could not resolve character ID for payment');
        return;
      }
      const userId = message.from?.id ?? message.chat.id;
      await automationManager.handleStarsPayment(charId, userId, payment);

      // Fire-and-forget notification for Stars purchase
      try {
        const starCount = payment.total_amount ?? 0;
        const userName = message.from?.first_name || message.from?.username || 'Kullanıcı';
        const character = await modules.dataStore.getCharacter(charId);
        const characterName = character?.identity?.name || charId;
        await modules.notificationService.create({
          type: 'stars_purchase',
          title: 'Stars satın alımı',
          body: `${userName}, ${characterName} için ${starCount} Stars harcadı`,
          characterId: charId,
          link: `/characters/${charId}`,
        });
      } catch (notifErr: any) {
        log.warn({ characterId: charId, err: notifErr.message }, 'Failed to create payment notification');
      }
    } catch (err: any) {
      log.error({ characterId, err: err.message }, 'Error handling successful payment');
    }
  });

  log.info({ characterId }, 'Bot handlers registered');
}

export async function wireBotHandlers(modules: AppModules): Promise<void> {
  const { telegramManager, encryptedStore } = modules;
  const activeBots = telegramManager.getActiveBots();

  for (const [characterId] of activeBots) {
    try {
      const token = await encryptedStore.getKey(`bot-token:${characterId}`);
      if (!token) {
        log.warn({ characterId }, 'No token found for active bot, skipping handler registration');
        continue;
      }
      registerBotHandlers(token, characterId, modules);
      modules.automationManager.setAutomationStatus(characterId, 'active');
    } catch (err: any) {
      log.error({ characterId, err: err.message }, 'Failed to register bot handlers');
    }
  }

  log.info({ botCount: activeBots.size }, 'All bot handlers wired');
}
