/**
 * Reformulation Generator
 * -------------------------
 * Generates prescriptive content reformulation specs per snippet opportunity.
 * Uses an AI content prescription engine with structured output.
 *
 * Internal module -- provider names permitted in code; forbidden in customer-facing strings.
 */

import Anthropic from "@anthropic-ai/sdk";
import { getSchemaRequirementsForSnippetType } from "./schema-requirements";
import { getBenchmarkForIndustry } from "../audit/data/industry-benchmarks";
import type { SnippetOpportunity, CapturedSnippetReformulation, CaptureSpec, SnippetType } from "./types";

const PER_OPPORTUNITY_TIMEOUT_MS = 15_000;

const client = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY ?? "" });

const WORD_COUNT_BY_TYPE: Record<SnippetType, { min: number; max: number }> = {
  paragraph: { min: 40, max: 58 },
  list_ordered: { min: 5, max: 8 },
  list_unordered: { min: 4, max: 9 },
  table: { min: 3, max: 7 },
  definition: { min: 35, max: 50 },
  how_to: { min: 6, max: 10 },
  faq: { min: 40, max: 60 },
  video: { min: 90, max: 180 },
};

const CTR_TABLE: Record<SnippetType, Record<string, number>> = {
  paragraph:      { high: 0.32, moderate: 0.22, low: 0.12 },
  list_ordered:   { high: 0.28, moderate: 0.18, low: 0.10 },
  list_unordered: { high: 0.28, moderate: 0.18, low: 0.10 },
  table:          { high: 0.24, moderate: 0.16, low: 0.09 },
  definition:     { high: 0.35, moderate: 0.24, low: 0.13 },
  how_to:         { high: 0.28, moderate: 0.19, low: 0.11 },
  faq:            { high: 0.25, moderate: 0.17, low: 0.10 },
  video:          { high: 0.20, moderate: 0.13, low: 0.08 },
};

function slugify(query: string): string {
  const stopwords = new Set(["a", "an", "the", "of", "in", "on", "at", "to", "for", "with", "how", "what", "is", "are"]);
  return query
    .toLowerCase()
    .replace(/[^a-z0-9\s]/g, "")
    .split(/\s+/)
    .filter((w) => w.length > 1 && !stopwords.has(w))
    .join("-")
    .slice(0, 60);
}

interface BrandContext {
  brandName: string;
  vertical: string;
  brandDomain: string;
  brandSitemap?: string;
}

export async function generateReformulation(
  opportunity: SnippetOpportunity,
  brandContext: BrandContext,
): Promise<CapturedSnippetReformulation | null> {
  const { brandName, vertical } = brandContext;
  const { query, snippetType, brandHasMatchingPage, brandMatchingPageUrl } = opportunity;

  const wordCountTarget = WORD_COUNT_BY_TYPE[snippetType];
  const newPageRecommended = !brandHasMatchingPage;
  const newPageSlug = newPageRecommended ? slugify(query) : null;
  const targetPageUrl = brandHasMatchingPage ? (brandMatchingPageUrl ?? null) : null;

  const existingPageLine = brandHasMatchingPage && brandMatchingPageUrl
    ? `Existing page URL: ${brandMatchingPageUrl}`
    : `Recommended new page slug: /${newPageSlug}`;

  const systemPrompt = `You generate prescriptive content reformulation specs for SEO featured snippet capture. Output must be a JSON object matching the CaptureSpec schema. Do not include any explanation outside the JSON. Do not mention any AI provider, model, or vendor in any string. Do not use em dashes anywhere in any output string.`;

  const userPrompt = `Brand: ${brandName}
Vertical: ${vertical}
Target query: ${query}
Snippet type: ${snippetType}
Brand has existing matching page: ${brandHasMatchingPage}
${existingPageLine}

Generate a CaptureSpec JSON with these fields:
- wordCountTarget: { "min": ${wordCountTarget.min}, "max": ${wordCountTarget.max} }
- paragraphStructure: 1 sentence describing the required structural pattern (no em dashes)
- headerFormat: 1 sentence describing required H2/H3 format (no em dashes)
- contentSkeleton: a 2-3 sentence example draft using realistic content for the ${vertical} vertical. Use no em dashes. Reference no vendor names. This is a structural reference, not finished copy.
- schemaRequirements: [] (leave empty array, will be filled externally)
- competitorReference: 1 sentence generically describing what currently captures this snippet (e.g. "A regional service provider currently holds this snippet with a 47-word paragraph and FAQ schema"). Never name a specific competitor or vendor. May be null if no competitor is known.
- estimatedCaptureProbability: "high" or "moderate" or "low"
- captureRationale: 1-2 sentences explaining the capture probability (no em dashes)

Output ONLY the JSON, no preamble, no markdown fences.`;

  try {
    const timeoutPromise = new Promise<null>((resolve) =>
      setTimeout(() => resolve(null), PER_OPPORTUNITY_TIMEOUT_MS),
    );

    const apiPromise = client.messages.create({
      model: "claude-haiku-4-5-20251001",
      max_tokens: 600,
      system: systemPrompt,
      messages: [{ role: "user", content: userPrompt }],
    });

    const response = await Promise.race([apiPromise, timeoutPromise]);
    if (!response) {
      console.warn(`[reformulation-generator] timeout for query="${query}"`);
      return null;
    }

    const rawText = response.content
      .filter((c) => c.type === "text")
      .map((c) => (c as { type: "text"; text: string }).text)
      .join("");

    let parsed: Partial<CaptureSpec>;
    try {
      parsed = JSON.parse(rawText) as Partial<CaptureSpec>;
    } catch {
      const jsonMatch = rawText.match(/\{[\s\S]*\}/);
      if (!jsonMatch) {
        console.warn(`[reformulation-generator] JSON parse failed for query="${query}"`);
        return null;
      }
      try {
        parsed = JSON.parse(jsonMatch[0]) as Partial<CaptureSpec>;
      } catch {
        console.warn(`[reformulation-generator] JSON extract failed for query="${query}"`);
        return null;
      }
    }

    const schemaRequirements = getSchemaRequirementsForSnippetType(snippetType, vertical);

    const captureSpec: CaptureSpec = {
      wordCountTarget,
      paragraphStructure: parsed.paragraphStructure ?? `Single ${wordCountTarget.min}-${wordCountTarget.max} unit block directly answering the query.`,
      headerFormat: parsed.headerFormat ?? `H2 matching the exact query phrasing or a close paraphrase.`,
      contentSkeleton: parsed.contentSkeleton ?? `[Content reformulation for: ${query}]`,
      schemaRequirements,
      competitorReference: parsed.competitorReference ?? null,
      estimatedCaptureProbability: parsed.estimatedCaptureProbability ?? "moderate",
      captureRationale: parsed.captureRationale ?? `This opportunity has moderate capture probability based on snippet type and competitive landscape.`,
    };

    const benchmarks = getBenchmarkForIndustry(vertical);
    const { avgCustomerValue, avgConversionRate } = benchmarks;
    const searchVolume = opportunity.estimatedMonthlySearchVolume ?? 0;
    const ctrMap = CTR_TABLE[snippetType] ?? CTR_TABLE.paragraph;
    const ctr = ctrMap[captureSpec.estimatedCaptureProbability] ?? ctrMap.moderate ?? 0.18;
    const estimatedMonthlyTrafficGain = Math.round(searchVolume * ctr);
    const estimatedMonthlyRevenueGain = Math.round(estimatedMonthlyTrafficGain * avgConversionRate * avgCustomerValue);

    return {
      opportunityId: opportunity.id,
      query,
      snippetType,
      targetPageUrl,
      newPageRecommended,
      newPageSlug,
      captureSpec,
      estimatedMonthlyTrafficGain,
      estimatedMonthlyRevenueGain,
    };
  } catch (err) {
    console.warn(`[reformulation-generator] error for query="${query}":`, err instanceof Error ? err.message : err);
    return null;
  }
}
