import { NextRequest, NextResponse } from 'next/server';
import { getSupabaseAdmin } from '@/lib/supabase';
import { loadCaches, matchProduct } from '@/lib/matching';
import { filterEDILines } from '@/lib/filters';
import { ParsedEDILine, Supplier } from '@/types';

// Allow up to 5 minutes for large file analysis with Claude API calls
export const maxDuration = 300;

export async function POST(req: NextRequest) {
  try {
    const body = await req.json();
    const {
      month,
      supplier,
      lines,
      fileName,
      categories,
      scope,
    }: {
      month: string;
      supplier: Supplier;
      lines: ParsedEDILine[];
      fileName?: string;
      categories?: { appareils: boolean; accessoires: boolean; entretien: boolean };
      scope?: 'all' | 'suc' | 'franchise';
    } = body;

    if (!month || !supplier || !lines?.length) {
      return NextResponse.json(
        { error: 'month, supplier, et lines requis' },
        { status: 400 }
      );
    }

    const supabase = getSupabaseAdmin();

    // Load caches for matching (date-aware: use analysis month for price lookup)
    await loadCaches(supplier, month);

    // Check if analysis already exists for this month+supplier
    const { data: existingAnalyses } = await supabase
      .from('analyses')
      .select('id')
      .eq('month', month)
      .eq('supplier', supplier);

    let analysisId: string;

    if (existingAnalyses && existingAnalyses.length > 0) {
      // Update existing
      analysisId = existingAnalyses[0].id;
      await supabase
        .from('analyses')
        .update({
          total_lines: lines.length,
          status: 'processing',
          file_name: fileName ?? null,
        })
        .eq('id', analysisId);

      // Clear previous analysis_lines
      await supabase.from('analysis_lines').delete().eq('analysis_id', analysisId);
    } else {
      // Create new
      const { data: newAnalysis, error: analysisError } = await supabase
        .from('analyses')
        .insert({
          month,
          supplier,
          total_lines: lines.length,
          filtered_lines: 0,
          matched_lines: 0,
          unmatched_lines: 0,
          total_discrepancies: 0,
          discrepancy_count: 0,
          total_overcharged: 0,
          status: 'processing',
          file_name: fileName ?? null,
        })
        .select()
        .single();

      if (analysisError || !newAnalysis) {
        return NextResponse.json(
          { error: 'Erreur création analyse: ' + analysisError?.message },
          { status: 500 }
        );
      }
      analysisId = newAnalysis.id;
    }

    // Load SUC codes for scope filtering
    let sucCodes: Set<string> | undefined;
    if (scope && scope !== 'all') {
      const { data: centres } = await supabase
        .from('centre_codes')
        .select('code, name')
        .eq('supplier', supplier)
        .eq('is_suc', true);
      if (centres) {
        sucCodes = new Set(centres.map((c: { code: string; name: string }) =>
          supplier === 'resound' ? c.name : c.code
        ));
      }
    }

    // Filter lines: exclude eco-taxe, port, réparations, garanties, etc.
    const { filtered: filteredLines } = filterEDILines(lines, supplier, {
      categories: categories ?? { appareils: true, accessoires: true, entretien: true },
      scope: scope ?? 'all',
      sucCodes,
    });

    // Process each line: match + calculate discrepancy
    const analysisLines: { analysis_id: string; centre: string; code_article: string; description: string; quantity: number; invoiced_price: number; negotiated_price: number | null; matched_product: string; match_method: string; invoice_number: string; famille?: string }[] = [];
    let discrepancyCount = 0;
    let totalOvercharged = 0;
    let matchedLines = 0;
    let unmatchedLines = 0;

    // Track match stats per level
    const matchStats = { exact: 0, keyword: 0, claude: 0, unmatched: 0 };

    for (const line of filteredLines) {
      const match = await matchProduct(supplier, line.code_article, line.description, line.unit_price);

      matchStats[match.match_method]++;
      const isMatched = match.match_method !== 'unmatched';
      if (isMatched) matchedLines++;
      else unmatchedLines++;

      // discrepancy is a GENERATED column (invoiced_price - negotiated_price)
      // so we just track it for the summary, don't insert it
      const discrepancy =
        match.negotiated_price !== null
          ? Math.round((line.unit_price - match.negotiated_price) * 100) / 100
          : 0;

      if (discrepancy > 0.01) {
        discrepancyCount++;
        totalOvercharged += discrepancy * line.quantity;
      }

      // Use centre_name if available, otherwise centre_code
      const centre = line.centre_name || line.centre_code;

      analysisLines.push({
        analysis_id: analysisId,
        centre,
        code_article: line.code_article,
        description: line.description,
        quantity: line.quantity,
        invoiced_price: line.unit_price,
        negotiated_price: match.negotiated_price,
        // discrepancy is GENERATED — do NOT insert
        matched_product: match.matched_product_name,
        match_method: match.match_method,
        invoice_number: line.invoice_number,
        famille: line.famille || '',
      });
    }

    console.log(`[ANALYZE] ${supplier} ${month} — Match stats: exact=${matchStats.exact}, keyword=${matchStats.keyword}, claude=${matchStats.claude}, unmatched=${matchStats.unmatched}`);

    // Insert analysis lines in batches of 500 (strip famille — column may not exist in DB)
    for (let i = 0; i < analysisLines.length; i += 500) {
      // eslint-disable-next-line @typescript-eslint/no-unused-vars
      const batch = analysisLines.slice(i, i + 500).map(({ famille, ...rest }) => rest);
      await supabase.from('analysis_lines').insert(batch);
    }

    // Persist unmatched products to product_mappings with status='unknown'
    const unmatchedCodes = new Set<string>();
    for (const line of analysisLines) {
      if (line.match_method === 'unmatched' && line.code_article) {
        unmatchedCodes.add(line.code_article);
      }
    }
    console.log(`[ANALYZE] ${supplier} — ${unmatchedCodes.size} unmatched codes to persist`);
    if (unmatchedCodes.size > 0) {
      for (const code of Array.from(unmatchedCodes)) {
        // Check if mapping already exists
        const { data: existing } = await supabase
          .from('product_mappings')
          .select('id')
          .eq('supplier', supplier)
          .eq('code_article', code)
          .limit(1);

        if (!existing || existing.length === 0) {
          const line = analysisLines.find(l => l.code_article === code);
          const { error: insertError } = await supabase
            .from('product_mappings')
            .insert({
              supplier,
              code_article: code,
              description_edi: line?.description || null,
              matched_product_name: null,
              matched_product_id: null,
              confidence: 'excluded',
              validated: false,
              status: 'unknown',
            });
          if (insertError) {
            console.log(`[ANALYZE] Failed to persist unknown code ${code}:`, insertError.message);
          } else {
            console.log(`[ANALYZE] Persisted unknown code ${code}`);
          }
        }
      }
    }

    // Update analysis totals
    totalOvercharged = Math.round(totalOvercharged * 100) / 100;
    await supabase
      .from('analyses')
      .update({
        discrepancy_count: discrepancyCount,
        total_discrepancies: discrepancyCount,
        total_overcharged: totalOvercharged,
        total_lines: lines.length,
        filtered_lines: filteredLines.length,
        matched_lines: matchedLines,
        unmatched_lines: unmatchedLines,
        status: 'done',
      })
      .eq('id', analysisId);

    return NextResponse.json({
      analysis_id: analysisId,
      total_lines: filteredLines.length,
      matched_lines: matchedLines,
      unmatched_lines: unmatchedLines,
      discrepancy_count: discrepancyCount,
      total_overcharged: totalOvercharged,
      lines: analysisLines.map((l, i) => ({
        ...l,
        // Add computed discrepancy for frontend display
        discrepancy:
          l.negotiated_price !== null
            ? Math.round((l.invoiced_price - l.negotiated_price) * 100) / 100
            : 0,
        id: `temp-${i}`,
      })),
    });
  } catch (error) {
    const message = error instanceof Error ? error.message : 'Erreur inconnue';
    return NextResponse.json({ error: message }, { status: 500 });
  }
}

// GET: fetch analysis results for a month
export async function GET(req: NextRequest) {
  try {
    const { searchParams } = new URL(req.url);
    const month = searchParams.get('month');
    const supplier = searchParams.get('supplier') as Supplier | null;

    const supabase = getSupabaseAdmin();

    let query = supabase.from('analyses').select('*');
    if (month) query = query.eq('month', month);
    if (supplier) query = query.eq('supplier', supplier);
    query = query.order('created_at', { ascending: false });

    const { data: analyses, error } = await query;

    if (error) {
      return NextResponse.json({ error: error.message }, { status: 500 });
    }

    // Fetch lines for each analysis
    const results = [];
    for (const analysis of analyses ?? []) {
      const { data: lines } = await supabase
        .from('analysis_lines')
        .select('*')
        .eq('analysis_id', analysis.id)
        .order('discrepancy', { ascending: false });

      results.push({ ...analysis, lines: lines ?? [] });
    }

    return NextResponse.json(results);
  } catch (error) {
    const message = error instanceof Error ? error.message : 'Erreur inconnue';
    return NextResponse.json({ error: message }, { status: 500 });
  }
}

// DELETE: remove an analysis and its lines
export async function DELETE(req: NextRequest) {
  try {
    const { searchParams } = new URL(req.url);
    const id = searchParams.get('id');
    if (!id) return NextResponse.json({ error: 'id requis' }, { status: 400 });

    const supabase = getSupabaseAdmin();
    await supabase.from('analysis_lines').delete().eq('analysis_id', id);
    await supabase.from('analyses').delete().eq('id', id);

    return NextResponse.json({ success: true });
  } catch (error) {
    const message = error instanceof Error ? error.message : 'Erreur inconnue';
    return NextResponse.json({ error: message }, { status: 500 });
  }
}
