import type { FastifyInstance } from 'fastify';
import { mergeChannelSettings, type ChannelSettings, isWebChatSystemChannel } from '@wa-ticketing/shared';
import { authenticate, requireRole } from '../middleware/auth.js';
import { channelService } from '../services/channelService.js';
import { auditService } from '../services/auditService.js';

const staff = [authenticate, requireRole('admin', 'user')];

export async function channelRoutes(fastify: FastifyInstance) {
  fastify.get('/', { preHandler: staff }, async (_req, reply) => {
    return reply.send(await channelService.list());
  });

  // POST /api/v1/channels/init  (Admin only — must register before /:id)
  fastify.post('/init', { preHandler: [authenticate, requireRole('admin')] }, async (req, reply) => {
    const { name, phone_number } = req.body as { name: string; phone_number: string };
    if (!name || !phone_number) {
      return reply.status(400).send({ error: 'name and phone_number are required' });
    }

    const channel = await channelService.create(name, phone_number);
    await auditService.log(req.user!.sub, 'user', 'channel.init_started', 'channel', channel.id, { name });

    // Start Baileys session — QR will be emitted via WebSocket
    channelService.startSession(channel.id, fastify.io).catch(err => {
      fastify.log.error({ err }, `Failed to start session for channel ${channel.id}`);
    });

    return reply.status(201).send(channel);
  });

  // POST /api/v1/channels/email — inbound-via-webhook email channel (SMTP replies; no POP/IMAP worker)
  fastify.post('/email', { preHandler: [authenticate, requireRole('admin')] }, async (req, reply) => {
    const { name } = req.body as { name?: string };
    if (!name?.trim()) return reply.status(400).send({ error: 'name is required' });
    const channel = await channelService.createEmailChannel(name.trim());
    await auditService.log(req.user!.sub, 'user', 'channel.email_created', 'channel', channel.id, { name: name.trim() });
    return reply.status(201).send(channel);
  });

  // POST /api/v1/channels/:id/reconnect  (Admin — relink disconnected channel; starts worker session + QR via Socket.IO)
  fastify.post('/:id/reconnect', { preHandler: [authenticate, requireRole('admin')] }, async (req, reply) => {
    const { id } = req.params as { id: string };
    const ch = await channelService.getById(id);
    if (!ch) return reply.status(404).send({ error: 'Channel not found' });
    if (isWebChatSystemChannel(ch.phone_number) || ch.kind === 'email') {
      return reply.status(400).send({ error: 'This channel does not use WhatsApp — no reconnect needed.' });
    }

    await channelService.clearWorkerSession(id);
    await channelService.setStatus(id, 'connecting');
    await auditService.log(req.user!.sub, 'user', 'channel.reconnect_started', 'channel', id, {});

    try {
      await channelService.startSession(id, fastify.io);
    } catch (err) {
      fastify.log.error({ err }, `Reconnect: worker failed for channel ${id}`);
      await channelService.setStatus(id, 'disconnected');
      return reply.status(503).send({
        error: 'WhatsApp worker unavailable. Ensure the worker service is running (e.g. docker compose up whatsapp).',
      });
    }

    const updated = await channelService.getById(id);
    return reply.send(updated ?? ch);
  });

  // GET /api/v1/channels/:id
  fastify.get('/:id', { preHandler: staff }, async (req, reply) => {
    const { id } = req.params as { id: string };
    const ch = await channelService.getById(id);
    if (!ch) return reply.status(404).send({ error: 'Channel not found' });
    return reply.send(ch);
  });

  // PATCH /api/v1/channels/:id  (Admin — name + settings)
  fastify.patch('/:id', { preHandler: [authenticate, requireRole('admin')] }, async (req, reply) => {
    const { id } = req.params as { id: string };
    const body = req.body as { name?: string; settings?: ChannelSettings };
    const updated = await channelService.update(
      id,
      {
        name: body.name,
        settings: body.settings !== undefined ? mergeChannelSettings(body.settings) : undefined,
      },
      req.user!.sub,
    );
    if (!updated) return reply.status(404).send({ error: 'Channel not found' });
    return reply.send(updated);
  });

  // DELETE /api/v1/channels/:id  (Admin only)
  fastify.delete('/:id', { preHandler: [authenticate, requireRole('admin')] }, async (req, reply) => {
    const { id } = req.params as { id: string };
    await channelService.remove(id, req.user!.sub);
    fastify.io.emit('channel:disconnected', { channelId: id, reason: 'Channel removed' });
    return reply.status(204).send();
  });
}
