/**
 * Competitor Web Research Orchestration
 *
 * Coordinates web research specifically for competitor generation.
 * Constructs appropriate search queries from company context + ICP data,
 * then uses the web research service to find and crawl competitor websites.
 */

import { performWebResearch, WebResearchResult, WebSearchResult, WebsiteFetchResult } from './webResearchService';
import { CompetitorPipelineInputs } from './competitorPrompts';

// ============================================
// TYPES
// ============================================

export interface CompetitorWebResearchData {
  /** The real website URL detected from web research, or null */
  detectedWebsite: string | null;
  /** Structured website info extracted from crawling */
  websiteInfo: {
    title?: string;
    description?: string;
    foundedYear?: string;
    headquarters?: string;
    employeeCount?: string;
    revenueEstimate?: string;
    keyProducts?: string[];
    pricingInfo?: string;
    valueProposition?: string;
    marketingChannels?: string[];
    seoKeywords?: string[];
    competitiveAdvantages?: string[];
    weaknesses?: string[];
  } | null;
  /** Search insights about the competitive landscape */
  searchInsights: {
    realCompetitors: string[];
    marketPosition: string;
    industryTrends: string[];
  } | null;
  /** Formatted research text for inclusion in AI prompts */
  rawResearch: string;
}

// ============================================
// MAIN EXPORT: RESEARCH COMPETITOR
// ============================================

/**
 * Perform web research for a competitor using the company context and ICP data.
 *
 * Two research strategies:
 * 1. Quick Generate (has shortDescription): Search for the described competitor directly
 * 2. Auto-Fill (no description): Search for companies competing in the same industry/market
 *
 * This function is non-blocking: if research fails, it returns an empty
 * CompetitorWebResearchData (with null fields) rather than throwing.
 */
export async function researchCompetitor(
  inputs: CompetitorPipelineInputs,
  onProgress?: (step: string) => void,
): Promise<CompetitorWebResearchData> {
  const emptyResult: CompetitorWebResearchData = {
    detectedWebsite: null,
    websiteInfo: null,
    searchInsights: null,
    rawResearch: '',
  };

  try {
    // Build search query from inputs
    const searchQuery = buildSearchQuery(inputs);
    const websiteUrl = inputs.existingCompetitorWebsite || undefined;
    // The competitor's name lets the resolver recognise its own domain among
    // the search results instead of settling for whatever ranked first.
    const nameHint = resolveCompetitorNameHint(inputs);

    console.log(`[CompetitorWebResearch] Searching for: "${searchQuery}"${websiteUrl ? `, website: ${websiteUrl}` : ''}${nameHint ? `, name: "${nameHint}"` : ''}`);
    onProgress?.('Researching competitors on the web...');

    // Perform web research
    const researchResult = await performWebResearch(searchQuery, websiteUrl, onProgress, nameHint);

    if (!researchResult) {
      console.log('[CompetitorWebResearch] No research results — falling back to AI-only generation');
      return emptyResult;
    }

    // Extract structured data from the research
    const websiteInfo = extractWebsiteInfo(researchResult);
    const searchInsights = extractSearchInsights(researchResult, inputs);
    const rawResearch = formatResearchForPrompt(researchResult);

    const result: CompetitorWebResearchData = {
      detectedWebsite: researchResult.detectedWebsite,
      websiteInfo,
      searchInsights,
      rawResearch,
    };

    console.log(`[CompetitorWebResearch] Research complete. Website: ${result.detectedWebsite || 'none'}, Search results: ${researchResult.searchResults.length}`);
    return result;

  } catch (error: any) {
    console.warn(`[CompetitorWebResearch] Research failed: ${error.message}`);
    return emptyResult;
  }
}

// ============================================
// SEARCH QUERY BUILDER
// ============================================

/**
 * The competitor's own name, when we know it.
 *
 * Regenerate/auto-fill supply it directly. Quick Generate only has a free-text
 * description, so the leading capitalised words are taken as the brand name
 * ("AirFlex Performance Running Shoes" → "AirFlex Performance"), which is
 * enough for the resolver to spot the matching domain.
 */
function resolveCompetitorNameHint(inputs: CompetitorPipelineInputs): string | undefined {
  if (inputs.existingCompetitorName?.trim()) return inputs.existingCompetitorName.trim();

  const description = inputs.shortDescription?.trim();
  if (!description) return undefined;

  const leadingProperNoun = description.match(/^([A-Z][\w&'-]*(?:\s+[A-Z][\w&'-]*)*)/);
  if (leadingProperNoun && leadingProperNoun[1].length >= 3) {
    return leadingProperNoun[1].split(/\s+/).slice(0, 4).join(' ');
  }
  // No obvious brand name — fall back to the first few words of the description.
  return description.split(/\s+/).slice(0, 4).join(' ');
}

/**
 * Build an effective search query from the pipeline inputs.
 */
function buildSearchQuery(inputs: CompetitorPipelineInputs): string {
  const parts: string[] = [];

  if (inputs.shortDescription) {
    // Quick generate: use the description directly
    parts.push(inputs.shortDescription);
    if (inputs.companyIndustry) {
      parts.push(`${inputs.companyIndustry} industry`);
    }
  } else if (inputs.existingCompetitorName) {
    // Regenerate: search for the existing competitor
    parts.push(inputs.existingCompetitorName);
    if (inputs.companyIndustry) {
      parts.push(`${inputs.companyIndustry} competitor`);
    }
  } else {
    // Auto-fill: search for competitors in our industry
    if (inputs.companyName) {
      parts.push(`companies like ${inputs.companyName}`);
    }
    if (inputs.companyIndustry) {
      parts.push(`${inputs.companyIndustry} competitors`);
    }
    if (inputs.companyPrimaryOffering) {
      parts.push(inputs.companyPrimaryOffering);
    }
    if (inputs.companyBusinessModel) {
      parts.push(inputs.companyBusinessModel);
    }
    if (inputs.icpIndustry) {
      parts.push(`${inputs.icpIndustry} market`);
    }
  }

  // If we still don't have much, add general context
  if (parts.length === 0) {
    if (inputs.companyDescription) {
      // Extract key terms from description
      const descWords = inputs.companyDescription.split(' ').slice(0, 10).join(' ');
      parts.push(descWords);
    }
  }

  // ── Targeting filters from the Generate with AI dialog ────────────────────
  // These were previously dropped here. The branches above search only on
  // company-level context, so "SEO agency in Pune" searched as
  // "companies like ABC Digital Solutions Digital Marketing competitors" —
  // which returns globally popular agencies. Those results are then handed to
  // the prompt as the PRIMARY source for factual claims, so the whole
  // generation inherits the wrong geography and domain. Narrowing the QUERY is
  // what makes the result set relevant; the prompt can only rank what it is given.
  const qualifiers: string[] = [];

  // Target industries beat the company's own industry: the user picked these
  // explicitly for this run.
  const industries = inputs.targetIndustries?.filter((s) => s?.trim()) || [];
  if (industries.length) {
    qualifiers.push(industries.slice(0, 3).join(' '));
  }

  // Product names, when the run is product-based — competitors are the firms
  // offering the same thing, which the company-level terms never express.
  if (inputs.generateBasedOn === 'product' || inputs.generateBasedOn === 'both') {
    const productNames = (inputs.targetProducts || [])
      .map((p) => p?.name?.trim())
      .filter((n): n is string => !!n);
    if (productNames.length) qualifiers.push(productNames.slice(0, 3).join(' '));
  }

  // Most specific location first — a city name is the strongest relevance
  // signal a search engine gets, and country alone is the weakest.
  const location = [
    inputs.targetCities?.filter((s) => s?.trim()).slice(0, 2).join(' '),
    inputs.targetStates?.filter((s) => s?.trim()).slice(0, 2).join(' '),
    inputs.targetCountries?.filter((s) => s?.trim()).slice(0, 2).join(' '),
  ]
    .filter(Boolean)
    .join(' ');
  if (location) qualifiers.push(`in ${location}`);

  const suffix = qualifiers.join(' ').trim();
  if (!suffix) return parts.join(' ').substring(0, 200);

  // Truncate the CORE terms, never the qualifiers — appending and then cutting
  // at 200 would silently drop the location, which is the part that matters most.
  const core = parts.join(' ').substring(0, Math.max(0, 200 - suffix.length - 1)).trim();
  return `${core} ${suffix}`.trim();
}

// ============================================
// DATA EXTRACTION
// ============================================

/**
 * Extract structured website information from the research results.
 */
function extractWebsiteInfo(result: WebResearchResult): CompetitorWebResearchData['websiteInfo'] {
  if (!result.websiteContent && !result.researchSummary) {
    return null;
  }

  const info: NonNullable<CompetitorWebResearchData['websiteInfo']> = {};

  // Extract from website content
  if (result.websiteContent) {
    info.title = result.websiteContent.title || undefined;
    info.description = result.websiteContent.description || undefined;

    // Extract key info from the crawled website
    const keyInfo = result.websiteContent.keyInfo;
    if (keyInfo.founded) info.foundedYear = keyInfo.founded;
    if (keyInfo.headquarters) info.headquarters = keyInfo.headquarters;
    if (keyInfo.employees) info.employeeCount = keyInfo.employees;
    if (keyInfo.revenue) info.revenueEstimate = keyInfo.revenue;

    // Try to extract pricing info from content
    const content = result.websiteContent.rawContent;
    const pricingMatch = content.match(/(?:pricing|plans?|packages?|tiers?)\s*[:\-–]?\s*([^\n.]{10,200})/i);
    if (pricingMatch) {
      info.pricingInfo = pricingMatch[1].trim();
    }

    // Try to extract value proposition from meta description or content
    if (result.websiteContent.description) {
      info.valueProposition = result.websiteContent.description.substring(0, 200);
    }
  }

  // Try to extract structured data from the AI summary
  if (result.researchSummary) {
    const summary = result.researchSummary;

    // Try to parse JSON if the summary contains JSON
    try {
      const jsonMatch = summary.match(/\{[\s\S]*\}/);
      if (jsonMatch) {
        const parsed = JSON.parse(jsonMatch[0]);

        if (parsed.companyInfo) {
          if (!info.foundedYear && parsed.companyInfo.foundedYear) info.foundedYear = String(parsed.companyInfo.foundedYear);
          if (!info.headquarters && parsed.companyInfo.headquarters) info.headquarters = parsed.companyInfo.headquarters;
          if (!info.employeeCount && parsed.companyInfo.employeeCount) info.employeeCount = parsed.companyInfo.employeeCount;
          if (!info.revenueEstimate && parsed.companyInfo.revenueEstimate) info.revenueEstimate = parsed.companyInfo.revenueEstimate;
          if (!info.description && parsed.companyInfo.description) info.description = parsed.companyInfo.description;
        }

        if (parsed.products && Array.isArray(parsed.products)) {
          info.keyProducts = parsed.products;
        }
        if (parsed.pricing) {
          info.pricingInfo = info.pricingInfo || parsed.pricing;
        }
        if (parsed.marketingChannels && Array.isArray(parsed.marketingChannels)) {
          info.marketingChannels = parsed.marketingChannels;
        }
        if (parsed.strengths && Array.isArray(parsed.strengths)) {
          info.competitiveAdvantages = parsed.strengths;
        }
        if (parsed.weaknesses && Array.isArray(parsed.weaknesses)) {
          info.weaknesses = parsed.weaknesses;
        }
      }
    } catch {
      // Not valid JSON — use text extraction
    }

    // Try text-based extraction
    if (!info.foundedYear) {
      const foundedMatch = summary.match(/(?:founded|established|started)\s+(?:in\s+)?(\d{4})/i);
      if (foundedMatch) info.foundedYear = foundedMatch[1];
    }
    if (!info.headquarters) {
      const hqMatch = summary.match(/(?:headquarters|HQ|based in|located in)\s+([A-Z][a-zA-Z\s]+(?:,\s*[A-Z][a-zA-Z\s]+)?)/);
      if (hqMatch) info.headquarters = hqMatch[1].trim();
    }
    if (!info.employeeCount) {
      const empMatch = summary.match(/(\d[\d,+]*)\+?\s*(?:employees|team members|people|staff)/i);
      if (empMatch) info.employeeCount = empMatch[1];
    }
  }

  // Only return if we have meaningful data
  const hasData = Object.values(info).some(v => v !== undefined);
  return hasData ? info : null;
}

/**
 * Extract search insights from the research results.
 */
function extractSearchInsights(
  result: WebResearchResult,
  inputs: CompetitorPipelineInputs,
): CompetitorWebResearchData['searchInsights'] {
  if (result.searchResults.length === 0 && !result.researchSummary) {
    return null;
  }

  const insights: NonNullable<CompetitorWebResearchData['searchInsights']> = {
    realCompetitors: [],
    marketPosition: '',
    industryTrends: [],
  };

  // Extract competitor names from search result titles and snippets
  const seenNames = new Set<string>();
  for (const r of result.searchResults) {
    // Try to extract company names from titles
    const titleWords = r.title.split(/[\s\-|:–—]+/).filter(w => w.length > 2);
    for (const word of titleWords.slice(0, 3)) {
      const cleanWord = word.replace(/[^a-zA-Z0-9]/g, '');
      if (cleanWord && !seenNames.has(cleanWord) && cleanWord.length > 2) {
        seenNames.add(cleanWord);
        if (insights.realCompetitors.length < 5) {
          insights.realCompetitors.push(cleanWord);
        }
      }
    }
  }

  // Extract from AI summary
  if (result.researchSummary) {
    try {
      const jsonMatch = result.researchSummary.match(/\{[\s\S]*\}/);
      if (jsonMatch) {
        const parsed = JSON.parse(jsonMatch[0]);
        if (parsed.competitors && Array.isArray(parsed.competitors)) {
          for (const comp of parsed.competitors) {
            if (typeof comp === 'string' && !seenNames.has(comp) && insights.realCompetitors.length < 5) {
              insights.realCompetitors.push(comp);
              seenNames.add(comp);
            }
          }
        }
      }
    } catch {
      // Not valid JSON
    }

    // Try to extract market position keywords
    const posMatch = result.researchSummary.match(/(?:market\s+(?:position|leader|share|positioning))[:\s]+([^\n.]{10,200})/i);
    if (posMatch) {
      insights.marketPosition = posMatch[1].trim();
    }

    // Extract industry trends
    const trendMatches = result.researchSummary.match(/(?:trend|growth|emerging|shift)[:\s]+([^\n.]{10,200})/gi);
    if (trendMatches) {
      insights.industryTrends = trendMatches.map(m => m.trim()).slice(0, 5);
    }
  }

  return insights;
}

// ============================================
// FORMAT RESEARCH FOR PROMPT
// ============================================

/**
 * Format the web research data into a text block that can be included
 * in the AI generation prompts. This provides the model with real
 * research data to ground its competitor profile generation.
 */
function formatResearchForPrompt(result: WebResearchResult): string {
  const parts: string[] = [];

  if (result.detectedWebsite) {
    parts.push(`DETECTED WEBSITE: ${result.detectedWebsite}`);
  }

  if (result.searchResults.length > 0) {
    parts.push('\nSEARCH RESULTS:');
    for (const r of result.searchResults.slice(0, 6)) {
      parts.push(`- ${r.title}`);
      if (r.url) parts.push(`  URL: ${r.url}`);
      if (r.snippet) parts.push(`  ${r.snippet}`);
    }
  }

  if (result.websiteContent) {
    parts.push('\nWEBSITE INFORMATION:');
    if (result.websiteContent.title) parts.push(`Title: ${result.websiteContent.title}`);
    if (result.websiteContent.description) parts.push(`Description: ${result.websiteContent.description}`);
    if (Object.keys(result.websiteContent.keyInfo).length > 0) {
      parts.push(`Key Info: ${JSON.stringify(result.websiteContent.keyInfo)}`);
    }
    // Include an excerpt of the raw content (limited to avoid token bloat)
    if (result.websiteContent.rawContent) {
      const excerpt = result.websiteContent.rawContent.substring(0, 3000);
      parts.push(`Content excerpt: ${excerpt}`);
    }
  }

  if (result.researchSummary) {
    parts.push('\nRESEARCH SUMMARY:');
    // Include the summary but limit its length
    parts.push(result.researchSummary.substring(0, 4000));
  }

  return parts.join('\n');
}