import { Hono } from 'hono';
import { zValidator } from '@hono/zod-validator';
import { z } from 'zod';
import { prisma } from '../utils/prisma';
import { authenticate } from '../middleware/auth';
import { generateReport } from '../services/report-generator';
import type { ReportPeriod } from '@wcag-ada/shared';

const reportRoutes = new Hono();

// Apply authentication to all routes
reportRoutes.use('*', authenticate);

// Validation schemas
const generateReportSchema = z.object({
  websiteId: z.string(),
  type: z.enum(['COMPLIANCE', 'EXECUTIVE', 'TECHNICAL', 'TREND']),
  format: z.enum(['PDF', 'HTML', 'JSON', 'CSV']),
  period: z.object({
    start: z.string().transform(s => new Date(s)),
    end: z.string().transform(s => new Date(s)),
  }),
});

// Generate a new report
reportRoutes.post('/generate', zValidator('json', generateReportSchema), async (c) => {
  const userId = c.get('userId');
  const { websiteId, type, format, period } = c.req.valid('json');
  
  // Check website ownership
  const website = await prisma.website.findFirst({
    where: {
      id: websiteId,
      userId,
      active: true,
    },
  });
  
  if (!website) {
    return c.json({ error: 'Website not found' }, 404);
  }
  
  // Get scan results for the period
  const scanResults = await prisma.scanResult.findMany({
    where: {
      websiteId,
      createdAt: {
        gte: period.start,
        lte: period.end,
      },
    },
    orderBy: { createdAt: 'asc' },
  });
  
  if (scanResults.length === 0) {
    return c.json({ error: 'No scan data available for the specified period' }, 400);
  }
  
  // Generate report data
  const reportData = await generateReport({
    website,
    scanResults,
    type,
    format,
    period,
  });
  
  // Save report
  const report = await prisma.report.create({
    data: {
      websiteId,
      userId,
      type,
      format,
      period: period as any,
      summary: reportData.summary as any,
      data: reportData.data as any,
      fileUrl: reportData.fileUrl,
    },
  });
  
  return c.json({
    report: {
      id: report.id,
      type: report.type,
      format: report.format,
      period: report.period,
      fileUrl: report.fileUrl,
      generatedAt: report.generatedAt,
    },
  }, 201);
});

// Get user's reports
reportRoutes.get('/', async (c) => {
  const userId = c.get('userId');
  const { page = '1', limit = '20', websiteId, type } = c.req.query();
  
  const pageNum = parseInt(page);
  const limitNum = parseInt(limit);
  const skip = (pageNum - 1) * limitNum;
  
  const where = {
    userId,
    ...(websiteId && { websiteId }),
    ...(type && { type }),
  };
  
  const [reports, total] = await Promise.all([
    prisma.report.findMany({
      where,
      skip,
      take: limitNum,
      orderBy: { generatedAt: 'desc' },
      include: {
        website: {
          select: {
            id: true,
            name: true,
            url: true,
          },
        },
      },
    }),
    prisma.report.count({ where }),
  ]);
  
  return c.json({
    reports,
    pagination: {
      page: pageNum,
      limit: limitNum,
      total,
      totalPages: Math.ceil(total / limitNum),
    },
  });
});

// Get report by ID
reportRoutes.get('/:id', async (c) => {
  const userId = c.get('userId');
  const reportId = c.req.param('id');
  
  const report = await prisma.report.findFirst({
    where: {
      id: reportId,
      userId,
    },
    include: {
      website: {
        select: {
          id: true,
          name: true,
          url: true,
        },
      },
    },
  });
  
  if (!report) {
    return c.json({ error: 'Report not found' }, 404);
  }
  
  return c.json(report);
});

// Download report file
reportRoutes.get('/:id/download', async (c) => {
  const userId = c.get('userId');
  const reportId = c.req.param('id');
  
  const report = await prisma.report.findFirst({
    where: {
      id: reportId,
      userId,
    },
  });
  
  if (!report || !report.fileUrl) {
    return c.json({ error: 'Report file not found' }, 404);
  }
  
  // In production, this would redirect to a signed URL or serve from storage
  // For now, we'll just return the file URL
  return c.json({ downloadUrl: report.fileUrl });
});

// Get compliance trends
reportRoutes.get('/trends/:websiteId', async (c) => {
  const userId = c.get('userId');
  const websiteId = c.req.param('websiteId');
  const { days = '30' } = c.req.query();
  
  // Check website ownership
  const website = await prisma.website.findFirst({
    where: {
      id: websiteId,
      userId,
    },
  });
  
  if (!website) {
    return c.json({ error: 'Website not found' }, 404);
  }
  
  const daysNum = parseInt(days);
  const startDate = new Date();
  startDate.setDate(startDate.getDate() - daysNum);
  
  const scanResults = await prisma.scanResult.findMany({
    where: {
      websiteId,
      createdAt: {
        gte: startDate,
      },
    },
    orderBy: { createdAt: 'asc' },
    select: {
      createdAt: true,
      summary: true,
      wcagCompliance: true,
    },
  });
  
  const trends = scanResults.map(result => ({
    date: result.createdAt,
    score: (result.summary as any).score,
    violationCount: (result.summary as any).violationCount,
    passCount: (result.summary as any).passCount,
    criticalIssues: (result.summary as any).criticalIssues,
    seriousIssues: (result.summary as any).seriousIssues,
  }));
  
  return c.json({
    websiteId,
    period: {
      start: startDate,
      end: new Date(),
    },
    trends,
  });
});

export { reportRoutes };