/**
 * Brand Authority Score -- Orchestrator
 * ----------------------------------------
 * Runs all six authority signals in parallel via Promise.allSettled,
 * applies a 30-second hard timeout, and produces a composite BrandAuthorityScore.
 *
 * A single signal failure NEVER collapses the section.
 *
 * Internal module -- vendor names permitted in code; forbidden in user-facing output.
 */

import { detectWikipediaWikidataPresence } from "../../authority/wikipedia-detector";
import { detectEditorialMentions } from "../../authority/editorial-mentions";
import { detectDirectoryListings } from "../../authority/directory-listings";
import { deriveSocialProof } from "../../authority/social-proof";
import { estimateReferringDomains } from "../../authority/referring-domains";
import { estimateBrandedSearchDemand } from "../../authority/branded-search-demand";
import { scoreBrandAuthority } from "../../authority/composite-scorer";
import type { AuthoritySignal, AuthoritySignalStatus, BrandAuthorityScore } from "../../authority/types";

const SECTION_TIMEOUT_MS = 30_000;

// ─── Score normalizers ────────────────────────────────────────────────────────

function statusFromScore(score: number): AuthoritySignalStatus {
  if (score >= 75) return "strong";
  if (score >= 45) return "moderate";
  if (score >= 15) return "weak";
  return "absent";
}

// ─── Encyclopedic signal ──────────────────────────────────────────────────────

interface EncyclopedicResult {
  hasWikipediaPage: boolean;
  wikipediaPageTitle: string | null;
  wikipediaUrl: string | null;
  hasWikidataEntity: boolean;
  wikidataId: string | null;
  avgDailyPageviews: number;
}

async function runEncyclopedicSignal(brandName: string): Promise<AuthoritySignal & { _internal: EncyclopedicResult }> {
  const presence = await detectWikipediaWikidataPresence(brandName);

  let avgDailyPageviews = 0;
  if (presence.hasWikipediaPage && presence.wikipediaPageTitle) {
    try {
      const { getWikipediaPageviews } = await import("../../authority/wikipedia-pageviews");
      const pv = await getWikipediaPageviews(presence.wikipediaPageTitle);
      avgDailyPageviews = pv?.avgDailyPageviews ?? 0;
    } catch {
      // non-fatal
    }
  }

  // Scoring: Wikipedia page = 60pts, Wikidata entity = 20pts, pageviews bonus up to 20pts
  let score = 0;
  if (presence.hasWikipediaPage) score += 60;
  if (presence.hasWikidataEntity) score += 20;
  if (avgDailyPageviews > 1000) score += 20;
  else if (avgDailyPageviews > 200) score += 12;
  else if (avgDailyPageviews > 50) score += 6;
  score = Math.min(100, score);

  const status = statusFromScore(score);
  const evidence: string[] = [];
  if (presence.hasWikipediaPage) {
    const pvStr = avgDailyPageviews > 0 ? ` with ${avgDailyPageviews.toLocaleString()} avg daily reference lookups over the past 90 days` : "";
    evidence.push(`Brand has a verified encyclopedic knowledge graph entry${pvStr}.`);
  } else {
    evidence.push("No encyclopedic knowledge graph entry detected for this brand.");
  }
  if (presence.hasWikidataEntity) {
    evidence.push("Brand entity is registered in structured open knowledge databases.");
  }

  const recommendation = score < 75
    ? "Pursue an encyclopedic knowledge graph entry. This is the single highest-leverage authority signal because it provides AI engines a structured, verifiable reference for the brand entity."
    : null;

  const internal: EncyclopedicResult = {
    hasWikipediaPage: presence.hasWikipediaPage,
    wikipediaPageTitle: presence.wikipediaPageTitle,
    wikipediaUrl: presence.wikipediaUrl,
    hasWikidataEntity: presence.hasWikidataEntity,
    wikidataId: presence.wikidataId,
    avgDailyPageviews,
  };

  return {
    key: "encyclopedic_presence",
    label: "Encyclopedic Presence",
    status,
    rawScore: score,
    weight: 0.20,
    weightedContribution: score * 0.20,
    evidence,
    recommendation,
    rawSignalData: internal as unknown as Record<string, unknown>,
    _internal: internal,
  };
}

// ─── Editorial signal ─────────────────────────────────────────────────────────

async function runEditorialSignal(brandName: string): Promise<AuthoritySignal> {
  const data = await detectEditorialMentions(brandName);

  // Scoring: tier1 = 20pts each (cap 60), tier2 = 10pts each (cap 20), last90d bonus up to 20
  let score = Math.min(60, data.tier1Count * 20) + Math.min(20, data.tier2Count * 10);
  if (data.last90DayMentionCount >= 5) score += 20;
  else if (data.last90DayMentionCount >= 2) score += 12;
  else if (data.last90DayMentionCount >= 1) score += 6;
  score = Math.min(100, score);

  const status = statusFromScore(score);
  const evidence: string[] = [];
  if (data.mentionCount > 0) {
    const t1Label = data.tier1Count === 1 ? "national publication" : "national publications";
    const t2Label = data.tier2Count === 1 ? "trade source" : "trade sources";
    evidence.push(
      `Brand has ${data.mentionCount} editorial mention${data.mentionCount !== 1 ? "s" : ""} in the past year, including ${data.tier1Count} from ${t1Label} and ${data.tier2Count} from ${t2Label}.`,
    );
    if (data.last90DayMentionCount > 0) {
      evidence.push(`${data.last90DayMentionCount} mention${data.last90DayMentionCount !== 1 ? "s" : ""} in the past 90 days indicate active media presence.`);
    }
  } else {
    evidence.push("No editorial mentions detected for this brand across major publications.");
  }

  const recommendation = score < 75
    ? "Invest in editorial PR targeting trade and national publications. Earned media coverage is one of the strongest authority signals AI engines use to validate brand credibility."
    : null;

  return {
    key: "editorial_mentions",
    label: "Editorial Mentions",
    status,
    rawScore: score,
    weight: 0.20,
    weightedContribution: score * 0.20,
    evidence,
    recommendation,
    rawSignalData: data as unknown as Record<string, unknown>,
  };
}

// ─── Directory signal ─────────────────────────────────────────────────────────

async function runDirectorySignal(brandName: string, vertical: string): Promise<AuthoritySignal> {
  const data = await detectDirectoryListings(brandName, vertical);

  const ratio = data.totalChecked > 0 ? data.totalFound / data.totalChecked : 0;
  const score = Math.round(ratio * 100);
  const status = statusFromScore(score);

  const evidence: string[] = [];
  if (data.totalFound > 0) {
    const top2 = data.foundDirectoryCategories.slice(0, 2);
    const catStr = top2.join(" and a ");
    evidence.push(
      `Brand is present in ${data.totalFound} of ${data.totalChecked} relevant industry director${data.totalChecked !== 1 ? "ies" : "y"}, including a ${catStr}.`,
    );
  } else {
    evidence.push("Brand has minimal presence in industry directories relevant to its vertical.");
  }

  const top2cats = data.foundDirectoryCategories.slice(0, 2).join(" and ");
  const recommendation = score < 75
    ? `Claim and complete profiles on the ${top2cats || "most relevant directories"} for this vertical. Industry directory presence reinforces categorical authority.`
    : null;

  return {
    key: "industry_directories",
    label: "Industry Authority Listings",
    status,
    rawScore: score,
    weight: 0.15,
    weightedContribution: score * 0.15,
    evidence,
    recommendation,
    rawSignalData: data as unknown as Record<string, unknown>,
  };
}

// ─── Social proof signal ──────────────────────────────────────────────────────

function runSocialProofSignal(existingContext: Parameters<typeof deriveSocialProof>[0]): AuthoritySignal {
  const data = deriveSocialProof(existingContext);

  let score = 0;
  if (data.aggregateRatingSchemaPresent) score += 30;
  if (data.reviewSchemaPresent) score += 20;
  if (data.hasVisibleReviewWidget) score += 20;
  if (data.totalReviewCount > 50) score += 20;
  else if (data.totalReviewCount > 10) score += 10;
  if (data.avgRating && data.avgRating >= 4.0) score += 10;
  score = Math.min(100, score);

  const status = statusFromScore(score);
  const evidence: string[] = [];
  if (data.totalReviewCount > 0 && data.avgRating) {
    evidence.push(
      `Brand has ${data.totalReviewCount} review${data.totalReviewCount !== 1 ? "s" : ""} with an average rating of ${data.avgRating.toFixed(1)}, and review schema is ${data.aggregateRatingSchemaPresent ? "properly implemented" : "not yet implemented"}.`,
    );
  } else {
    evidence.push("Limited review volume and no aggregate rating schema detected.");
  }
  if (data.hasVisibleReviewWidget) {
    evidence.push("Social proof is visible to visitors on key pages.");
  }

  const recommendation = score < 75
    ? "Build review velocity on relevant platforms and implement aggregateRating schema markup. Visible social proof is a near-universal trust signal across AI engines."
    : null;

  return {
    key: "social_proof",
    label: "Social Proof Signals",
    status,
    rawScore: score,
    weight: 0.15,
    weightedContribution: score * 0.15,
    evidence,
    recommendation,
    rawSignalData: data as unknown as Record<string, unknown>,
  };
}

// ─── Referring domains signal ─────────────────────────────────────────────────

async function runReferringDomainsSignal(brandDomain: string): Promise<AuthoritySignal> {
  const data = await estimateReferringDomains(brandDomain);

  // Scoring: unique domains (capped at 50) = up to 70pts, quality score provides up to 30
  const domainScore = Math.min(70, Math.round((data.uniqueReferringDomainCount / 50) * 70));
  const qualityBonus = Math.round(data.qualityScore * 0.30);
  const score = Math.min(100, domainScore + qualityBonus);
  const status = statusFromScore(score);

  const evidence: string[] = [];
  if (data.uniqueReferringDomainCount > 0) {
    const tier1Pct = data.uniqueReferringDomainCount > 0
      ? Math.round((data.tier1ReferringCount / data.uniqueReferringDomainCount) * 100)
      : 0;
    evidence.push(
      `Brand domain is referenced across ${data.uniqueReferringDomainCount} unique external domain${data.uniqueReferringDomainCount !== 1 ? "s" : ""}, with ${tier1Pct}% from high-authority sources.`,
    );
  } else {
    evidence.push("Brand domain has minimal external referencing across the public web.");
  }

  const recommendation = score < 75
    ? "Develop a backlink acquisition strategy focused on high-authority editorial and industry sources. Referring domain quality outweighs quantity for authority scoring."
    : null;

  return {
    key: "referring_domains",
    label: "Referring Domain Network",
    status,
    rawScore: score,
    weight: 0.15,
    weightedContribution: score * 0.15,
    evidence,
    recommendation,
    rawSignalData: data as unknown as Record<string, unknown>,
  };
}

// ─── Branded demand signal ────────────────────────────────────────────────────

async function runBrandedDemandSignal(
  brandName: string,
  hasWikipediaPage: boolean,
  wikipediaPageTitle: string | null,
  vertical: string,
): Promise<AuthoritySignal> {
  const data = await estimateBrandedSearchDemand(brandName, hasWikipediaPage, wikipediaPageTitle, vertical);

  const tierScore: Record<string, number> = { high: 100, moderate: 65, low: 35, minimal: 10 };
  const score = tierScore[data.demandTier] ?? 10;
  const status = statusFromScore(score);

  const evidence: string[] = [
    `Branded search interest is ${data.demandTier} for this brand's vertical${data.source === "pageviews" ? `, based on ${data.proxyMetric.toLocaleString()} average daily knowledge graph reference lookups` : ""}.`,
  ];

  const recommendation = score < 75
    ? "Increase branded search demand through targeted brand campaigns. Branded search volume is a leading indicator AI engines use to weight entity importance."
    : null;

  return {
    key: "branded_search_demand",
    label: "Branded Search Demand",
    status,
    rawScore: score,
    weight: 0.15,
    weightedContribution: score * 0.15,
    evidence,
    recommendation,
    rawSignalData: data as unknown as Record<string, unknown>,
  };
}

// ─── Degraded fallback ────────────────────────────────────────────────────────

function buildDegradedScore(brandName: string, start: number): BrandAuthorityScore {
  const runtimeSeconds = (Date.now() - start) / 1000;
  const emptySignals: AuthoritySignal[] = [
    "encyclopedic_presence", "editorial_mentions", "industry_directories",
    "social_proof", "referring_domains", "branded_search_demand",
  ].map((key, i) => ({
    key: key as AuthoritySignal["key"],
    label: ["Encyclopedic Presence", "Editorial Mentions", "Industry Authority Listings", "Social Proof Signals", "Referring Domain Network", "Branded Search Demand"][i]!,
    status: "absent" as AuthoritySignalStatus,
    rawScore: 0,
    weight: 1 / 6,
    weightedContribution: 0,
    evidence: ["Signal analysis timed out for this dimension."],
    recommendation: null,
    rawSignalData: { timedOut: true },
  }));
  return {
    hasScore: true,
    overall: 0,
    tier: "Limited",
    signals: emptySignals,
    topRecommendations: [],
    narrativeSummary: `${brandName} authority analysis timed out. Please re-run the audit to generate authority signals.`,
    patentRelevance: "Brand authority composite combines public knowledge graph presence with editorial mentions, directory authority, and branded search demand to produce a defensible single-number signal of AI-engine citation-worthiness across the LLMO surface.",
    costMetrics: { signalsAttempted: 6, signalsSucceeded: 0, estimatedCostUsd: 0, runtimeSeconds },
    windowDate: new Date(),
  };
}

// ─── Main orchestrator ────────────────────────────────────────────────────────

export async function aggregateBrandAuthorityScore({
  brandName,
  brandDomain,
  vertical,
  existingAuditContext,
}: {
  brandName: string;
  brandDomain: string;
  vertical: string;
  existingAuditContext: Parameters<typeof deriveSocialProof>[0];
}): Promise<BrandAuthorityScore | null> {
  const start = Date.now();

  try {
    type Batch = readonly [
      PromiseSettledResult<AuthoritySignal & { _internal: EncyclopedicResult }>,
      PromiseSettledResult<AuthoritySignal>,
      PromiseSettledResult<AuthoritySignal>,
      PromiseSettledResult<Awaited<ReturnType<typeof estimateReferringDomains>>>,
    ];
    const allSettledPromise = Promise.allSettled([
      runEncyclopedicSignal(brandName),
      runEditorialSignal(brandName),
      runDirectorySignal(brandName, vertical),
      estimateReferringDomains(brandDomain),
    ]) as Promise<Batch>;

    const timeoutPromise = new Promise<null>((resolve) =>
      setTimeout(() => resolve(null), SECTION_TIMEOUT_MS),
    );

    const batch = await Promise.race([allSettledPromise, timeoutPromise]);

    if (batch === null) {
      return buildDegradedScore(brandName, start);
    }

    const [encyclopedicSettled, editorialSettled, directorySettled, referringSettled] = batch;

    // Extract encyclopedic internal data for dependent signals
    const encyclopedicSignal = encyclopedicSettled.status === "fulfilled" ? encyclopedicSettled.value : null;
    const hasWikipediaPage = encyclopedicSignal?._internal?.hasWikipediaPage ?? false;
    const wikipediaPageTitle = encyclopedicSignal?._internal?.wikipediaPageTitle ?? null;

    // Now run branded demand (depends on encyclopedic) + social proof (sync)
    const [brandedSettled] = await Promise.allSettled([
      runBrandedDemandSignal(brandName, hasWikipediaPage, wikipediaPageTitle, vertical),
    ]);

    const socialSignal = runSocialProofSignal(existingAuditContext);

    // Assemble final signal array -- all 6 must be present
    const signals: AuthoritySignal[] = [];
    let signalsSucceeded = 0;
    let braveCallCount = 0; // for cost estimation

    function pushSettled<T extends AuthoritySignal>(settled: PromiseSettledResult<T>, fallbackKey: AuthoritySignal["key"], fallbackLabel: string): void {
      if (settled.status === "fulfilled") {
        // Strip _internal before pushing (type assertion needed)
        const { _internal: _dropped, ...sig } = settled.value as T & { _internal?: unknown };
        signals.push(sig as AuthoritySignal);
        signalsSucceeded++;
      } else {
        console.warn(`[brand-authority] signal ${fallbackKey} failed:`, settled.reason instanceof Error ? settled.reason.message : settled.reason);
        signals.push({
          key: fallbackKey,
          label: fallbackLabel,
          status: "absent",
          rawScore: 0,
          weight: 1 / 6,
          weightedContribution: 0,
          evidence: ["Signal analysis unavailable for this dimension."],
          recommendation: null,
          rawSignalData: { error: String(settled.reason) },
        });
      }
    }

    pushSettled(encyclopedicSettled as PromiseSettledResult<AuthoritySignal & { _internal: EncyclopedicResult }>, "encyclopedic_presence", "Encyclopedic Presence");
    pushSettled(editorialSettled as PromiseSettledResult<AuthoritySignal>, "editorial_mentions", "Editorial Mentions");
    pushSettled(directorySettled as PromiseSettledResult<AuthoritySignal>, "industry_directories", "Industry Authority Listings");

    // Referring domains: referringSettled holds the raw result, not a full signal yet
    if (referringSettled.status === "fulfilled") {
      const rd = referringSettled.value as Awaited<ReturnType<typeof estimateReferringDomains>>;
      const domainScore = Math.min(70, Math.round((rd.uniqueReferringDomainCount / 50) * 70));
      const qualityBonus = Math.round(rd.qualityScore * 0.30);
      const score = Math.min(100, domainScore + qualityBonus);
      const tier1Pct = rd.uniqueReferringDomainCount > 0 ? Math.round((rd.tier1ReferringCount / rd.uniqueReferringDomainCount) * 100) : 0;
      signals.push({
        key: "referring_domains",
        label: "Referring Domain Network",
        status: statusFromScore(score),
        rawScore: score,
        weight: 0.15,
        weightedContribution: score * 0.15,
        evidence: rd.uniqueReferringDomainCount > 0
          ? [`Brand domain is referenced across ${rd.uniqueReferringDomainCount} unique external domain${rd.uniqueReferringDomainCount !== 1 ? "s" : ""}, with ${tier1Pct}% from high-authority sources.`]
          : ["Brand domain has minimal external referencing across the public web."],
        recommendation: score < 75
          ? "Develop a backlink acquisition strategy focused on high-authority editorial and industry sources. Referring domain quality outweighs quantity for authority scoring."
          : null,
        rawSignalData: rd as unknown as Record<string, unknown>,
      });
      signalsSucceeded++;
      braveCallCount++;
    } else {
      signals.push({
        key: "referring_domains", label: "Referring Domain Network",
        status: "absent", rawScore: 0, weight: 0.15, weightedContribution: 0,
        evidence: ["Signal analysis unavailable for this dimension."],
        recommendation: "Develop a backlink acquisition strategy focused on high-authority editorial and industry sources. Referring domain quality outweighs quantity for authority scoring.",
        rawSignalData: {},
      });
    }

    signals.push(socialSignal);
    signalsSucceeded++;

    pushSettled(brandedSettled as PromiseSettledResult<AuthoritySignal>, "branded_search_demand", "Branded Search Demand");

    // Brave cost estimate: editorial + directories (up to 8) + referring + maybe branded
    braveCallCount += 1 + 8 + 1 + (hasWikipediaPage ? 0 : 1);
    const estimatedCostUsd = Math.round(braveCallCount * 0.003 * 1000) / 1000;

    const runtimeSeconds = (Date.now() - start) / 1000;

    return scoreBrandAuthority(signals, vertical, brandName, new Date(), {
      signalsAttempted: 6,
      signalsSucceeded,
      estimatedCostUsd,
      runtimeSeconds,
    });
  } catch (err) {
    console.warn("[brand-authority] orchestrator error:", err instanceof Error ? err.message : err);
    return buildDegradedScore(brandName, start);
  }
}
