import { Router } from 'express';
import prisma from '../database.js';
import PDFDocument from 'pdfkit';
import { join } from 'path';
import { generateTodaysSummary } from '../services/mantisSummarizer.js';
import { FieldType } from '@prisma/client';

const router = Router();

const __dirname = new URL('.', import.meta.url).pathname.replace(/\/$/, '');

// Helper function for consistent error handling
const handlePrismaError = (res, err, context) => 
{
  console.error(`Error ${context}:`, err.message);
  // Basic error handling, can be expanded (e.g., check for Prisma-specific error codes)
  if (err.code === 'P2025') 
  { // Prisma code for record not found
    return res.status(404).json({ error: `${context}: Record not found` });
  }
  res.status(500).json({ error: `Failed to ${context}: ${err.message}` });
};

// --- Forms API --- //

// GET /api/forms - List all forms
router.get('/forms', async(req, res) => 
{
  try 
  {
    const forms = await prisma.form.findMany({
      orderBy: {
        createdAt: 'desc',
      },
      select: { // Select only necessary fields
        id: true,
        title: true,
        description: true,
        createdAt: true,
      }
    });
    res.json(forms);
  }
  catch (err) 
  {
    handlePrismaError(res, err, 'fetch forms');
  }
});

// POST /api/forms - Create a new form
router.post('/forms', async(req, res) => 
{
  const { title, description, categories } = req.body;

  if (!title) 
  {
    return res.status(400).json({ error: 'Form title is required' });
  }

  try 
  {
    const newForm = await prisma.form.create({
      data: {
        title,
        description,
        categories: {
          create: categories?.map((category, catIndex) => ({
            name: category.name,
            sortOrder: catIndex,
            fields: {
              create: category.fields?.map((field, fieldIndex) => 
              {
                // Validate field type against Prisma Enum
                if (!Object.values(FieldType).includes(field.type)) 
                {
                  throw new Error(`Invalid field type: ${field.type}`);
                }
                if (!field.label) 
                {
                  throw new Error('Field label is required');
                }
                return {
                  label: field.label,
                  type: field.type,
                  description: field.description || null,
                  sortOrder: fieldIndex,
                };
              }) || [],
            },
          })) || [],
        },
      },
      select: { // Return basic form info
        id: true,
        title: true,
        description: true,
      }
    });
    res.status(201).json(newForm);
  }
  catch (err) 
  {
    handlePrismaError(res, err, 'create form');
  }
});

// GET /api/forms/:id - Get a specific form with its structure
router.get('/forms/:id', async(req, res) => 
{
  const { id } = req.params;
  const formId = parseInt(id, 10);

  if (isNaN(formId)) 
  {
    return res.status(400).json({ error: 'Invalid form ID' });
  }

  try 
  {
    const form = await prisma.form.findUnique({
      where: { id: formId },
      include: {
        categories: {
          orderBy: { sortOrder: 'asc' },
          include: {
            fields: {
              orderBy: { sortOrder: 'asc' },
            },
          },
        },
      },
    });

    if (!form) 
    {
      return res.status(404).json({ error: 'Form not found' });
    }
    res.json(form);
  }
  catch (err) 
  {
    handlePrismaError(res, err, `fetch form ${formId}`);
  }
});

// DELETE /api/forms/:id - Delete a specific form and all related data
router.delete('/forms/:id', async(req, res) => 
{
  const { id } = req.params;
  const formId = parseInt(id, 10);

  if (isNaN(formId)) 
  {
    return res.status(400).json({ error: 'Invalid form ID' });
  }

  try 
  {
    // Prisma automatically handles cascading deletes based on schema relations (onDelete: Cascade)
    const deletedForm = await prisma.form.delete({
      where: { id: formId },
    });
    res.status(200).json({ message: `Form ${formId} and all related data deleted successfully.` });
  }
  catch (err) 
  {
    handlePrismaError(res, err, `delete form ${formId}`);
  }
});

// PUT /api/forms/:id - Update an existing form
router.put('/forms/:id', async(req, res) => 
{
  const { id } = req.params;
  const formId = parseInt(id, 10);
  const { title, description, categories } = req.body;

  if (isNaN(formId)) 
  {
    return res.status(400).json({ error: 'Invalid form ID' });
  }
  if (!title) 
  {
    return res.status(400).json({ error: 'Form title is required' });
  }

  try 
  {
    // Use a transaction to ensure atomicity: delete old structure, update form, create new structure
    const result = await prisma.$transaction(async(tx) => 
    {
      // 1. Check if form exists (optional, delete/update will fail if not found anyway)
      const existingForm = await tx.form.findUnique({ where: { id: formId } });
      if (!existingForm) 
      {
        throw { code: 'P2025' }; // Simulate Prisma not found error
      }

      // 2. Delete existing categories (fields and response values cascade)
      await tx.category.deleteMany({ where: { formId: formId } });

      // 3. Update form details and recreate categories/fields in one go
      const updatedForm = await tx.form.update({
        where: { id: formId },
        data: {
          title,
          description,
          categories: {
            create: categories?.map((category, catIndex) => ({
              name: category.name,
              sortOrder: catIndex,
              fields: {
                create: category.fields?.map((field, fieldIndex) => 
                {
                  if (!Object.values(FieldType).includes(field.type)) 
                  {
                    throw new Error(`Invalid field type: ${field.type}`);
                  }
                  if (!field.label) 
                  {
                    throw new Error('Field label is required');
                  }
                  return {
                    label: field.label,
                    type: field.type,
                    description: field.description || null,
                    sortOrder: fieldIndex,
                  };
                }) || [],
              },
            })) || [],
          },
        },
        select: { // Return basic form info
          id: true,
          title: true,
          description: true,
        }
      });
      return updatedForm;
    });

    res.status(200).json(result);
  }
  catch (err) 
  {
    handlePrismaError(res, err, `update form ${formId}`);
  }
});


// --- Responses API --- //

// POST /api/forms/:id/responses - Submit a response for a form
router.post('/forms/:id/responses', async(req, res) => 
{
  const { id } = req.params;
  const formId = parseInt(id, 10);
  const { values } = req.body; // values is expected to be { fieldId: value, ... }

  if (isNaN(formId)) 
  {
    return res.status(400).json({ error: 'Invalid form ID' });
  }
  if (!values || typeof values !== 'object' || Object.keys(values).length === 0) 
  {
    return res.status(400).json({ error: 'Response values are required' });
  }

  try 
  {
    // Use transaction to ensure response and values are created together
    const result = await prisma.$transaction(async(tx) => 
    {
      // 1. Verify form exists
      const form = await tx.form.findUnique({ where: { id: formId }, select: { id: true } });
      if (!form) 
      {
        throw { code: 'P2025' }; // Simulate Prisma not found error
      }

      // 2. Create the response record
      const newResponse = await tx.response.create({
        data: {
          formId: formId,
        },
        select: { id: true }
      });

      // 3. Prepare response values data
      const responseValuesData = [];
      const fieldIds = Object.keys(values).map(k => parseInt(k, 10));

      // Optional: Verify all field IDs belong to the form (more robust)
      const validFields = await tx.field.findMany({
        where: {
          id: { 'in': fieldIds },
          category: { formId: formId }
        },
        select: { id: true }
      });
      const validFieldIds = new Set(validFields.map(f => f.id));

      for (const fieldIdStr in values) 
      {
        const fieldId = parseInt(fieldIdStr, 10);
        if (validFieldIds.has(fieldId)) 
        {
          const value = values[fieldIdStr];
          responseValuesData.push({
            responseId: newResponse.id,
            fieldId: fieldId,
            value: (value === null || typeof value === 'undefined') ? null : String(value),
          });
        }
        else 
        {
          console.warn(`Attempted to submit value for field ${fieldId} not belonging to form ${formId}`);
          // Decide whether to throw an error or just skip invalid fields
          // throw new Error(`Field ${fieldId} does not belong to form ${formId}`);
        }
      }

      // 4. Create all response values
      if (responseValuesData.length > 0) 
      {
        await tx.responseValue.createMany({
          data: responseValuesData,
        });
      }

      return { responseId: newResponse.id };
    });

    res.status(201).json(result);
  }
  catch (err) 
  {
    handlePrismaError(res, err, `submit response for form ${formId}`);
  }
});

// GET /api/forms/:id/responses - Get all responses for a form
router.get('/forms/:id/responses', async(req, res) => 
{
  const { id } = req.params;
  const formId = parseInt(id, 10);

  if (isNaN(formId)) 
  {
    return res.status(400).json({ error: 'Invalid form ID' });
  }

  try 
  {
    // 1. Check if form exists
    const formExists = await prisma.form.findUnique({ where: { id: formId }, select: { id: true } });
    if (!formExists) 
    {
      return res.status(404).json({ error: 'Form not found' });
    }

    // 2. Fetch responses with their values and related field info
    const responses = await prisma.response.findMany({
      where: { formId: formId },
      orderBy: { submittedAt: 'desc' },
      include: {
        responseValues: {
          include: {
            field: {
              select: { label: true, type: true, category: { select: { sortOrder: true } }, sortOrder: true } // Include sort orders
            }
          }
        }
      }
    });

    // 3. Group data similar to the old structure for frontend compatibility
    const groupedResponses = responses.map(response => ({
      id: response.id,
      submittedAt: response.submittedAt,
      values: response.responseValues
        .sort((a, b) => 
        {
          // Sort by category order, then field order
          const catSort = a.field.category.sortOrder - b.field.category.sortOrder;
          if (catSort !== 0) return catSort;
          return a.field.sortOrder - b.field.sortOrder;
        })
        .reduce((acc, rv) => 
        {
          acc[rv.fieldId] = {
            label: rv.field.label,
            type: rv.field.type,
            value: rv.value
          };
          return acc;
        }, {})
    }));

    res.json(groupedResponses);
  }
  catch (err) 
  {
    handlePrismaError(res, err, `fetch responses for form ${formId}`);
  }
});


// GET /responses/:responseId/export/pdf - Export response as PDF
router.get('/responses/:responseId/export/pdf', async(req, res) => 
{
  const { responseId: responseIdStr } = req.params;
  const responseId = parseInt(responseIdStr, 10);

  if (isNaN(responseId)) 
  {
    return res.status(400).json({ error: 'Invalid response ID' });
  }

  try 
  {
    // 1. Fetch the response, form title, form structure, and values in one go
    const responseData = await prisma.response.findUnique({
      where: { id: responseId },
      include: {
        form: {
          select: {
            title: true,
            categories: {
              orderBy: { sortOrder: 'asc' },
              include: {
                fields: {
                  orderBy: { sortOrder: 'asc' },
                  select: { id: true, label: true, type: true, description: true }
                }
              }
            }
          }
        },
        responseValues: {
          select: { fieldId: true, value: true }
        }
      }
    });

    if (!responseData) 
    {
      return res.status(404).json({ error: 'Response not found' });
    }

    const formTitle = responseData.form.title;
    const categories = responseData.form.categories;
    const responseValues = responseData.responseValues.reduce((acc, rv) => 
    {
      acc[rv.fieldId] = (rv.value === null || typeof rv.value === 'undefined') ? '' : String(rv.value);
      return acc;
    }, {});

    // 4. Generate PDF using pdfkit (logic remains largely the same)
    const doc = new PDFDocument({ margin: 50, size: 'A4' });
    const fontsDir = join(__dirname, '../../public/fonts');

    doc.registerFont('Roboto-Bold', join(fontsDir, 'Roboto-Bold.ttf'));
    doc.registerFont('Roboto-SemiBold', join(fontsDir, 'Roboto-SemiBold.ttf'));
    doc.registerFont('Roboto-Italics', join(fontsDir, 'Roboto-Italic.ttf'));
    doc.registerFont('Roboto-Regular', join(fontsDir, 'Roboto-Regular.ttf'));

    res.setHeader('Content-Type', 'application/pdf');
    res.setHeader('Content-Disposition', `inline; filename=response_${responseId}_${formTitle.replace(/[\s\\/]/g, '_') || 'form'}.pdf`);

    doc.pipe(res);

    // --- PDF Content (remains the same as before) ---
    doc.fontSize(18).font('Roboto-Bold').text(formTitle, { align: 'center' });
    doc.moveDown();

    for (const category of categories) 
    {
      if (category.name) 
      {
        doc.fontSize(14).font('Roboto-Bold').text(category.name);
        doc.moveDown(0.5);
      }

      for (const field of category.fields) 
      {
        const value = responseValues[field.id] || '';
        doc.fontSize(12).font('Roboto-SemiBold').text(field.label + ':', { continued: false });
        if (field.description) 
        {
          doc.fontSize(9).font('Roboto-Italics').text(field.description);
        }
        doc.moveDown(0.2);
        doc.fontSize(11).font('Roboto-Regular');
        if (field.type === 'textarea') 
        {
          const textHeight = doc.heightOfString(value, { width: 500 });
          doc.rect(doc.x, doc.y, 500, Math.max(textHeight + 10, 30)).stroke();
          doc.text(value, doc.x + 5, doc.y + 5, { width: 490 });
          doc.y += Math.max(textHeight + 10, 30) + 10;
        }
        else if (field.type === 'date') 
        {
          let formattedDate = '';
          if (value) 
          {
            try 
            {
              const dateObj = new Date(value + 'T00:00:00');
              if (!isNaN(dateObj.getTime())) 
              {
                const day = String(dateObj.getDate()).padStart(2, '0');
                const month = String(dateObj.getMonth() + 1).padStart(2, '0');
                const year = dateObj.getFullYear();
                formattedDate = `${day}/${month}/${year}`;
              }
              else 
              {
                formattedDate = value;
              }
            }
            catch (e) 
            {
              console.error('Error formatting date:', value, e);
              formattedDate = value;
            }
          }
          doc.text(formattedDate || ' ');
          doc.lineCap('butt').moveTo(doc.x, doc.y).lineTo(doc.x + 500, doc.y).stroke();
          doc.moveDown(1.5);
        }
        else if (field.type === 'boolean') 
        {
          const displayValue = value === 'true' ? 'Yes' : (value === 'false' ? 'No' : ' ');
          doc.text(displayValue);
          doc.lineCap('butt').moveTo(doc.x, doc.y).lineTo(doc.x + 500, doc.y).stroke();
          doc.moveDown(1.5);
        }
        else 
        {
          doc.text(value || ' ');
          doc.lineCap('butt').moveTo(doc.x, doc.y).lineTo(doc.x + 500, doc.y).stroke();
          doc.moveDown(1.5);
        }
      }
      doc.moveDown(1);
    }
    doc.end();

  }
  catch (err) 
  {
    console.error(`Error generating PDF for response ${responseId}:`, err.message);
    if (!res.headersSent) 
    {
      // Use the helper function
      handlePrismaError(res, err, `generate PDF for response ${responseId}`);
    }
    else 
    {
      console.error('Headers already sent, could not send JSON error for PDF generation failure.');
      res.end();
    }
  }
});


// --- Mantis Summary API Route --- //

// GET /api/mantis-summary/today - Get today's summary specifically
router.get('/mantis-summary/today', async(req, res) => 
{
  try 
  {
    const today = new Date();
    today.setHours(0, 0, 0, 0); // Set to start of day UTC for comparison

    const todaySummary = await prisma.mantisSummary.findUnique({
      where: { summaryDate: today },
      select: { summaryDate: true, summaryText: true, generatedAt: true }
    });

    if (todaySummary) 
    {
      res.json(todaySummary);
    }
    else 
    {
      res.status(404).json({ message: `No Mantis summary found for today (${today.toISOString().split('T')[0]}).` });
    }
  }
  catch (error) 
  {
    handlePrismaError(res, error, 'fetch today\'s Mantis summary');
  }
});

// GET /api/mantis-summaries - Get ALL summaries from the DB, with pagination
router.get('/mantis-summaries', async(req, res) => 
{
  const page = parseInt(req.query.page, 10) || 1;
  const limit = parseInt(req.query.limit, 10) || 10;
  const skip = (page - 1) * limit;

  try 
  {
    const [summaries, totalItems] = await prisma.$transaction([
      prisma.mantisSummary.findMany({
        orderBy: { summaryDate: 'desc' },
        take: limit,
        skip: skip,
        select: { id: true, summaryDate: true, summaryText: true, generatedAt: true }
      }),
      prisma.mantisSummary.count()
    ]);

    res.json({ summaries, total: totalItems });
  }
  catch (error) 
  {
    handlePrismaError(res, error, 'fetch paginated Mantis summaries');
  }
});

// POST /api/mantis-summaries/generate - Trigger summary generation
router.post('/mantis-summaries/generate', async(req, res) => 
{
  try 
  {
    // Trigger generation asynchronously, don't wait for it
    generateTodaysSummary()
      .then(() => 
      {
        console.log('Summary generation process finished successfully (async).');
      })
      .catch(error => 
      {
        console.error('Background summary generation failed:', error);
      });

    res.status(202).json({ message: 'Summary generation started.' });
  }
  catch (error) 
  {
    handlePrismaError(res, error, 'initiate Mantis summary generation');
  }
});

// --- Settings API --- //

// GET /api/settings/:key - Get a specific setting value
router.get('/settings/:key', async(req, res) => 
{
  const { key } = req.params;
  try 
  {
    const setting = await prisma.setting.findUnique({
      where: { key: key },
      select: { value: true }
    });

    if (setting !== null) 
    {
      res.json({ key, value: setting.value });
    }
    else 
    {
      res.json({ key, value: '' }); // Return empty value if not found
    }
  }
  catch (err) 
  {
    handlePrismaError(res, err, `fetch setting '${key}'`);
  }
});

// PUT /api/settings/:key - Update or create a specific setting
router.put('/settings/:key', async(req, res) => 
{
  const { key } = req.params;
  const { value } = req.body;

  if (typeof value === 'undefined') 
  {
    return res.status(400).json({ error: 'Setting value is required in the request body' });
  }

  try 
  {
    const upsertedSetting = await prisma.setting.upsert({
      where: { key: key },
      update: { value: String(value) },
      create: { key: key, value: String(value) },
      select: { key: true, value: true } // Select to return the updated/created value
    });
    res.status(200).json(upsertedSetting);
  }
  catch (err) 
  {
    handlePrismaError(res, err, `update setting '${key}'`);
  }
});

export default router;