import type { IndustryContext } from "../audit/synthesizers/industry-classifier";
import type { VoiceSearchEligibility, VoiceSearchGap, VoiceSearchRecommendation } from "./types";
import type { SpeakableSchemaResult } from "./checks/speakable-schema";
import type { ConversationalQueryResult } from "./checks/conversational-query";
import type { FaqReadabilityResult } from "./checks/faq-readability";
import type { LocalPackSignalsResult } from "./checks/local-pack-signals";

// Industry relevance weight map. Default 0.7 for unmapped industries.
// Exact strings must match src/lib/audit/synthesizers/industry-classifier.ts
const INDUSTRY_VOICE_WEIGHT: Record<string, number> = {
  "local-services": 1.0,
  "healthcare-medical": 1.0,
  "healthcare-dental": 1.0,
  "hospitality": 1.0,
  "professional-services": 0.85,
  "real-estate": 0.85,
  "legal": 0.85,
  "finance": 0.75,
  "ecommerce": 0.7,
  "nonprofit": 0.7,
  "higher-ed": 0.65,
  "b2b-saas": 0.6,
};

function resolveIndustryRelevance(industryContext: IndustryContext | null): VoiceSearchEligibility["industryRelevance"] {
  const id = industryContext?.industry ?? "other";
  const weight = INDUSTRY_VOICE_WEIGHT[id] ?? 0.7;
  if (weight >= 0.9) return "high";
  if (weight >= 0.7) return "medium";
  return "low";
}

const PATENT_RELEVANCE =
  "Voice search eligibility signals (speakable schema coverage, conversational query alignment, FAQ speakability, and local entity disambiguation) represent the structural content-qualification layer AI voice assistants apply when selecting sources for spoken responses.";

export function scoreVoiceSearchEligibility(
  speakable: SpeakableSchemaResult,
  conversational: ConversationalQueryResult,
  faq: FaqReadabilityResult,
  local: LocalPackSignalsResult,
  industryContext: IndustryContext | null,
): VoiceSearchEligibility {
  // Equal-weight composite (25/25/25/25). Industry weight drives relevance label only.
  const compositeScore = Math.round(
    ((speakable.score + conversational.score + faq.score + local.score) / 4) * 100,
  ) / 100;

  const allGaps: VoiceSearchGap[] = [
    ...speakable.gaps,
    ...conversational.gaps,
    ...faq.gaps,
    ...local.gaps,
  ].sort((a, b) => b.estimatedScoreLift - a.estimatedScoreLift);

  const allRecommendations: VoiceSearchRecommendation[] = [
    ...speakable.recommendations,
    ...conversational.recommendations,
    ...faq.recommendations,
    ...local.recommendations,
  ];

  // Deduplicate recommendations by title, preserving insertion order
  const seen = new Set<string>();
  const recommendations = allRecommendations.filter((r) => {
    if (seen.has(r.title)) return false;
    seen.add(r.title);
    return true;
  });

  return {
    hasData: true,
    compositeScore,
    industryRelevance: resolveIndustryRelevance(industryContext),
    subScores: {
      speakableSchema: speakable.score,
      conversationalQuery: conversational.score,
      faqReadability: faq.score,
      localPackSignals: local.score,
    },
    topGaps: allGaps.slice(0, 5),
    recommendations: recommendations.slice(0, 6),
    patentRelevance: PATENT_RELEVANCE,
  };
}
