import type { FastifyInstance } from 'fastify';
import { extractAuth } from '../../lib/auth.js';
import { BadRequestError, NotFoundError } from '../../lib/errors.js';
import {
  SendEmailSchema,
  SendSlackSchema,
  SendTelegramSchema,
  SendTestEmailSchema,
} from './types.js';
import { BUILT_IN_TEMPLATES } from './templates.js';
import { dispatchEmail, dispatchSlack, dispatchTelegram } from './dispatcher.js';
import * as repo from './repository.js';

const DEFAULT_PRODUCT_ID = 'lysnrai';

export async function deliveryRoutes(app: FastifyInstance) {
  // List all email templates
  app.get('/delivery/templates', async req => {
    await extractAuth(req);
    return BUILT_IN_TEMPLATES.map(({ id, name, subject, variables }) => ({
      id,
      name,
      subject,
      variables,
    }));
  });

  // Get a specific template (full content)
  app.get('/delivery/templates/:id', async req => {
    await extractAuth(req);
    const { id } = req.params as { id: string };
    const template = BUILT_IN_TEMPLATES.find(t => t.id === id);
    if (!template) throw new BadRequestError(`Template '${id}' not found`);
    return template;
  });

  // Send an email via template
  app.post('/delivery/send-email', async req => {
    await extractAuth(req);
    const parsed = SendEmailSchema.safeParse(req.body);
    if (!parsed.success) {
      throw new BadRequestError(parsed.error.issues.map(i => i.message).join('; '));
    }

    const result = await dispatchEmail(
      {
        to: parsed.data.to,
        templateId: parsed.data.templateId,
        variables: parsed.data.variables,
        productId: parsed.data.productId,
      },
      req.log
    );

    if (!result.success) {
      throw new BadRequestError(`Email delivery failed: ${result.error}`);
    }

    return { success: true, messageId: result.messageId };
  });

  // Send a test email (admin only, uses default productId)
  app.post('/delivery/send-test', async req => {
    await extractAuth(req);
    const parsed = SendTestEmailSchema.safeParse(req.body);
    if (!parsed.success) {
      throw new BadRequestError(parsed.error.issues.map(i => i.message).join('; '));
    }

    const result = await dispatchEmail(
      {
        to: parsed.data.to,
        templateId: parsed.data.templateId,
        variables: parsed.data.variables,
        productId: DEFAULT_PRODUCT_ID,
      },
      req.log
    );

    return { success: result.success, messageId: result.messageId, error: result.error };
  });

  app.post('/delivery/send-telegram', async req => {
    await extractAuth(req);
    const parsed = SendTelegramSchema.safeParse(req.body);
    if (!parsed.success) {
      throw new BadRequestError(parsed.error.issues.map(i => i.message).join('; '));
    }

    const result = await dispatchTelegram(parsed.data);
    if (!result.success) {
      throw new BadRequestError(`Telegram delivery failed: ${result.error}`);
    }

    return { success: true, messageId: result.messageId };
  });

  app.post('/delivery/send-slack', async req => {
    await extractAuth(req);
    const parsed = SendSlackSchema.safeParse(req.body);
    if (!parsed.success) {
      throw new BadRequestError(parsed.error.issues.map(i => i.message).join('; '));
    }

    const result = await dispatchSlack(parsed.data);
    if (!result.success) {
      throw new BadRequestError(`Slack delivery failed: ${result.error}`);
    }

    return { success: true, messageId: result.messageId };
  });

  // List delivery logs
  app.get('/delivery/logs', async req => {
    await extractAuth(req);
    const query = req.query as Record<string, string>;
    return repo.listDeliveryLogs(DEFAULT_PRODUCT_ID, {
      channel: query.channel,
      status: query.status,
      limit: query.limit ? parseInt(query.limit, 10) : undefined,
    });
  });

  // Retry a failed delivery
  app.post('/delivery/logs/:id/retry', async req => {
    await extractAuth(req);
    const { id } = req.params as { id: string };
    const query = req.query as Record<string, string>;
    const pk = query.pk || '';

    // Look up the original log entry
    const original = await repo.getDeliveryLog(id, pk);
    if (!original) throw new NotFoundError(`Delivery log '${id}' not found`);
    if (original.status !== 'failed') {
      throw new BadRequestError(
        `Can only retry failed deliveries (current status: ${original.status})`
      );
    }

    // Re-dispatch based on channel
    if (original.channel === 'email' && original.templateId) {
      const result = await dispatchEmail(
        {
          to: original.to,
          templateId: original.templateId,
          variables: (original.metadata as Record<string, string>) ?? {},
          productId: original.productId,
          userId: original.userId,
        },
        req.log
      );
      return { success: result.success, messageId: result.messageId, error: result.error };
    }

    if (original.channel === 'telegram') {
      const result = await dispatchTelegram({
        text: (original.metadata as Record<string, string>)?.text ?? original.subject ?? '',
        productId: original.productId,
        chatId: original.to,
        userId: original.userId,
      });
      return { success: result.success, messageId: result.messageId, error: result.error };
    }

    if (original.channel === 'slack') {
      const result = await dispatchSlack({
        text: (original.metadata as Record<string, string>)?.text ?? original.subject ?? '',
        productId: original.productId,
        channel: original.to,
        userId: original.userId,
      });
      return { success: result.success, messageId: result.messageId, error: result.error };
    }

    throw new BadRequestError(`Retry not supported for channel '${original.channel}'`);
  });

  // Get delivery stats
  app.get('/delivery/stats', async req => {
    await extractAuth(req);
    return repo.getDeliveryStats(DEFAULT_PRODUCT_ID);
  });
}
