const router = require('express').Router();
const { body, query } = require('express-validator');
const prisma = require('../lib/prisma');
const cache = require('../lib/cache');
const auditMiddleware = require('../middleware/auditMiddleware');
const { validateRequest } = require('../middleware/errorHandler');

// Look up which experiment a daily status belongs to, then clear all cached data for it.
async function invalidateByStatusId(statusId) {
  const rec = await prisma.dailyStatus.findUnique({
    where: { id: statusId },
    select: { animal: { select: { experiment_id: true } } },
  });
  const expId = rec?.animal?.experiment_id;
  if (expId) cache.delByPrefix(`exp:${expId}:`);
}

const statusValidation = [
  body('animal_id').notEmpty().withMessage('animal_id is required').matches(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i).withMessage('animal_id must be a valid UUID'),
  body('date').notEmpty().withMessage('date is required').isISO8601().withMessage('date must be a valid ISO 8601 date (YYYY-MM-DD)'),
  body('experiment_description').optional({ nullable: true }).isString(),
  body('vitals').optional({ nullable: true }).isString(),
  body('treatment').optional({ nullable: true }).isString(),
  body('notes').optional({ nullable: true }).isString(),
  body('custom_fields').optional({ nullable: true }).isObject().withMessage('custom_fields must be an object'),
];

const statusUpdateValidation = [
  body('date').optional().isISO8601().withMessage('date must be a valid ISO 8601 date'),
  body('experiment_description').optional({ nullable: true }).isString(),
  body('vitals').optional({ nullable: true }).isString(),
  body('treatment').optional({ nullable: true }).isString(),
  body('notes').optional({ nullable: true }).isString(),
  body('custom_fields').optional({ nullable: true }).isObject().withMessage('custom_fields must be an object'),
];

// GET /api/daily-statuses?animalId=<uuid>
router.get(
  '/',
  [query('animalId').optional().matches(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i).withMessage('animalId must be a valid UUID')],
  validateRequest,
  async (req, res, next) => {
    try {
      const where = req.query.animalId ? { animal_id: req.query.animalId } : {};
      const statuses = await prisma.dailyStatus.findMany({
        where,
        orderBy: { date: 'desc' },
        include: { animal: { select: { animal_name: true, animal_id_string: true } } },
      });
      res.json(statuses);
    } catch (err) { next(err); }
  }
);

// GET /api/daily-statuses/:id
router.get('/:id', async (req, res, next) => {
  try {
    const status = await prisma.dailyStatus.findUnique({
      where: { id: req.params.id },
      include: { animal: true },
    });
    if (!status) return res.status(404).json({ error: 'Daily status not found' });
    res.json(status);
  } catch (err) { next(err); }
});

// POST /api/daily-statuses
router.post('/', statusValidation, validateRequest, async (req, res, next) => {
  try {
    const { animal_id, date, experiment_description, vitals, treatment, notes, custom_fields } = req.body;
    const status = await prisma.dailyStatus.create({
      data: {
        animal_id,
        date: new Date(date),
        experiment_description,
        vitals,
        treatment,
        notes,
        custom_fields: custom_fields ?? {},
      },
    });
    await prisma.auditLog.create({
      data: { table_name: 'daily_statuses', record_id: status.id, action: 'CREATE', changes: { before: null, after: status } },
    });
    // Invalidate cached experiment data — new status may change calendar counts and chart data
    const animal = await prisma.animal.findUnique({ where: { id: animal_id }, select: { experiment_id: true } });
    if (animal) cache.delByPrefix(`exp:${animal.experiment_id}:`);
    res.status(201).json(status);
  } catch (err) { next(err); }
});

// PUT /api/daily-statuses/:id
router.put(
  '/:id',
  auditMiddleware('daily_statuses', prisma.dailyStatus),
  statusUpdateValidation,
  validateRequest,
  async (req, res, next) => {
    try {
      const { date, experiment_description, vitals, treatment, notes, custom_fields } = req.body;
      const data = {};
      if (date !== undefined)                   data.date = new Date(date);
      if (experiment_description !== undefined)  data.experiment_description = experiment_description;
      if (vitals !== undefined)                  data.vitals = vitals;
      if (treatment !== undefined)               data.treatment = treatment;
      if (notes !== undefined)                   data.notes = notes;
      if (custom_fields !== undefined)           data.custom_fields = custom_fields;

      const status = await prisma.dailyStatus.update({ where: { id: req.params.id }, data });
      await invalidateByStatusId(req.params.id);
      res.json(status);
    } catch (err) { next(err); }
  }
);

// PUT /api/daily-statuses/:id/analysis-summary
router.put('/:id/analysis-summary', async (req, res, next) => {
  try {
    const status = await prisma.dailyStatus.findUnique({
      where: { id: req.params.id },
      include: { animal: { select: { experiment_id: true } } },
    });
    if (!status) return res.status(404).json({ error: 'Daily status not found' });

    const { counts, total, success_rate, source_analysis_id } = req.body;
    if (!counts || total == null) {
      return res.status(422).json({ error: 'counts and total are required' });
    }

    const summary = {
      counts,
      total,
      success_rate: success_rate ?? null,
      source_analysis_id: source_analysis_id ?? null,
      computed_at: new Date().toISOString(),
    };

    const updated = await prisma.dailyStatus.update({
      where: { id: req.params.id },
      data: { analysis_summary: summary },
    });
    if (status.animal?.experiment_id) cache.delByPrefix(`exp:${status.animal.experiment_id}:`);
    res.json(updated);
  } catch (err) { next(err); }
});

// DELETE /api/daily-statuses/:id
router.delete(
  '/:id',
  auditMiddleware('daily_statuses', prisma.dailyStatus),
  async (req, res, next) => {
    try {
      // Resolve experiment before deleting so we can invalidate after
      const rec = await prisma.dailyStatus.findUnique({
        where: { id: req.params.id },
        select: { animal: { select: { experiment_id: true } } },
      });
      await prisma.dailyStatus.delete({ where: { id: req.params.id } });
      if (rec?.animal?.experiment_id) cache.delByPrefix(`exp:${rec.animal.experiment_id}:`);
      res.status(204).send();
    } catch (err) { next(err); }
  }
);

module.exports = router;
