import { NextResponse } from 'next/server';
import { prisma } from '@/lib/prisma';
import { sourceRegistry } from '@/lib/sources/registry';
import { checkDuplicate } from '@/lib/dedup';
import { normalizeQuery } from '@/lib/utils/normalization';

export async function POST(request: Request) {
  try {
    const body = await request.json();

    // Support both payload formats:
    // 1. Legacy:  { sourceId, params }
    // 2. UI form: { keyword, location }
    let sourceId: string;
    let params: Record<string, any>;

    if (body.keyword !== undefined || body.location !== undefined) {
      // Coming from the scan page UI
      sourceId = 'all';
      
      // Normalize user input to handle conversational queries, typos, and missing data intelligently
      const normalized = await normalizeQuery(body.keyword || "", body.location || "");
      
      params = {
        keyword: normalized.keyword,
        location: normalized.location,
        limit: body.limit ?? 100,
        originalKeyword: body.keyword,
        originalLocation: body.location,
      };
    } else {
      sourceId = body.sourceId;
      params = body.params ?? {};
    }

    console.log(`[SearchAPI] Processing search: source=${sourceId}`, params);

    const source = sourceRegistry.getSource(sourceId);
    if (!source && sourceId !== 'all') {
      return NextResponse.json({ error: 'Invalid source ID' }, { status: 400 });
    }

    // Create a search run record
    const searchRun = await prisma.searchRun.create({
      data: {
        sourceId: sourceId,
        sourceName: sourceId === 'all' ? 'All Sources' : source!.name,
        query: JSON.stringify(params),
        status: 'running',
      }
    });

    let results: any[] = [];

    if (sourceId === 'all') {
      const allAvailable = await sourceRegistry.getAvailableSources();
      // Exclude the mock source for real scans
      const realSources = allAvailable.filter(s => s.id !== 'mock-source');
      const sourcesToUse = realSources.length > 0 ? realSources : allAvailable;

      const allResults = await Promise.all(
        sourcesToUse.map(s => s.run(params).catch(e => {
          console.error(`Source ${s.id} failed:`, e);
          return [];
        }))
      );
      results = allResults.flat();
    } else {
      results = await source!.run(params);
    }

    // Process and save leads
    const finalLeadsMap = new Map();
    for (const lead of results) {
      const dup = await checkDuplicate(lead);

      if (!dup.isDuplicate) {
        const saved = await prisma.lead.create({
          data: {
            businessName: lead.businessName,
            website: lead.website,
            email: lead.email,
            phone: lead.phone,
            address: lead.address,
            city: lead.city,
            state: lead.state,
            country: lead.country,
            category: lead.category,
            source: sourceId === 'all' ? 'Aggregated' : sourceId,
            confidenceScore: lead.confidenceScore,
            status: 'new',
            rawData: JSON.stringify(lead.rawData),
          }
        });
        finalLeadsMap.set(saved.id, saved);
      } else {
        // Update existing lead with fresh real-world data from extraction nodes
        const updated = await prisma.lead.update({
          where: { id: dup.existingId },
          data: {
            businessName: lead.businessName,
            website: lead.website || undefined,
            email: lead.email || undefined,
            phone: lead.phone || undefined,
            address: lead.address || undefined,
            city: lead.city || undefined,
            category: lead.category || undefined,
            confidenceScore: lead.confidenceScore,
            rawData: JSON.stringify(lead.rawData),
            // Reset status if it was unqualified? Or just keep it. 
            // For now, let's just ensure fields are fresh.
          }
        });
        finalLeadsMap.set(updated.id, updated);
      }
    }

    const finalLeads = Array.from(finalLeadsMap.values());

    // Update search run status
    await prisma.searchRun.update({
      where: { id: searchRun.id },
      data: {
        status: 'completed',
        resultCount: results.length,
        completedAt: new Date(),
      }
    });

    // Log activity
    await prisma.activityLog.create({
      data: {
        action: 'search_run',
        details: `Ran search for "${params.keyword}" in "${params.location}". Total found: ${results.length}. Unique leads: ${finalLeads.length}.`
      }
    });

    return NextResponse.json({
      runId: searchRun.id,
      totalFound: results.length,
      newLeadsSaved: finalLeads.length,
      results: finalLeads.slice(0, 100)
    });

  } catch (error: any) {
    console.error('Search API Error:', error);
    return NextResponse.json(
      { error: error.message || 'Failed to search leads' },
      { status: 500 }
    );
  }
}
