import { Router } from 'express';
import { authenticate } from '../../middleware/auth';
import { requireRoles } from '../../middleware/rbac';
import { Role, ErrorCode, TicketStatus, TICKET_STATUS_TRANSITIONS } from '@saferoute/constants';
import { prisma } from '../../config/database';
import { sendSuccess, sendError, sendPaginated } from '../../utils/response';

export const ticketRoutes = Router();

ticketRoutes.get('/', authenticate, async (req, res) => {
  try {
    const page = parseInt(req.query.page as string) || 1;
    const limit = parseInt(req.query.limit as string) || 20;
    const skip = (page - 1) * limit;

    const where: any = {};

    if (req.user!.roles.includes(Role.PARENT)) { where.raisedBy = req.user!.userId; }
    if (req.query.status) { where.status = req.query.status; }
    if (req.query.category) { where.category = req.query.category; }

    const [tickets, total] = await Promise.all([
      prisma.ticket.findMany({
        where, skip, take: limit, orderBy: { createdAt: 'desc' },
        include: {
          raiser: { select: { fullName: true } },
          assignee: { select: { fullName: true } },
          school: { select: { id: true, name: true } },
        },
      }),
      prisma.ticket.count({ where }),
    ]);
    sendPaginated(res, tickets, total, page, limit);
  } catch (error) {
    sendError(res, ErrorCode.SERVER_ERROR, 'Failed to list tickets.');
  }
});

ticketRoutes.post('/', authenticate, async (req, res) => {
  try {
    const { category, priority, subject, message, schoolId } = req.body;
    const ticket = await prisma.ticket.create({
      data: { schoolId, raisedBy: req.user!.userId, category, priority: priority || 'MEDIUM', subject },
    });
    if (message) {
      await prisma.ticketMessage.create({ data: { ticketId: ticket.id, sentBy: req.user!.userId, message } });
    }
    sendSuccess(res, { id: ticket.id, status: ticket.status }, 'Ticket created', 201);
  } catch (error) {
    sendError(res, ErrorCode.SERVER_ERROR, 'Failed to create ticket.');
  }
});

ticketRoutes.get('/:ticketId', authenticate, async (req, res) => {
  try {
    const ticket = await prisma.ticket.findUnique({
      where: { id: req.params.ticketId },
      include: {
        raiser: { select: { id: true, fullName: true } },
        assignee: { select: { id: true, fullName: true } },
        messages: { include: { sender: { select: { fullName: true } } }, orderBy: { createdAt: 'asc' } },
      },
    });
    if (!ticket) { sendError(res, ErrorCode.RESOURCE_NOT_FOUND, 'Ticket not found.'); return; }
    sendSuccess(res, ticket);
  } catch (error) {
    sendError(res, ErrorCode.SERVER_ERROR, 'Failed to get ticket.');
  }
});

ticketRoutes.patch('/:ticketId/status', authenticate, requireRoles(Role.OWNER, Role.SUPPORT_EXECUTIVE, Role.SCHOOL_HELPDESK, Role.SCHOOL_PRINCIPAL), async (req, res) => {
  try {
    const { status } = req.body;
    const ticket = await prisma.ticket.findUnique({ where: { id: req.params.ticketId } });
    if (!ticket) { sendError(res, ErrorCode.RESOURCE_NOT_FOUND, 'Ticket not found.'); return; }

    if (ticket.status === 'CLOSED' && status !== 'REOPENED') {
      sendError(res, ErrorCode.TICKET_ALREADY_CLOSED, 'Ticket is closed. Must be reopened first.'); return;
    }

    const allowed = TICKET_STATUS_TRANSITIONS[ticket.status as TicketStatus] || [];
    if (!allowed.includes(status as TicketStatus)) {
      sendError(res, ErrorCode.VALIDATION_ERROR, `Cannot transition from ${ticket.status} to ${status}.`); return;
    }

    await prisma.ticket.update({ where: { id: req.params.ticketId }, data: { status } });
    sendSuccess(res, { id: req.params.ticketId, status }, 'Ticket status updated');
  } catch (error) {
    sendError(res, ErrorCode.SERVER_ERROR, 'Failed to update ticket status.');
  }
});

ticketRoutes.post('/:ticketId/messages', authenticate, async (req, res) => {
  try {
    const { message } = req.body;
    const msg = await prisma.ticketMessage.create({
      data: { ticketId: req.params.ticketId, sentBy: req.user!.userId, message },
    });
    sendSuccess(res, { id: msg.id }, 'Message added', 201);
  } catch (error) {
    sendError(res, ErrorCode.SERVER_ERROR, 'Failed to add message.');
  }
});

ticketRoutes.post('/:ticketId/escalate', authenticate, requireRoles(Role.SUPPORT_EXECUTIVE, Role.SCHOOL_HELPDESK), async (req, res) => {
  try {
    const { reason } = req.body;
    await prisma.ticket.update({ where: { id: req.params.ticketId }, data: { status: 'ESCALATED' } });
    await prisma.ticketMessage.create({
      data: { ticketId: req.params.ticketId, sentBy: req.user!.userId, message: `Escalated: ${reason}` },
    });
    sendSuccess(res, { id: req.params.ticketId, status: 'ESCALATED' }, 'Ticket escalated');
  } catch (error) {
    sendError(res, ErrorCode.SERVER_ERROR, 'Failed to escalate ticket.');
  }
});
