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 type { Website, ScanSchedule } from '@wcag-ada/shared';

const websiteRoutes = new Hono();

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

// Validation schemas
const createWebsiteSchema = z.object({
  name: z.string().min(1),
  url: z.string().url(),
  tags: z.array(z.string()).optional(),
  scanSchedule: z.object({
    frequency: z.enum(['manual', 'hourly', 'daily', 'weekly', 'monthly']),
    dayOfWeek: z.number().min(0).max(6).optional(),
    dayOfMonth: z.number().min(1).max(31).optional(),
    hour: z.number().min(0).max(23).optional(),
    timezone: z.string().optional(),
  }).optional(),
  authConfig: z.any().optional(),
  scanOptions: z.any().optional(),
});

const updateWebsiteSchema = createWebsiteSchema.partial();

// List websites
websiteRoutes.get('/', async (c) => {
  const userId = c.get('userId');
  const { page = '1', limit = '20', search } = c.req.query();
  
  const pageNum = parseInt(page);
  const limitNum = parseInt(limit);
  const skip = (pageNum - 1) * limitNum;
  
  const where = {
    userId,
    ...(search && {
      OR: [
        { name: { contains: search, mode: 'insensitive' } },
        { url: { contains: search, mode: 'insensitive' } },
      ],
    }),
  };
  
  const [websites, total] = await Promise.all([
    prisma.website.findMany({
      where,
      skip,
      take: limitNum,
      orderBy: { createdAt: 'desc' },
      include: {
        _count: {
          select: { scanResults: true },
        },
      },
    }),
    prisma.website.count({ where }),
  ]);
  
  return c.json({
    websites,
    pagination: {
      page: pageNum,
      limit: limitNum,
      total,
      totalPages: Math.ceil(total / limitNum),
    },
  });
});

// Get website by ID
websiteRoutes.get('/:id', async (c) => {
  const userId = c.get('userId');
  const websiteId = c.req.param('id');
  
  const website = await prisma.website.findFirst({
    where: {
      id: websiteId,
      userId,
    },
    include: {
      scanResults: {
        take: 1,
        orderBy: { createdAt: 'desc' },
      },
      _count: {
        select: {
          scanResults: true,
          scanJobs: true,
        },
      },
    },
  });
  
  if (!website) {
    return c.json({ error: 'Website not found' }, 404);
  }
  
  return c.json(website);
});

// Create website
websiteRoutes.post('/', zValidator('json', createWebsiteSchema), async (c) => {
  const userId = c.get('userId');
  const data = c.req.valid('json');
  
  // Check if website already exists for this user
  const existing = await prisma.website.findFirst({
    where: {
      url: data.url,
      userId,
    },
  });
  
  if (existing) {
    return c.json({ error: 'Website already exists' }, 400);
  }
  
  const website = await prisma.website.create({
    data: {
      ...data,
      userId,
      scanSchedule: data.scanSchedule ? data.scanSchedule : undefined,
      authConfig: data.authConfig ? data.authConfig : undefined,
      scanOptions: data.scanOptions ? data.scanOptions : undefined,
    },
  });
  
  return c.json(website, 201);
});

// Update website
websiteRoutes.patch('/:id', zValidator('json', updateWebsiteSchema), async (c) => {
  const userId = c.get('userId');
  const websiteId = c.req.param('id');
  const data = c.req.valid('json');
  
  // Check ownership
  const existing = await prisma.website.findFirst({
    where: {
      id: websiteId,
      userId,
    },
  });
  
  if (!existing) {
    return c.json({ error: 'Website not found' }, 404);
  }
  
  const website = await prisma.website.update({
    where: { id: websiteId },
    data: {
      ...data,
      scanSchedule: data.scanSchedule !== undefined ? data.scanSchedule : undefined,
      authConfig: data.authConfig !== undefined ? data.authConfig : undefined,
      scanOptions: data.scanOptions !== undefined ? data.scanOptions : undefined,
    },
  });
  
  return c.json(website);
});

// Delete website
websiteRoutes.delete('/:id', async (c) => {
  const userId = c.get('userId');
  const websiteId = c.req.param('id');
  
  // Check ownership
  const existing = await prisma.website.findFirst({
    where: {
      id: websiteId,
      userId,
    },
  });
  
  if (!existing) {
    return c.json({ error: 'Website not found' }, 404);
  }
  
  // Soft delete by setting active to false
  await prisma.website.update({
    where: { id: websiteId },
    data: { active: false },
  });
  
  return c.json({ message: 'Website deleted successfully' });
});

// Get website scan history
websiteRoutes.get('/:id/scans', async (c) => {
  const userId = c.get('userId');
  const websiteId = c.req.param('id');
  const { page = '1', limit = '20' } = c.req.query();
  
  const pageNum = parseInt(page);
  const limitNum = parseInt(limit);
  const skip = (pageNum - 1) * limitNum;
  
  // Check ownership
  const website = await prisma.website.findFirst({
    where: {
      id: websiteId,
      userId,
    },
  });
  
  if (!website) {
    return c.json({ error: 'Website not found' }, 404);
  }
  
  const [scans, total] = await Promise.all([
    prisma.scanResult.findMany({
      where: { websiteId },
      skip,
      take: limitNum,
      orderBy: { createdAt: 'desc' },
      select: {
        id: true,
        url: true,
        scanDuration: true,
        summary: true,
        wcagCompliance: true,
        createdAt: true,
      },
    }),
    prisma.scanResult.count({ where: { websiteId } }),
  ]);
  
  return c.json({
    scans,
    pagination: {
      page: pageNum,
      limit: limitNum,
      total,
      totalPages: Math.ceil(total / limitNum),
    },
  });
});

export { websiteRoutes };