import { serve } from "https://deno.land/std@0.168.0/http/server.ts";
import { createEdgeFunction, type EdgeFunctionContext } from '../_shared/edgeFunctionWrapper.ts';
import { addSpanEvent } from '../_shared/logger.ts';
import { formatEdgeError } from '../_shared/errorFormatter.ts';

const BASE_URL = 'https://dev.thrillwiki.com';

// ============================================================================
// TYPE DEFINITIONS
// ============================================================================

interface SitemapUrl {
  loc: string;
  lastmod: string;
  changefreq: 'always' | 'hourly' | 'daily' | 'weekly' | 'monthly' | 'yearly' | 'never';
  priority: number;
}

interface SitemapStats {
  total_urls: number;
  parks: number;
  rides: number;
  manufacturers: number;
  models: number;
  designers: number;
  operators: number;
  owners: number;
  static_pages: number;
  generation_time_ms: number;
}

// ============================================================================
// IN-MEMORY CACHE
// ============================================================================

let cachedSitemap: string | null = null;
let cacheTimestamp: number = 0;
const CACHE_TTL_MS = 60 * 60 * 1000; // 1 hour

const cacheHeaders = {
  'Cache-Control': 'public, s-maxage=3600, stale-while-revalidate=86400',
  'CDN-Cache-Control': 'public, s-maxage=3600',
  'Vercel-CDN-Cache-Control': 'public, s-maxage=3600',
};

function isCacheValid(): boolean {
  if (!cachedSitemap) return false;
  const age = Date.now() - cacheTimestamp;
  return age < CACHE_TTL_MS;
}

// ============================================================================
// XML GENERATION UTILITIES
// ============================================================================

function escapeXml(unsafe: string): string {
  return unsafe
    .replace(/&/g, '&amp;')
    .replace(/</g, '&lt;')
    .replace(/>/g, '&gt;')
    .replace(/"/g, '&quot;')
    .replace(/'/g, '&apos;');
}

function calculatePriority(entityType: string, metadata?: { ride_count?: number }): number {
  switch (entityType) {
    case 'home': return 1.0;
    case 'park': 
      const rideCount = metadata?.ride_count || 0;
      return rideCount > 10 ? 0.9 : 0.8;
    case 'ride': return 0.9;
    case 'manufacturer': return 0.7;
    case 'model': return 0.6;
    case 'designer': return 0.6;
    case 'operator': return 0.6;
    case 'owner': return 0.6;
    case 'list': return 0.5;
    case 'static': return 0.3;
    default: return 0.5;
  }
}

function getChangeFreq(entityType: string): SitemapUrl['changefreq'] {
  switch (entityType) {
    case 'home': return 'daily';
    case 'park':
    case 'ride':
    case 'manufacturer': return 'weekly';
    case 'model':
    case 'designer':
    case 'operator':
    case 'owner': return 'monthly';
    case 'list': return 'daily';
    case 'static': return 'yearly';
    default: return 'monthly';
  }
}

function createUrl(
  path: string,
  entityType: string,
  lastmod: string,
  metadata?: { ride_count?: number }
): SitemapUrl {
  return {
    loc: `${BASE_URL}${path}`,
    lastmod: new Date(lastmod).toISOString().split('T')[0],
    changefreq: getChangeFreq(entityType),
    priority: calculatePriority(entityType, metadata),
  };
}

function generateSitemapXml(urls: SitemapUrl[]): string {
  const header = '<?xml version="1.0" encoding="UTF-8"?>\n' +
    '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n';
  
  const entries = urls.map(url => 
    `  <url>\n` +
    `    <loc>${escapeXml(url.loc)}</loc>\n` +
    `    <lastmod>${url.lastmod}</lastmod>\n` +
    `    <changefreq>${url.changefreq}</changefreq>\n` +
    `    <priority>${url.priority.toFixed(1)}</priority>\n` +
    `  </url>`
  ).join('\n');
  
  const footer = '\n</urlset>';
  
  return header + entries + footer;
}

// ============================================================================
// SITEMAP GENERATION
// ============================================================================

async function generateSitemap(requestId: string, span: any): Promise<{
  xml: string;
  stats: SitemapStats;
}> {
  const startTime = Date.now();
  const urls: SitemapUrl[] = [];
  const stats: SitemapStats = {
    total_urls: 0,
    parks: 0,
    rides: 0,
    manufacturers: 0,
    models: 0,
    designers: 0,
    operators: 0,
    owners: 0,
    static_pages: 0,
    generation_time_ms: 0,
  };
  
  const supabaseUrl = Deno.env.get('SUPABASE_URL') ?? '';
  const supabaseAnonKey = Deno.env.get('SUPABASE_ANON_KEY') ?? '';
  
  // Dynamic import to avoid circular dependency issues
  const { createClient } = await import('https://esm.sh/@supabase/supabase-js@2.57.4');
  const supabase = createClient(supabaseUrl, supabaseAnonKey);
  
  // Static pages
  const now = new Date().toISOString();
  urls.push(
    createUrl('/', 'home', now),
    createUrl('/parks', 'list', now),
    createUrl('/rides', 'list', now),
    createUrl('/manufacturers', 'list', now),
    createUrl('/designers', 'list', now),
    createUrl('/operators', 'list', now),
    createUrl('/owners', 'list', now),
    createUrl('/blog', 'list', now),
    createUrl('/terms', 'static', now),
    createUrl('/privacy', 'static', now),
    createUrl('/submission-guidelines', 'static', now),
    createUrl('/contact', 'static', now),
  );
  stats.static_pages = 12;
  
  // Parallel database queries
  const [parksResult, ridesResult, companiesResult, modelsResult] = await Promise.all([
    supabase
      .from('parks')
      .select('slug, updated_at')
      .not('slug', 'is', null)
      .order('updated_at', { ascending: false }),
    
    supabase
      .from('rides')
      .select('slug, updated_at, park:parks!inner(slug)')
      .not('slug', 'is', null)
      .order('updated_at', { ascending: false }),
    
    supabase
      .from('companies')
      .select('slug, updated_at, company_type')
      .not('slug', 'is', null)
      .order('updated_at', { ascending: false }),
    
    supabase
      .from('ride_models')
      .select('slug, updated_at, manufacturer:companies!ride_models_manufacturer_id_fkey(slug)')
      .not('slug', 'is', null)
      .order('updated_at', { ascending: false }),
  ]);
  
  // Process parks
  if (parksResult.data) {
    for (const park of parksResult.data) {
      urls.push(createUrl(`/parks/${park.slug}`, 'park', park.updated_at));
      urls.push(createUrl(`/parks/${park.slug}/rides`, 'list', park.updated_at));
      stats.parks++;
    }
  }
  
  // Process rides
  if (ridesResult.data) {
    for (const ride of ridesResult.data) {
      if (ride.park?.slug) {
        urls.push(createUrl(`/parks/${ride.park.slug}/rides/${ride.slug}`, 'ride', ride.updated_at));
        stats.rides++;
      }
    }
  }
  
  // Process companies
  if (companiesResult.data) {
    for (const company of companiesResult.data) {
      const type = company.company_type;
      
      if (type === 'manufacturer') {
        urls.push(createUrl(`/manufacturers/${company.slug}`, 'manufacturer', company.updated_at));
        urls.push(createUrl(`/manufacturers/${company.slug}/rides`, 'list', company.updated_at));
        urls.push(createUrl(`/manufacturers/${company.slug}/models`, 'list', company.updated_at));
        stats.manufacturers++;
      } else if (type === 'designer') {
        urls.push(createUrl(`/designers/${company.slug}`, 'designer', company.updated_at));
        urls.push(createUrl(`/designers/${company.slug}/rides`, 'list', company.updated_at));
        stats.designers++;
      } else if (type === 'operator') {
        urls.push(createUrl(`/operators/${company.slug}`, 'operator', company.updated_at));
        urls.push(createUrl(`/operators/${company.slug}/parks`, 'list', company.updated_at));
        stats.operators++;
      } else if (type === 'property_owner') {
        urls.push(createUrl(`/owners/${company.slug}`, 'owner', company.updated_at));
        urls.push(createUrl(`/owners/${company.slug}/parks`, 'list', company.updated_at));
        stats.owners++;
      }
    }
  }
  
  // Process ride models
  if (modelsResult.data) {
    for (const model of modelsResult.data) {
      if (model.manufacturer?.slug) {
        urls.push(
          createUrl(`/manufacturers/${model.manufacturer.slug}/models/${model.slug}`, 'model', model.updated_at)
        );
        urls.push(
          createUrl(`/manufacturers/${model.manufacturer.slug}/models/${model.slug}/rides`, 'list', model.updated_at)
        );
        stats.models++;
      }
    }
  }
  
  stats.total_urls = urls.length;
  stats.generation_time_ms = Date.now() - startTime;
  
  const xml = generateSitemapXml(urls);
  
  addSpanEvent(span, 'sitemap_generated', {
    stats,
    sizeKB: (xml.length / 1024).toFixed(2),
  });
  
  return { xml, stats };
}

function generateFallbackSitemap(): string {
  const now = new Date().toISOString();
  const urls: SitemapUrl[] = [
    createUrl('/', 'home', now),
    createUrl('/parks', 'list', now),
    createUrl('/rides', 'list', now),
    createUrl('/manufacturers', 'list', now),
    createUrl('/designers', 'list', now),
    createUrl('/operators', 'list', now),
    createUrl('/owners', 'list', now),
  ];
  
  return generateSitemapXml(urls);
}

// ============================================================================
// MAIN HANDLER
// ============================================================================

serve(createEdgeFunction({
  name: 'sitemap',
  requireAuth: false, // Public endpoint
  corsHeaders: {},
}, async (req, { span, requestId }: EdgeFunctionContext) => {
  const startTime = Date.now();
  
  // Return cached version if valid
  if (isCacheValid()) {
    const duration = Date.now() - startTime;
    addSpanEvent(span, 'sitemap_cache_hit', {
      cacheAge: Date.now() - cacheTimestamp,
      duration,
    });
    
    return new Response(cachedSitemap, {
      headers: {
        'Content-Type': 'application/xml; charset=utf-8',
        'X-Cache': 'HIT',
        'X-Generation-Time': `${duration}ms`,
        ...cacheHeaders,
      },
    });
  }
  
  // Generate fresh sitemap
  const sitemap = await generateSitemap(requestId, span);
  
  // Update cache
  cachedSitemap = sitemap.xml;
  cacheTimestamp = Date.now();
  
  const duration = Date.now() - startTime;
  
  addSpanEvent(span, 'sitemap_cache_miss', {
    duration,
    stats: sitemap.stats,
  });
  
  return new Response(sitemap.xml, {
    headers: {
      'Content-Type': 'application/xml; charset=utf-8',
      'X-Cache': 'MISS',
      'X-Generation-Time': `${duration}ms`,
      ...cacheHeaders,
    },
  });
}));
