import { Hono } from 'hono';
import { zValidator } from '@hono/zod-validator';
import { z } from 'zod';
import { db, dbGet, siteSettings, events } from '../db/index.js';
import { eq, and, gte } from 'drizzle-orm';
import { requireAuth } from '../lib/auth.js';
import { generateId, getNow, toDbBool } from '../lib/utils.js';
import { revalidateFrontendCache } from '../lib/revalidate.js';

interface UserContext {
  id: string;
  email: string;
  name: string;
  role: string;
}

const siteSettingsRouter = new Hono<{ Variables: { user: UserContext } }>();

// Validation schema for updating site settings
// Validate against the runtime's IANA timezone database (rejects arbitrary strings
// that later get fed into Intl.DateTimeFormat on the frontend).
const isValidTimezone = (tz: string): boolean => {
  try {
    Intl.DateTimeFormat('en-US', { timeZone: tz });
    return true;
  } catch {
    return false;
  }
};

const updateSiteSettingsSchema = z.object({
  timezone: z.string().refine(isValidTimezone, { message: 'Invalid timezone' }).optional(),
  siteName: z.string().max(255).optional(),
  siteDescription: z.string().optional().nullable(),
  siteDescriptionEs: z.string().optional().nullable(),
  contactEmail: z.string().email().optional().nullable().or(z.literal('')),
  contactPhone: z.string().optional().nullable(),
  facebookUrl: z.string().url().optional().nullable().or(z.literal('')),
  instagramUrl: z.string().url().optional().nullable().or(z.literal('')),
  twitterUrl: z.string().url().optional().nullable().or(z.literal('')),
  linkedinUrl: z.string().url().optional().nullable().or(z.literal('')),
  featuredEventId: z.string().optional().nullable(),
  maintenanceMode: z.boolean().optional(),
  maintenanceMessage: z.string().optional().nullable(),
  maintenanceMessageEs: z.string().optional().nullable(),
});

// Get site settings (public - needed for frontend timezone)
siteSettingsRouter.get('/', async (c) => {
  const settings = await dbGet(
    (db as any).select().from(siteSettings).limit(1)
  );
  
  if (!settings) {
    // Return default settings if none exist
    return c.json({
      settings: {
        timezone: 'America/Asuncion',
        siteName: 'Spanglish',
        siteDescription: null,
        siteDescriptionEs: null,
        contactEmail: null,
        contactPhone: null,
        facebookUrl: null,
        instagramUrl: null,
        twitterUrl: null,
        linkedinUrl: null,
        featuredEventId: null,
        maintenanceMode: false,
        maintenanceMessage: null,
        maintenanceMessageEs: null,
      },
    });
  }
  
  return c.json({ settings });
});

// Get available timezones
siteSettingsRouter.get('/timezones', async (c) => {
  // Common timezones for Americas (especially relevant for Paraguay)
  const timezones = [
    { value: 'America/Asuncion', label: 'Paraguay (Asunción) - UTC-4/-3' },
    { value: 'America/Sao_Paulo', label: 'Brazil (São Paulo) - UTC-3' },
    { value: 'America/Buenos_Aires', label: 'Argentina (Buenos Aires) - UTC-3' },
    { value: 'America/Santiago', label: 'Chile (Santiago) - UTC-4/-3' },
    { value: 'America/Lima', label: 'Peru (Lima) - UTC-5' },
    { value: 'America/Bogota', label: 'Colombia (Bogotá) - UTC-5' },
    { value: 'America/Caracas', label: 'Venezuela (Caracas) - UTC-4' },
    { value: 'America/La_Paz', label: 'Bolivia (La Paz) - UTC-4' },
    { value: 'America/Montevideo', label: 'Uruguay (Montevideo) - UTC-3' },
    { value: 'America/New_York', label: 'US Eastern - UTC-5/-4' },
    { value: 'America/Chicago', label: 'US Central - UTC-6/-5' },
    { value: 'America/Denver', label: 'US Mountain - UTC-7/-6' },
    { value: 'America/Los_Angeles', label: 'US Pacific - UTC-8/-7' },
    { value: 'America/Mexico_City', label: 'Mexico (Mexico City) - UTC-6/-5' },
    { value: 'Europe/London', label: 'UK (London) - UTC+0/+1' },
    { value: 'Europe/Madrid', label: 'Spain (Madrid) - UTC+1/+2' },
    { value: 'Europe/Paris', label: 'France (Paris) - UTC+1/+2' },
    { value: 'Europe/Berlin', label: 'Germany (Berlin) - UTC+1/+2' },
    { value: 'UTC', label: 'UTC (Coordinated Universal Time)' },
  ];
  
  return c.json({ timezones });
});

// Update site settings (admin only)
siteSettingsRouter.put('/', requireAuth(['admin']), zValidator('json', updateSiteSettingsSchema), async (c) => {
  const data = c.req.valid('json');
  const user = c.get('user');
  const now = getNow();
  
  // Check if settings exist
  const existing = await dbGet<any>(
    (db as any).select().from(siteSettings).limit(1)
  );
  
  if (!existing) {
    // Create new settings record
    const id = generateId();
    
    // Validate featured event if provided
    if (data.featuredEventId) {
      const featuredEvent = await dbGet<any>(
        (db as any).select().from(events).where(eq((events as any).id, data.featuredEventId))
      );
      if (!featuredEvent || featuredEvent.status !== 'published') {
        return c.json({ error: 'Featured event must exist and be published' }, 400);
      }
    }
    
    const newSettings = {
      id,
      timezone: data.timezone || 'America/Asuncion',
      siteName: data.siteName || 'Spanglish',
      siteDescription: data.siteDescription || null,
      siteDescriptionEs: data.siteDescriptionEs || null,
      contactEmail: data.contactEmail || null,
      contactPhone: data.contactPhone || null,
      facebookUrl: data.facebookUrl || null,
      instagramUrl: data.instagramUrl || null,
      twitterUrl: data.twitterUrl || null,
      linkedinUrl: data.linkedinUrl || null,
      featuredEventId: data.featuredEventId || null,
      maintenanceMode: toDbBool(data.maintenanceMode || false),
      maintenanceMessage: data.maintenanceMessage || null,
      maintenanceMessageEs: data.maintenanceMessageEs || null,
      updatedAt: now,
      updatedBy: user.id,
    };
    
    await (db as any).insert(siteSettings).values(newSettings);
    
    return c.json({ settings: newSettings, message: 'Settings created successfully' }, 201);
  }
  
  // Validate featured event if provided
  if (data.featuredEventId) {
    const featuredEvent = await dbGet<any>(
      (db as any).select().from(events).where(eq((events as any).id, data.featuredEventId))
    );
    if (!featuredEvent || featuredEvent.status !== 'published') {
      return c.json({ error: 'Featured event must exist and be published' }, 400);
    }
  }
  
  // Update existing settings
  const updateData: Record<string, any> = {
    ...data,
    updatedAt: now,
    updatedBy: user.id,
  };
  // Convert maintenanceMode boolean to appropriate format for database
  if (typeof data.maintenanceMode === 'boolean') {
    updateData.maintenanceMode = toDbBool(data.maintenanceMode);
  }
  
  await (db as any)
    .update(siteSettings)
    .set(updateData)
    .where(eq((siteSettings as any).id, existing.id));
  
  const updated = await dbGet(
    (db as any).select().from(siteSettings).where(eq((siteSettings as any).id, existing.id))
  );
  
  // Revalidate frontend cache if featured event changed
  if (data.featuredEventId !== undefined) {
    revalidateFrontendCache();
  }
  
  return c.json({ settings: updated, message: 'Settings updated successfully' });
});

// Set featured event (admin only) - convenience endpoint for event editor
siteSettingsRouter.put('/featured-event', requireAuth(['admin']), zValidator('json', z.object({
  eventId: z.string().nullable(),
})), async (c) => {
  const { eventId } = c.req.valid('json');
  const user = c.get('user');
  const now = getNow();
  
  // Validate event if provided
  if (eventId) {
    const event = await dbGet<any>(
      (db as any).select().from(events).where(eq((events as any).id, eventId))
    );
    if (!event) {
      return c.json({ error: 'Event not found' }, 404);
    }
    if (event.status !== 'published') {
      return c.json({ error: 'Event must be published to be featured' }, 400);
    }
    const eventEndTime = event.endDatetime || event.startDatetime;
    if (new Date(eventEndTime).getTime() <= Date.now()) {
      return c.json(
        { error: 'Cannot feature an event that has already ended' },
        400
      );
    }
  }

  // Get or create settings
  const existing = await dbGet<any>(
    (db as any).select().from(siteSettings).limit(1)
  );
  
  if (!existing) {
    // Create new settings record with featured event
    const id = generateId();
    const newSettings = {
      id,
      timezone: 'America/Asuncion',
      siteName: 'Spanglish',
      featuredEventId: eventId,
      maintenanceMode: 0,
      updatedAt: now,
      updatedBy: user.id,
    };
    
    await (db as any).insert(siteSettings).values(newSettings);
    
    // Revalidate frontend cache so homepage shows the updated featured event
    revalidateFrontendCache();
    
    return c.json({ featuredEventId: eventId, message: eventId ? 'Event set as featured' : 'Featured event removed' });
  }
  
  // Update existing settings
  await (db as any)
    .update(siteSettings)
    .set({
      featuredEventId: eventId,
      updatedAt: now,
      updatedBy: user.id,
    })
    .where(eq((siteSettings as any).id, existing.id));
  
  // Revalidate frontend cache so homepage shows the updated featured event
  revalidateFrontendCache();
  
  return c.json({ featuredEventId: eventId, message: eventId ? 'Event set as featured' : 'Featured event removed' });
});

export default siteSettingsRouter;
