import { Router } from 'express';
import {
  sequelize,
  Booking,
  JobCard,
  JobTask,
  Service,
  User,
  Vehicle,
} from '../models/index.js';
import { requireAuth, requireRole } from '../middleware/auth.js';
import { sendError } from '../util/httpError.js';

const router = Router();

function toJobCard(row) {
  return {
    id: Number(row.id),
    booking_id: Number(row.booking_id),
    status: row.status,
    estimated_cost: row.estimated_cost,
    final_cost: row.final_cost,
    created_at: row.created_at,
    booking_user_id: row.booking?.user_id ?? null,
    booking_status: row.booking?.status ?? null,
    scheduled_date: row.booking?.scheduled_date ?? null,
    vehicle_brand: row.booking?.vehicle?.brand ?? null,
    vehicle_model: row.booking?.vehicle?.model ?? null,
    number_plate: row.booking?.vehicle?.number_plate ?? null,
  };
}

function toTask(row) {
  return {
    ...row.toJSON(),
    service_name: row.service?.name ?? null,
    employee_name: row.employee?.name ?? null,
  };
}

router.post('/', requireAuth, requireRole('admin', 'super_admin'), async (req, res) => {
  const { booking_id, estimated_cost, service_ids } = req.body || {};
  if (!booking_id || !Array.isArray(service_ids) || service_ids.length === 0) {
    return sendError(
      res,
      400,
      'VALIDATION_ERROR',
      'booking_id and non-empty service_ids[] required'
    );
  }
  const tx = await sequelize.transaction();
  try {
    const existing = await JobCard.findOne({
      where: { booking_id: Number(booking_id) },
      transaction: tx,
    });
    if (existing) {
      await tx.rollback();
      return sendError(res, 400, 'VALIDATION_ERROR', 'Job card already exists for booking');
    }
    const created = await JobCard.create(
      {
        booking_id: Number(booking_id),
        status: 'open',
        estimated_cost: estimated_cost != null ? Number(estimated_cost) : null,
      },
      { transaction: tx }
    );
    const jobCardId = Number(created.id);
    for (const sid of service_ids) {
      await JobTask.create(
        {
          job_card_id: jobCardId,
          service_id: Number(sid),
          employee_id: null,
          status: 'pending',
        },
        { transaction: tx }
      );
    }
    await Booking.update(
      { status: 'in_progress' },
      { where: { id: Number(booking_id) }, transaction: tx }
    );
    await tx.commit();
    const card = await JobCard.findByPk(jobCardId, {
      include: [
        {
          model: Booking,
          as: 'booking',
          include: [{ model: Vehicle, as: 'vehicle', attributes: ['brand', 'model', 'number_plate'] }],
        },
      ],
    });
    const tasks = await JobTask.findAll({
      where: { job_card_id: jobCardId },
      include: [{ model: Service, as: 'service', attributes: ['name'] }],
      order: [['id', 'ASC']],
    });
    return res.status(201).json({ job_card: toJobCard(card), tasks: tasks.map(toTask) });
  } catch (e) {
    await tx.rollback();
    throw e;
  }
});

router.get('/', requireAuth, requireRole('admin', 'super_admin'), async (_req, res) => {
  const rows = await JobCard.findAll({
    include: [
      {
        model: Booking,
        as: 'booking',
        include: [{ model: Vehicle, as: 'vehicle', attributes: ['brand', 'model', 'number_plate'] }],
      },
    ],
    order: [['id', 'DESC']],
  });
  return res.json({ job_cards: rows.map(toJobCard) });
});

router.get('/:id', requireAuth, async (req, res) => {
  const id = Number(req.params.id);
  const jc = await JobCard.findByPk(id, {
    include: [
      {
        model: Booking,
        as: 'booking',
        include: [{ model: Vehicle, as: 'vehicle', attributes: ['brand', 'model', 'number_plate'] }],
      },
    ],
  });
  if (!jc) {
    return sendError(res, 404, 'NOT_FOUND', 'Job card not found');
  }
  const bookingUserId = Number(jc.booking?.user_id || 0);
  if (req.user.role === 'admin') {
    const tasks = await JobTask.findAll({
      where: { job_card_id: id },
      include: [
        { model: Service, as: 'service', attributes: ['name'] },
        { model: User, as: 'employee', attributes: ['name'], required: false },
      ],
    });
    return res.json({ job_card: toJobCard(jc), tasks: tasks.map(toTask) });
  }
  if (req.user.role === 'customer' && bookingUserId === req.user.id) {
    const tasks = await JobTask.findAll({
      where: { job_card_id: id },
      include: [
        { model: Service, as: 'service', attributes: ['name'] },
        { model: User, as: 'employee', attributes: ['name'], required: false },
      ],
    });
    return res.json({ job_card: toJobCard(jc), tasks: tasks.map(toTask) });
  }
  if (req.user.role === 'employee') {
    const tasks = await JobTask.findAll({
      where: { job_card_id: id, employee_id: req.user.id },
      include: [{ model: Service, as: 'service', attributes: ['name'] }],
    });
    if (tasks.length === 0) {
      return sendError(res, 403, 'FORBIDDEN', 'No tasks assigned to you on this card');
    }
    return res.json({ job_card: toJobCard(jc), tasks: tasks.map(toTask) });
  }
  return sendError(res, 403, 'FORBIDDEN', 'Cannot view this job card');
});

router.patch('/:id', requireAuth, requireRole('admin', 'super_admin'), async (req, res) => {
  const id = Number(req.params.id);
  const { status, final_cost } = req.body || {};
  const allowed = ['open', 'in_progress', 'completed', 'closed'];
  if (status && !allowed.includes(status)) {
    return sendError(res, 400, 'VALIDATION_ERROR', 'Invalid job card status');
  }
  const card = await JobCard.findByPk(id);
  if (!card) {
    return sendError(res, 404, 'NOT_FOUND', 'Job card not found');
  }
  if (status) card.status = status;
  if (final_cost != null) card.final_cost = Number(final_cost);
  await card.save();
  const out = await JobCard.findByPk(id, {
    include: [
      {
        model: Booking,
        as: 'booking',
        include: [{ model: Vehicle, as: 'vehicle', attributes: ['brand', 'model', 'number_plate'] }],
      },
    ],
  });
  return res.json({ job_card: toJobCard(out) });
});

export default router;
