import type { FastifyInstance } from 'fastify';
import type { StaffTag } from '@wa-ticketing/shared';
import { authenticate, requireRole } from '../middleware/auth.js';
import { authService } from '../services/authService.js';
import { auditService } from '../services/auditService.js';
import { emitMessageNew } from '../services/messageEmitService.js';
import { enrichMessageWithMediaUrl } from '../services/ticketMediaService.js';
import { staffWorkspaceService } from '../services/staffWorkspaceService.js';

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

export async function userRoutes(fastify: FastifyInstance) {
  // Manage → Staff directory (active admin/agent users)
  fastify.get('/staff', { preHandler: staffGuard }, async (_req, reply) => {
    const users = await authService.listStaffDirectory();
    return reply.send(
      users.map(u => ({
        id: u.id,
        email: u.email,
        display_name: u.display_name,
        phone: u.phone,
        role: u.role,
        staff_tags: u.staff_tags ?? [],
        last_login_at: u.last_login_at,
      })),
    );
  });

  // Staff profile: WhatsApp chat context, tickets, calendar, audit
  fastify.get('/staff/:id', { preHandler: staffGuard }, async (req, reply) => {
    const { id } = req.params as { id: string };
    const workspace = await staffWorkspaceService.get(id);
    if (!workspace) return reply.status(404).send({ error: 'Staff member not found' });
    return reply.send(workspace);
  });

  // WhatsApp chat to this staff phone — reuses open direct ticket so replies stay in history
  fastify.post('/staff/:id/chat', { preHandler: staffGuard }, async (req, reply) => {
    const { id } = req.params as { id: string };
    const body = req.body as { channel_id?: string; content?: string };
    const channelId = body.channel_id?.trim();
    const content = body.content?.trim() ?? '';
    if (!channelId) return reply.status(400).send({ error: 'channel_id is required' });
    if (!content) return reply.status(400).send({ error: 'content is required' });
    try {
      const result = await staffWorkspaceService.sendChat(id, channelId, content, req.user!.sub);
      const enriched = await enrichMessageWithMediaUrl(result.message);
      await emitMessageNew(fastify.io, result.ticket_id, enriched);
      return reply.status(201).send({ ...result, message: enriched });
    } catch (err: unknown) {
      const e = err as { message: string; statusCode?: number };
      return reply.status(e.statusCode ?? 500).send({ error: e.message });
    }
  });

  // Staff: active staff users that have a WhatsApp phone (for group tickets)
  fastify.get('/staff-for-groups', { preHandler: staffGuard }, async (_req, reply) => {
    const users = await authService.listUsers();
    const eligible = users.filter(
      u =>
        u.is_active &&
        (u.role === 'admin' || u.role === 'user') &&
        Boolean(u.phone?.trim()) &&
        !u.phone!.startsWith('portal:') &&
        !u.phone!.toLowerCase().startsWith('email:'),
    );
    return reply.send(
      eligible.map(u => ({
        id: u.id,
        email: u.email,
        display_name: u.display_name,
        phone: u.phone,
        staff_tags: u.staff_tags ?? [],
      })),
    );
  });

  // GET /api/v1/users
  fastify.get('/', { preHandler: adminGuard }, async (_req, reply) => {
    return reply.send(await authService.listUsers());
  });

  // GET /api/v1/users/:id
  fastify.get('/:id', { preHandler: adminGuard }, async (req, reply) => {
    const { id } = req.params as { id: string };
    const user = await authService.getUser(id);
    if (!user) return reply.status(404).send({ error: 'User not found' });
    return reply.send(user);
  });

  // POST /api/v1/users
  fastify.post('/', { preHandler: adminGuard }, async (req, reply) => {
    const body = req.body as {
      email: string;
      password: string;
      role: 'admin' | 'user';
      ai_agent_id?: string | null;
      phone?: string | null;
      staff_tags?: string[];
    };
    const { email, password, role, ai_agent_id, phone, staff_tags } = body;
    if (!email || !password || !role) {
      return reply.status(400).send({ error: 'email, password and role are required' });
    }
    try {
      const user = await authService.createUser(email, password, role, ai_agent_id, {
        phone,
        staffTags: staff_tags as StaffTag[] | undefined,
      });
      await auditService.log(req.user!.sub, 'user', 'user.created', 'user', user.id, {
        email,
        role,
        phone: user.phone,
        staff_tags: user.staff_tags,
      });
      return reply.status(201).send(user);
    } catch (err: unknown) {
      const e = err as { message: string; statusCode?: number };
      return reply.status(e.statusCode ?? 409).send({ error: e.message });
    }
  });

  // PATCH /api/v1/users/:id
  fastify.patch('/:id', { preHandler: adminGuard }, async (req, reply) => {
    const { id } = req.params as { id: string };
    const patch = req.body as {
      role?: 'admin' | 'user';
      is_active?: boolean;
      ai_agent_id?: string | null;
      phone?: string | null;
      staff_tags?: string[];
    };
    try {
      const user = await authService.updateUser(id, {
        ...patch,
        staff_tags: patch.staff_tags as StaffTag[] | undefined,
      });
      if (patch.role !== undefined) {
        await auditService.log(req.user!.sub, 'user', 'user.role_changed', 'user', id, { role: patch.role });
      }
      if (patch.phone !== undefined || patch.staff_tags !== undefined) {
        await auditService.log(req.user!.sub, 'user', 'user.profile_updated', 'user', id, {
          phone: patch.phone,
          staff_tags: patch.staff_tags,
        });
      }
      return reply.send(user);
    } catch (err: unknown) {
      const e = err as { message: string; statusCode?: number };
      return reply.status(e.statusCode ?? 500).send({ error: e.message });
    }
  });

  // DELETE /api/v1/users/:id  (deactivate)
  fastify.delete('/:id', { preHandler: adminGuard }, async (req, reply) => {
    const { id } = req.params as { id: string };
    await authService.deactivateUser(id);
    await auditService.log(req.user!.sub, 'user', 'user.deactivated', 'user', id, {});
    return reply.status(204).send();
  });
}
