/**
 * Audit Engine — Shared Types
 * ─────────────────────────────
 * Type definitions shared across all audit engine modules.
 * No third-party service names appear in type identifiers or JSDoc.
 */

// ─── Input ───────────────────────────────────────────────────────────────────

export interface AuditInput {
  brandName: string;
  website: string;
  competitors: string[];
  locations: string[];
  services: string[];
  isLocal: boolean;
  inferredIndustry?: string;
  degradedMode?: boolean;
  industryContext?: import("./synthesizers/industry-classifier").IndustryContext; // populated after Haiku industry pre-call
  // First-party context — only present when audit is brand-linked (brandId set)
  brandContext?: BrandContext;
  behavioralContext?: BehavioralContext;
  aiAttributionContext?: AiAttributionContext;
  webVitalsContext?: WebVitalEntry[];
  crawlStatsContext?: CrawlStatsContext;
  signalCenterContext?: SignalCenter | null;
  bilingualAuditContext?: BilingualAudit | null;
  competitorAnalysisContext?: CompetitorAnalysis | null;
  schemaOpportunityForecastContext?: SchemaOpportunityForecast | null;
  industryBenchmarkComparisonContext?: IndustryBenchmarkComparison | null;
  pageStrategicPassContext?: PageStrategicPass | null;
  aiEnginePersonalityAnalysisContext?: AiEnginePersonalityAnalysis | null;
  aiSourceAttributionComparisonContext?: AiSourceAttributionComparison | null;
  behavioralActionBridgeContext?: BehavioralActionBridge | null;
  eeatAuditContext?: import("./data-sources/eeat-audit").EeatAudit | null;
  voiceSearchEligibilityContext?: import("../voice-search-eligibility/types").VoiceSearchEligibility | null;
  aiSnippetEligibilityContext?: AiSnippetEligibility | null;
  multiTouchAiPathContext?: MultiTouchAiPath | null;
  revenueAttributionContext?: RevenueAttribution | null;
  predictiveConversionScoringContext?: PredictiveConversionScoring | null;
  conversionHeatMapContext?: ConversionHeatMap | null;
  aiSearchVerificationContext?: AiSearchVerification | null;
  lostOpportunityCalculationContext?: LostOpportunityCalculation | null;
  liveVisualAnnotationsContext?: LiveVisualAnnotations | null;
  competitorVisualComparisonContext?: CompetitorVisualComparison | null;
  brandAuthorityContext?: import("../authority/types").BrandAuthorityScore | null;
  snippetCaptureContext?: import("../snippet-capture/types").SnippetCaptureStrategy | null;
  mobileFirstContext?: import("../mobile-first/types").MobileFirstAudit | null;
  pageSpeedContext?: import("../page-speed/types").PageSpeedInsights | null;
  // Real-user technical findings context from Phase 19A.19 Site Tag behavioral data.
  realUserTechContext?: { patternCount: number; topFinding: string } | null;
  // Brief pre-synthesis context for specialized synthesizers (injected into executive summary).
  multilingualContext?: { findingCount: number; topFinding: string } | null;
  complianceContext?: { findingCount: number; topFinding: string; isHipaaRelevant: boolean } | null;
  ecommerceContext?: { findingCount: number; topFinding: string } | null;
  b2bContext?: { findingCount: number; topFinding: string } | null;
}

// ─── First-party context types ────────────────────────────────────────────────

/** Per-URL Core Web Vitals at p75 from real user measurement data (min 10 samples). */
export interface WebVitalEntry {
  url: string;
  samples: number;
  lcp75?: number;   // milliseconds
  cls75?: number;   // unitless (e.g. 0.08)
  inp75?: number;   // milliseconds
  ttfb75?: number;  // milliseconds
}

/** URL lists from the crawl pass, used to ground synthesizer findings in specific pages. */
export interface CrawlStatsContext {
  missingH1Urls: string[];
  missingMetaDescUrls: string[];
  thinContentUrls: string[];
  missingSchemaUrls: string[];
}

export interface BrandContext {
  brandId: string;
  brandName: string;
  services: string[];
  locations: string[];
  siteTagInstalled: boolean;
  siteTagDaysActive?: number | null;
}

/** Per-URL behavioral metrics over the trailing 30-day window. */
export interface BehavioralPageContext {
  url: string;
  bounceRate: number | null;          // 0–1 ratio of single-page sessions
  avgSessionDuration: number | null;  // seconds
  conversionCount: number;
  conversionValue: number;            // sum of conversionValue (monetary) in window
}

/** Aggregated behavioral data for all crawled pages. */
export interface BehavioralContext {
  windowDays: number;                 // always 30 for now
  pages: BehavioralPageContext[];     // only pages matching DFS crawl URLs
}

/** Per-page AI referral breakdown for top landing pages. */
export interface AiAttributionPageContext {
  url: string;
  aiVisits: number;
  conversions: number;
  attributedRevenue: number;
}

/** Site-level AI attribution context over trailing 30-day window. */
export interface AiAttributionContext {
  windowDays: number;                              // always 30
  totalAiReferrals: number;                        // count in trailing 30d
  totalConversions30d: number;                     // AI-attributed conversions in trailing 30d
  topPages: AiAttributionPageContext[];            // top 20 pages by AI visit count (30d)
  trendRatio: number | null;                       // recent-30d rate / prior-comparable rate; null if < 14 days of prior data
  topEngines: { engine: string; count: number }[]; // top 10 AI engines by session count (30d)
  referralsByDay?: Array<{ date: string; count: number }>; // last 30 days daily rollup for sparkline
}

// ─── Raw page data (from structural scanner) ──────────────────────────────────

export interface PageData {
  url: string;
  title?: string;
  h1?: string;
  metaDescription?: string;
  contentMarkdown?: string;
  statusCode: number;
  wordCount?: number;
  internalLinks: string[];
  externalLinks: string[];
  images: ImageData[];
  canonical?: string;
  hasSchema: boolean;
  schemaTypes: string[];
  isIndexable: boolean;
  redirectTarget?: string;
}

export interface ImageData {
  src: string;
  alt?: string;
  width?: number;
  height?: number;
  fileSizeKb?: number;
}

// ─── Structural scan summary ──────────────────────────────────────────────────

export interface SiteScanResult {
  pages: PageData[];
  totalPagesDiscovered: number;
  crawledAt: string;
  hasSitemap: boolean;
  hasRobotsTxt: boolean;
  sitemapUrl?: string;
  robotsUrl?: string;
  mobileFriendly?: boolean;
  coreWebVitals?: {
    lcp?: number;
    cls?: number;
    fid?: number;
  };
}

// ─── SEO Findings (output of analyzer) ───────────────────────────────────────

export interface SeoFindings {
  siteSize: {
    totalPages: number;
    crawlableDepth: number;
    hasSitemap: boolean;
    hasRobotsTxt: boolean;
    sitemapUrl?: string;
  };
  metaTitles: {
    total: number;
    missing: number;
    tooLong: number;    // > 60 chars
    tooShort: number;   // < 30 chars
    duplicates: string[];
    averageLength: number;
  };
  metaDescriptions: {
    total: number;
    missing: number;
    tooLong: number;    // > 160 chars
    tooShort: number;   // < 70 chars
    duplicates: string[];
    averageLength: number;
  };
  headings: {
    missingH1: number;
    multipleH1: number;
    pagesWithH1: number;
    deepStructureIssues: string[];
  };
  brokenLinks: {
    internal404s: string[];
    total: number;
  };
  images: {
    missingAlt: number;
    totalImages: number;
    oversizedCount: number;
    brokenCount: number;
  };
  schema: {
    typesDetected: string[];
    pagesWithSchema: number;
    percentCoverage: number;
    missingOpportunities: string[];
  };
  technical: {
    hasSitemap: boolean;
    hasRobotsTxt: boolean;
    canonicalIssues: string[];
    mobileFriendly: boolean | null;
    nonIndexablePages: number;
    redirectChains: string[];
  };
  content: {
    avgWordCount: number;
    thinContentPages: string[];  // pages < 300 words
    totalContentPages: number;
  };
  topPages: string[];  // top 5 pages by inbound link count
}

// ─── SEO Section (output of synthesizer) ─────────────────────────────────────

/** Behavioral engagement overlay for a URL-specific finding (first-party only). */
export interface BehavioralOverlay {
  bounceRate: number | null;
  avgSessionDuration: number | null;  // seconds
  conversions: number;
  conversionValue: number;
  estimatedLostConversionValue: number; // conversionValue × bounceRate heuristic
}

export interface SeoKeyFinding {
  title: string;
  detail: string;
  behavioralOverlay?: BehavioralOverlay; // present only when a URL match exists in behavioral data
}

export interface SeoActionImplementation {
  type?: "Schema" | "Meta" | "CTA" | "Content" | "Performance" | "Redirect";
  codeSnippet?: string;
  copyRecommendation?: string;
  implementationSteps?: string[];
}

export interface SeoAction {
  title: string;
  impact: "high" | "medium" | "low";
  effort: "hour" | "day" | "week";
  rationale: string;
  implementation?: SeoActionImplementation;
  phaseAssignment?: "week-1" | "weeks-2-4" | "month-2" | "month-3";
  effortHours?: number;
  expectedLiftPoints?: number;
}

export interface SeoQuickWin {
  title: string;
  estimatedTime: string;
}

/** AI search attribution performance panel — first-party audits only. */
export interface AiSearchPerformance {
  narrative: string;                                           // Claude-written
  totalReferrals30d: number;
  trendVsTrailing90d: number | null;                          // percent change vs prior 60d avg rate
  topAttributedPages: Array<{ url: string; aiVisits: number; conversions: number }>;
  topEngines: Array<{ engine: string; count: number }>;
  estimatedAttributedRevenue: number;
  referralsByDay?: Array<{ date: string; count: number }>;    // last 30 days daily rollup
}

// ─── Industry classification (from Haiku pre-call) ───────────────────────────

export interface IndustryClassification {
  industry: string;          // e.g. "healthcare-medical"
  subVertical: string;       // e.g. "cardiology-practice"
  audienceFraming: string;   // e.g. "patient acquisition and trust signals"
  relevantFrameworks: string[]; // e.g. ["YMYL", "local-medical-SEO"]
}

// ─── Methodology (how Claude evaluated the audit) ────────────────────────────

export interface AuditMethodology {
  factors: Array<{ factor: string; lookedAt: string }>;
}

// ─── Dimension scores (5-axis breakdown) ─────────────────────────────────────

export interface DimensionScores {
  technicalSeo: number;          // 0-90: crawlability, schema, mobile, indexing
  contentMetadata: number;       // 0-90: title/desc/H1 coverage and quality
  aiVisibility: number | null;   // 0-90 (1st-party referrals) or 0-70 (3rd-party public signals); null only in legacy/degraded audits
  conversionOptimization: number | null; // 0-90 (1st-party behavioral) or 0-70 (3rd-party proxy); null only in legacy/degraded audits
  userEngagement: number | null; // 0-90 (1st-party RUM) or 0-70 (3rd-party proxy); null only in legacy/degraded audits
}

// ─── Site Tag context ─────────────────────────────────────────────────────────

export interface SiteTagContext {
  installedAt: string | null;   // ISO timestamp of first event
  daysActive: number | null;    // days since first event
  state: "active-mature" | "active-fresh" | "silent";
}

// ─── Consulting-grade output types (additive, 3rd-party audits) ──────────────

export type DataSourceTag = "crawl" | "content" | "authority" | "serp" | "ai-surface" | "framework";

export interface PrioritizedFinding {
  rank: number;
  title: string;
  priority: "critical" | "high" | "medium" | "low";
  whatsWorking: string;
  whereItFallsShort: string;
  recommendedNextSteps: string[];
  affectedUrls?: string[];
  whatFirstPartyDataWouldAdd?: string; // 3rd-party only: what Site Tag would surface
  dataSourceWeave?: DataSourceTag[];   // which signal categories ground this finding
  // Non-seo categories surface specialized findings from deterministic synthesizers.
  // "tech" = real-user JS error patterns from Site Tag behavioral data.
  // "multilingual" = hreflang, language-region, and translation parity issues.
  // "compliance" = WCAG accessibility, GDPR/CCPA privacy, HIPAA (medical vertical only).
  // "ecommerce" = Product schema, faceted nav, variant canonicalization, category content.
  // "b2b" = funnel-stage coverage, pricing/case-study discoverability, comparison pages.
  category?: "seo" | "tech" | "multilingual" | "compliance" | "ecommerce" | "b2b";
}

export interface AdditionalFinding {
  title: string;
  assessment: string;
}

export interface SummaryTheme {
  theme: string;
  observation: string;
}

// ─── Signal Center ────────────────────────────────────────────────────────────
// 1st-party only — behavioral telemetry aggregated from Site Tag event tables.

export interface SignalCenterFrictionEvent {
  eventType: "rage_click" | "dead_click" | "form_error" | "quick_bounce" | "excessive_back";
  displayName: string;
  count: number;
  severity: "critical" | "high" | "medium" | "low";
  topAffectedPages: Array<{ url: string; count: number }>;
}

export interface SignalCenterFunnelStage {
  sessions: number;
  percent: number;
  dropoffFromPrior: number;
}

export interface SignalCenter {
  windowDays: number;
  totalSessions: number;
  dataConfidence: "high" | "moderate" | "low";

  topFrictionEvents: SignalCenterFrictionEvent[];

  conversionFunnel: {
    landing: SignalCenterFunnelStage;
    engagement: SignalCenterFunnelStage;
    intent: SignalCenterFunnelStage;
    conversion: SignalCenterFunnelStage;
    biggestDropoff: { from: string; to: string; percent: number };
    topDropoffPages: Array<{ url: string; stage: string; sessionsLost: number }>;
  };

  formAbandonment: {
    totalStarts: number;
    totalCompletes: number;
    abandonRate: number;
    topAbandonedFields: Array<{
      fieldName: string;
      abandonCount: number;
      abandonRate: number;
      medianTimeSpent: number;
      errorRate: number;
      recommendation: string;
    }>;
  } | null;

  channelMix: {
    phone: { count: number; share: number; conversionRate: number | null };
    form: { count: number; share: number; conversionRate: number | null };
    paperwork: { count: number; share: number; conversionRate: number | null };
    chat: { count: number; share: number; conversionRate: number | null };
  };

  scrollToConversion: {
    medianScrollDepthBeforeConversion: number;
    highScrollLowConvPages: Array<{ url: string; avgScroll: number; conversions: number }>;
    lowScrollHighConvPages: Array<{ url: string; avgScroll: number; conversions: number }>;
    recommendation: string;
  };

  deviceGeo: {
    deviceMix: {
      mobile: { sessions: number; share: number; conversionRate: number };
      desktop: { sessions: number; share: number; conversionRate: number };
      tablet: { sessions: number; share: number; conversionRate: number };
    };
    mobileDesktopDelta: number;
    topMetros: Array<{ city: string; region: string; sessions: number; conversionRate: number }>;
    geoConcentration: number;
  } | null;
}

// ─── Bilingual Content Audit ──────────────────────────────────────────────────

export interface BilingualAudit {
  detectedLanguages: Array<{ code: string; displayName: string; pageCount: number }>;
  primaryLanguage: string;
  dataConfidence: "high" | "moderate" | "low";

  languageCoverage: {
    totalPages: number;
    perLanguage: Array<{ code: string; pageCount: number; sharePercent: number }>;
  };

  contentParity: {
    primaryLanguagePageCount: number;
    perNonPrimaryLanguage: Array<{
      code: string;
      pagesWithEquivalent: number;
      pagesMissingEquivalent: number;
      parityPercent: number;
      topMissingPages: Array<{ primaryUrl: string; expectedNonPrimaryUrl: string }>;
    }>;
  };

  hreflangImplementation: {
    pagesWithHreflang: number;
    pagesShouldHaveHreflang: number;
    coveragePercent: number;
    bidirectionalCheckPassed: boolean | null;
    commonBugs: Array<{
      type: "missing_self_reference" | "wrong_code" | "missing_x_default" | "unidirectional" | "mismatch";
      description: string;
      affectedUrls: string[];
    }>;
    status: "complete" | "partial" | "missing";
  };

  conversionPathway: {
    perLanguage: Array<{
      code: string;
      sessions: number;
      conversions: number;
      conversionRate: number;
      channelMix: { phone: number; form: number; paperwork: number; chat: number };
    }>;
    aiAttributed: Array<{
      code: string;
      aiVisits: number;
      aiConversions: number;
      aiConversionRate: number;
      topEngines: Array<{ engine: string; visits: number; conversions: number }>;
    }>;
  } | null;

  aiCitationByLanguage: {
    perLanguage: Array<{
      code: string;
      aiVisits: number;
      sharePercent: number;
      topCitedPages: Array<{ url: string; aiVisits: number }>;
      perEngine: Array<{ engine: string; visits: number }>;
    }>;
  } | null;

  contentQuality: {
    perNonPrimaryLanguage: Array<{
      code: string;
      avgWordCount: number;
      primaryLanguageAvgWordCount: number;
      depthRatio: number;
      hasLanguageSpecificSchema: boolean;
      bilingualCtaStatus: "present" | "partial" | "absent";
      bilingualCtaRecommendation: string;
    }>;
  };
}

// ─── Competitor Deep Dive ─────────────────────────────────────────────────────

export interface CompetitorAnalysis {
  detectedCompetitors: Array<{
    domain: string;
    appearsInQueries: string[];
    avgRankPosition: number;
    domainAuthority: number | null;
    referringDomains: number | null;
    totalBacklinks: number | null;
    detectedSchema: Array<{ type: string; present: boolean }>;
    topContentTopics: string[];
    pagesScraped: number;
    keyDifferentiator: string;
  }>;
  competitiveGapMatrix: {
    dimensions: Array<{
      name: string;
      brandValue: string | number;
      competitorAValue: string | number;
      competitorBValue: string | number;
      competitorCValue: string | number;
      brandRank: 1 | 2 | 3 | 4;
      gapMagnitude: "critical" | "high" | "moderate" | "low";
    }>;
  };
  dataQuality: "high" | "moderate" | "low";
}

// ─── Schema Opportunity Forecast ─────────────────────────────────────────────

export interface SchemaOpportunityForecast {
  industryVertical: string;
  industrySubVertical: string;
  prioritySchemaTypes: Array<{
    schemaType: string;
    priority: "critical" | "high" | "moderate" | "low";
    present: boolean;
    presentOnPages: string[];
    expectedImpact: string;
    estimatedLiftPercent: number;
    implementationDifficulty: "easy" | "moderate" | "hard";
    implementationNote: string;
  }>;
  currentCoveragePercent: number;
  potentialCoveragePercent: number;
  cumulativeLiftEstimate: number;
  hasSchemaConflicts: boolean;
  schemaConflicts: Array<{ url: string; issue: string }>;
}

// ─── Strategic Roadmap ────────────────────────────────────────────────────────

export interface StrategicRoadmap {
  phases: Array<{
    phaseName: string;
    timeframe: string;
    theme: string;
    actions: Array<{
      title: string;
      type: string;
      effortHours: number;
      expectedLiftPoints: number;
    }>;
    cumulativeEffortHours: number;
    cumulativeLiftPoints: number;
    projectedScoreAtEndOfPhase: number;
    successMetrics: string[];
  }>;
  totalEffortHours: number;
  totalLiftPoints: number;
  finalProjectedScore: number;
}

// ─── AI Engine Personality Analysis ──────────────────────────────────────────

export interface EnginePersonalityCard {
  engineId: string;
  displayName: string;
  parentCompany: string;
  citationStyle: string;
  preferredContentTypes: string[];
  schemaPriorities: string[];
  eAtSensitivity: "high" | "medium" | "low";
  recencyBias: "high" | "medium" | "low";
  optimizationApproach: [string, string, string, string];
  firstPartyOverlay: {
    sessions30d: number;
    conversions30d: number;
    conversionRate: number | null;
    topLandingPages: Array<{ url: string; aiVisits: number; conversions: number }>;
  } | null;
}

export interface AiEnginePersonalityAnalysis {
  engines: EnginePersonalityCard[];
  topEngineId: string | null;   // engine with most sessions (1st-party only)
}

// ─── Page Strategic Pass ─────────────────────────────────────────────────────

export interface PageHealthCard {
  url: string;
  pageType: "homepage" | "contact" | "service" | "product" | "about" | "blog" | "pricing" | "faq" | "other";
  healthScore: number;   // 0-100 composite
  selectionReason: string;
  structuralSignals: {
    hasH1: boolean;
    h1Text: string | null;
    hasSchema: boolean;
    schemaTypes: string[];
    wordCount: number | null;
    hasCTA: boolean | null;
    ctaExamples: string[];
    hasPhoneClick: boolean | null;
    hasFAQ: boolean | null;
    internalLinkCount: number;
    isIndexable: boolean;
    metaDescription: string | null;
  };
  behavioralSignals: {
    bounceRate: number | null;
    avgSessionDuration: number | null;
    conversionCount: number;
    conversionValue: number;
  } | null;
  aiSignals: {
    aiVisits30d: number;
    conversions30d: number;
  } | null;
  topIssues: Array<{
    severity: "critical" | "high" | "medium" | "low";
    issue: string;
    fix: string;
  }>;
  topRecommendation: string;
  crossReferences: Array<{ sectionId: string; label: string }>;
}

export interface PageStrategicPass {
  pages: PageHealthCard[];
}

// ─── Industry Benchmark Comparison ───────────────────────────────────────────

export interface IndustryBenchmarkComparison {
  industry: string;
  industryDisplayName: string;
  dimensions: Array<{
    name: string;
    brandValue: number;
    industryAverage: number;
    industryP25: number;
    industryP75: number;
    brandPercentile: number;
    brandStanding: "top-25" | "top-50" | "bottom-50" | "bottom-25";
    gapToAverage: number;
    gapToTopQuartile: number;
  }>;
  overallPercentile: number;
  benchmarkConfidence: "high" | "moderate" | "low";
}

// ─── AI Source Attribution Comparison ────────────────────────────────────────

export interface AttributionDimension {
  dimension: string;
  publicSignalPrediction: {
    value: number | string;
    method: string;
    confidence: "low" | "moderate" | "high";
  };
  firstPartyActual: {
    value: number | string;
    measurementMethod: string;
    sampleSize: number;
  };
  deltaPercent: number;
  deltaDirection: "predicted_overestimated" | "predicted_underestimated" | "aligned";
  explanation: string;
}

export interface AiSourceAttributionComparison {
  hasFirstPartyData: boolean;
  comparisonWindow: { startDate: Date; endDate: Date; daysCovered: number };
  predictionVsActual: AttributionDimension[];
  topInsights: Array<{
    insight: string;
    supportingDimension: string;
    patentRelevance: string;
  }>;
  overallGapMagnitude: "minimal" | "moderate" | "significant";
  overallGapNarrative: string;
}

// ─── Behavioral Action Bridge ─────────────────────────────────────────────────

export interface BehavioralActionBridge {
  hasBehavioralOverlay: boolean;
  enhancedActions: Array<{
    originalActionTitle: string;
    behavioralEvidence: Array<{
      signal: string;
      source: "signal-center" | "page-strategic-pass" | "ai-attribution";
      dataPoints: Record<string, number>;
    }>;
    quantifiedImpactEstimate: {
      metric: string;
      currentValue: number;
      projectedValue: number;
      liftRange: { min: number; max: number };
      confidence: "low" | "moderate" | "high";
    };
    rewrittenActionDescription: string;
  }>;
  newBehavioralFindings: Array<{
    title: string;
    severity: "critical" | "high" | "moderate" | "low";
    description: string;
    behavioralEvidence: string[];
    affectedUrls: string[];
    recommendation: string;
  }>;
  topBehavioralPatterns: Array<{
    pattern: string;
    impact: string;
    relatedActions: string[];
  }>;
}

// ─── AI Snippet Eligibility ───────────────────────────────────────────────────

export interface SnippetFeatureEligibility {
  feature: string;
  currentlyEligible: boolean;
  eligibilityStatus: "eligible" | "partial" | "not_eligible";
  missingFactors: string[];
  implementationDifficulty: "easy" | "moderate" | "hard";
  estimatedTraffic: "high" | "moderate" | "low";
}

export interface AiSnippetEligibility {
  perQuery: Array<{
    query: string;
    serpFeaturesPresent: Array<"featured_snippet" | "faq" | "knowledge_panel" | "image_pack" | "video_carousel" | "people_also_ask" | "local_pack" | "ai_overview" | "product_carousel" | "reviews_carousel">;
    brandRanking: number | null;
    perFeatureEligibility: SnippetFeatureEligibility[];
  }>;
  topOpportunities: Array<{
    query: string;
    feature: string;
    rationale: string;
    quickestPath: string;
    estimatedImpact: string;
  }>;
  aggregateStats: {
    totalQueriesAnalyzed: number;
    queriesWithEligibleFeatures: number;
    totalFeaturesPresent: number;
    totalFeaturesEligible: number;
    eligibilityRatePercent: number;
  };
}

// ─── Multi-Touch AI Attribution Path ─────────────────────────────────────────

export interface MultiTouchAiPath {
  hasFirstPartyData: boolean;
  topConversionPaths: Array<{
    pathDescription: string;
    pathSteps: Array<{
      stepType: "ai_engine" | "page" | "conversion";
      identifier: string;
      timestamp?: string;
      device?: string;
    }>;
    conversionCount: number;
    avgTimeToConversion: number;
    sessionsInvolved: number;
    crossDevice: boolean;
  }>;
  pathComplexityDistribution: {
    singleTouch: { count: number; percent: number; avgConversionRate: number };
    twoTouch: { count: number; percent: number; avgConversionRate: number };
    multiTouch: { count: number; percent: number; avgConversionRate: number };
  };
  topEntryChannels: Array<{
    channel: string;
    conversionsAsFirstTouch: number;
    conversionsAsLastTouch: number;
    avgPositionInPath: number;
    conversionAssistRate: number;
  }>;
  topConversionTriggers: Array<{
    pageUrl: string;
    conversionCount: number;
    avgPriorPageviews: number;
    topReferringEngines: string[];
  }>;
  crossDeviceJourneys: {
    detected: number;
    percentOfConversions: number;
    avgDaysSpanned: number;
    typicalPattern: string;
  };
}

// ─── Revenue Attribution (Phase 8) ───────────────────────────────────────────

export interface RevenueAttribution {
  hasRevenueTracking: boolean;
  windowDays: number;
  dataConfidence: "high" | "moderate" | "low" | "insufficient";
  aggregateMetrics: {
    totalRevenueTracked: number;
    totalConversionsWithRevenue: number;
    avgRevenuePerConversion: number;
    conversionsMissingRevenue: number;
    revenueTrackingCoveragePercent: number;
  };
  revenueByChannel: Array<{
    channelName: string;
    revenue: number;
    sharePercent: number;
    conversions: number;
    avgRevenuePerConversion: number;
    deltaVsPrior30d: {
      revenueDelta: number;
      revenueDeltaPercent: number;
      conversionsDelta: number;
    } | null;
  }>;
  revenueByAiEngine: Array<{
    engineName: string;
    revenue: number;
    shareOfAiRevenuePercent: number;
    shareOfTotalRevenuePercent: number;
    conversions: number;
    avgRevenuePerConversion: number;
    highestRevenueLandingPage: string | null;
  }>;
  topRevenuePages: Array<{
    pageUrl: string;
    revenue: number;
    conversions: number;
    avgRevenuePerConversion: number;
    dominantReferringChannel: string;
    sharePercent: number;
  }>;
  insights: Array<{
    insight: string;
    supportingMetric: string;
    businessImplication: string;
  }>;
  patentRelevance: string;
  futureCapabilities: {
    cacAvailable: boolean;
    ltvAvailable: boolean;
    cacNote: string;
    ltvNote: string;
  };
}

// ─── Predictive Conversion Scoring (Phase 9) ─────────────────────────────────

export type ScoreBand = "very_low" | "low" | "moderate" | "high" | "very_high";

export interface PredictiveConversionScoring {
  windowDays: number;
  totalScoredSessions: number;
  avgScore: number;
  scoreDistribution: Record<ScoreBand, number>; // count per band
  conversionRateByBand: Partial<Record<ScoreBand, number>>; // % that converted
  scoreByChannel: Array<{
    channelName: string;
    avgScore: number;
    sessionCount: number;
    topBand: ScoreBand;
  }>;
  scoreByAiEngine: Array<{
    engineName: string;
    avgScore: number;
    sessionCount: number;
  }>;
  topScoringPages: Array<{
    pageUrl: string;
    avgScoreBoost: number;
    visitCount: number;
  }>;
  liveSessionsSnapshot: {
    activeLast30Min: number;
    highIntentCount: number;  // score >= 61
    avgScoreActive: number;
  };
  insights: Array<{
    insight: string;
    supportingMetric: string;
    businessImplication: string;
  }>;
  patentRelevance: string;
}

// ─── Conversion Heat Map (Phase 10) ──────────────────────────────────────────

export interface ConversionHeatMap {
  hasFirstPartyData: boolean;
  hasClickData: boolean;
  windowDays: number;
  dataConfidence: "high" | "moderate" | "low" | "insufficient";
  perPage: Array<{
    pageUrl: string;
    pageType: "homepage" | "service" | "product" | "contact" | "other";
    totalClicks: number;
    totalSessions: number;
    clicksPerSession: number;
    clickDensityRegions: Array<{
      regionLabel: string;
      clickCount: number;
      sharePercent: number;
      hasConversionPath: boolean;
    }>;
    topClickedElements: Array<{
      selector: string;
      elementLabel: string;
      clickCount: number;
      conversionContribution: number;
      conversionContributionPercent: number;
    }>;
    deadZones: Array<{
      regionLabel: string;
      pageviewCount: number;
      clickCount: number;
      missedClickRatio: number;
      recommendation: string;
    }>;
    hotZones: Array<{
      regionLabel: string;
      clickCount: number;
      isCurrentlyCta: boolean;
      recommendation: string;
    }>;
    currentCtaPlacements: Array<{
      selector: string;
      elementLabel: string;
      regionLabel: string;
      clickCount: number;
      conversionContribution: number;
      effectivenessScore: number;
    }>;
    recommendedCtaPlacements: Array<{
      regionLabel: string;
      rationale: string;
      expectedLift: string;
    }>;
  }>;
  aggregateInsights: Array<{
    insight: string;
    affectedPages: string[];
    actionRecommendation: string;
  }>;
  patentRelevance: string;
}

// ─── Executive Brief (Phase 6) ────────────────────────────────────────────────

export interface ExecutiveBrief {
  headline: {
    auditScore: number;
    scoreLabel: string;
    industryPosition: string;
    keyMetric: string;
    narrative: string;
  };
  crossCuttingThemes: Array<{
    title: string;
    description: string;
    affectedAreas: string[];
  }>;
  criticalFinding: {
    title: string;
    framing: string;
    affectedBusinessOutcome: string;
    primaryRemediation: string;
  };
  topFindings: Array<{
    rank: number;
    severity: "critical" | "high" | "moderate";
    title: string;
    impactSummary: string;
    quantifiedOpportunity: string | null;
    primaryRecommendation: string;
    affectedSection: string;
  }>;
  topQuickWins: Array<{
    rank: number;
    title: string;
    effortHours: number;
    expectedLift: string;
    implementationNote: string;
    whyFirst: string;
  }>;
  ninetyDayOutlook: {
    currentScore: number;
    projectedScore30d: number;
    projectedScore60d: number;
    projectedScore90d: number;
    maxPossibleScore: number;
    totalEffortHours: number;
    phaseHighlights: Array<{
      phaseName: string;
      primaryFocus: string;
      keyMilestone: string;
    }>;
    confidenceNote: string;
  };
  closingPage: {
    type: "first_party_preview" | "behavioral_highlights";
    firstPartyPreview?: {
      narrative: string;
      previewCallouts: Array<{
        currentEstimate: string;
        firstPartyReveal: string;
        businessRelevance: string;
      }>;
      ctaText: string;
    };
    behavioralHighlights?: {
      narrative: string;
      topInsights: Array<{
        insight: string;
        supportingData: string;
        connectedAction: string;
      }>;
      patentRelevance: string;
    };
  };
}

export interface SeoSection {
  healthScore: number;              // 0–100
  narrative: string;                // executive summary prose (backward compat)
  keyFindings: SeoKeyFinding[];     // 4–6 items (backward compat)
  priorityActions: SeoAction[];     // 5–8 items (backward compat)
  quickWins: SeoQuickWin[];         // 2–4 items
  scoringBreakdown: {
    critical: number;
    high: number;
    medium: number;
    low: number;
  };
  // Consulting-grade fields (additive — absent on incomplete audits)
  displayName?: string;
  prioritizedFindings?: PrioritizedFinding[];
  additionalFindings?: AdditionalFinding[];
  summaryThemes?: SummaryTheme[];
  inferredIndustry?: string;
  // First-party enrichments — absent (not null) on 3rd-party audits
  aiSearchPerformance?: AiSearchPerformance;
  brandEcho?: { brandName: string; services: string[]; locations: string[] };
  dimensionScores?: DimensionScores;
  siteTagContext?: SiteTagContext;
  methodology?: AuditMethodology;
  industryFramework?: IndustryClassification;
  industryContext?: import("./synthesizers/industry-classifier").IndustryContext;
  // Competitive intelligence — populated from SERP analysis (3rd-party and 1st-party)
  competitiveLandscape?: {
    topCompetitors: string[];
    topCompetitorDetails?: Array<{
      domain: string;
      sharedKeywords?: number;
      topBrandLossQuery?: string;  // "[query]: brand #N vs competitor #M"
    }>;
    aiOverviewCoveragePercent: number;   // % of industry queries that trigger an AI Overview
    aiOverviewBrandCitationRate: number; // % of AI Overviews that mention the brand
    serpShareOfVoice?: number;           // % of top-10 positions owned by brand (future)
  };
  backlinkProfile?: {
    referringDomains: number | null;
    totalBacklinks: number | null;
    domainRank: number | null;
    spamScore?: number | null;
    gained30d?: number | null;
    lost30d?: number | null;
    toxicityFlag?: boolean;
    anchorDistribution?: {
      branded?: number;   // percent
      exact?: number;
      partial?: number;
      generic?: number;
      url?: number;
    };
    topReferrers?: Array<{
      domain: string;
      domainRank: number | null;
      firstSeen?: string;         // ISO date string
      spamScore?: number | null;
    }>;
  };
  publicAiVisibility?: {
    queriesWithAiOverview: number;
    totalQueriesChecked: number;
    brandMentionedInAiOverview: boolean;
    overallCitabilityScore?: number;    // composite 0-100
    aiOverviewDetails: Array<{
      query: string;
      brandMentioned: boolean;
      snippet: string | null;
      competitors?: string[];           // competitor domains mentioned in this overview
    }>;
  };
  // 1st-party enrichments from organic search integration (present when GSC is connected)
  organicSearchSummary?: {
    totalClicks30d: number;
    totalImpressions30d: number;
    avgCtr: number;
    avgPosition: number;
    narrative?: string;
    topQueries: Array<{ query: string; clicks: number; impressions: number; position: number }>;
    topPages: Array<{ page: string; clicks: number; impressions: number; position: number }>;
  };
  // AI conversion funnel — 1st-party only; derived from aiAttributionContext
  aiConversionAttribution?: {
    totalAiReferrals30d: number;
    totalAiConversions30d: number;
    aiConversionRate: number;              // percent, rounded to 1 decimal
    topConvertingPages: Array<{ url: string; aiVisits: number; conversions: number }>;
    topConvertingEngines: Array<{ engine: string; count: number; conversionRate?: number }>;
    conversionGap?: {
      infrastructureGapPages?: string[];   // URLs receiving AI traffic without conversion pathway
    };
  };
  // Signal Center — 1st-party only; behavioral telemetry from Site Tag
  signalCenter?: SignalCenter | null;
  // Bilingual Content Audit — present for bilingual brands (1st and 3rd party)
  bilingualAudit?: BilingualAudit | null;
  // Competitor Deep Dive — populated when SERP competitor data is available
  competitorAnalysis?: CompetitorAnalysis | null;
  schemaOpportunityForecast?: SchemaOpportunityForecast | null;
  strategicRoadmap?: StrategicRoadmap | null;
  industryBenchmarkComparison?: IndustryBenchmarkComparison | null;
  pageStrategicPass?: PageStrategicPass | null;
  aiEnginePersonalityAnalysis?: AiEnginePersonalityAnalysis | null;
  aiSourceAttributionComparison?: AiSourceAttributionComparison | null;
  behavioralActionBridge?: BehavioralActionBridge | null;
  eeatAudit?: import("./data-sources/eeat-audit").EeatAudit | null;
  voiceSearchEligibility?: import("../voice-search-eligibility/types").VoiceSearchEligibility | null;
  aiSnippetEligibility?: AiSnippetEligibility | null;
  multiTouchAiPath?: MultiTouchAiPath | null;
  revenueAttribution?: RevenueAttribution | null;
  predictiveConversionScoring?: PredictiveConversionScoring | null;
  conversionHeatMap?: ConversionHeatMap | null;
  aiSearchVerification?: AiSearchVerification | null;
  lostOpportunityCalculation?: LostOpportunityCalculation | null;
  liveVisualAnnotations?: LiveVisualAnnotations | null;
  competitorVisualComparison?: CompetitorVisualComparison | null;
  brandAuthorityScore?: import("../authority/types").BrandAuthorityScore | null;
  snippetCaptureStrategy?: import("../snippet-capture/types").SnippetCaptureStrategy | null;
  mobileFirstAudit?: import("../mobile-first/types").MobileFirstAudit | null;
  pageSpeedInsights?: import("../page-speed/types").PageSpeedInsights | null;
  executiveBrief?: ExecutiveBrief | null;
  // 3rd-party upsell teaser — absent on 1st-party audits
  lockedFirstPartyTeaser?: {
    whatYouAreMissing: string[];
    siteTagInstallUrl: string;
    proofPointMetric: string;
    estimatedAiSessionsRange?: { min: number; max: number };
  };
  /**
   * Crawl failure reason -- present only on degraded-mode audits.
   * Matches CrawlErrorReason values from the structural scanner.
   * Used to render a specific explanation in the limited-mode banner.
   */
  crawlErrorReason?: string;
  /**
   * Engineering-only metadata. MUST NOT be rendered by any dashboard component or PDF template.
   * Vendor names may appear here for engineering clarity.
   */
  internal?: {
    dataSourcesUsed: {
      crawl: boolean;
      content: boolean;
      authority: boolean;
      serp: boolean;
      framework: boolean;
    };
    costLog?: {
      crawl: number;
      firecrawl: number;
      dfsBacklinks: number;
      dfsSerp: number;
      haiku: number;
      synth: number;
      total: number;
    };
    auditType: "1st" | "3rd";
  };
}

// ─── Lost Opportunity Calculator ─────────────────────────────────────────────

export interface LostOpportunityEstimate {
  findingTitle: string;
  findingSection: string;
  affectedQueryVolumeMonthly: number;
  estimatedRecoverableTrafficPercent: number;
  estimatedRecoverableSessionsMonthly: number;
  estimatedConversionsMonthly: number;
  estimatedRevenueMonthly: number;
  confidenceLevel: "high" | "moderate" | "low";
  methodologyNote: string;
}

export interface LostOpportunityCalculation {
  hasCalculation: boolean;
  windowMonths: 1;
  confidence: "high" | "moderate" | "low";
  industryBaselines: {
    industryVertical: string;
    avgCustomerValue: number;
    avgConversionRate: number;
    sourceNote: string;
  };
  perFindingEstimates: LostOpportunityEstimate[];
  aggregateOpportunity: {
    totalMonthlyOpportunityUsd: number;
    annualizedOpportunityUsd: number;
    topThreeMonthlyImpact: Array<{
      findingTitle: string;
      monthlyImpactUsd: number;
      timeToImplement: string;
    }>;
  };
  disclosures: {
    estimationDisclosure: string;
    assumptionsNote: string;
    confidenceFactors: string[];
  };
}

// ─── Visual Annotation (Phase 12) ────────────────────────────────────────────

export interface AnnotationSpec {
  id: string;
  severity: "critical" | "high" | "moderate" | "low" | "positive";
  boundingBox: { x: number; y: number; width: number; height: number };
  shape: "box" | "arrow" | "circle";
  color: string;
  number: number;
  shortLabel: string;
  description: string;
  linkedFindingTitle: string | null;
  linkedAction: string | null;
}

export interface PerPageAnnotation {
  pageUrl: string;
  pageLabel: string;
  pageType: "homepage" | "service" | "product" | "category" | "about" | "contact" | "blog" | "other";
  desktopScreenshotUrl: string;
  desktopAnnotatedScreenshotUrl: string;
  mobileScreenshotUrl: string;
  annotations: AnnotationSpec[];
  annotationCount: number;
  severityBreakdown: {
    critical: number;
    high: number;
    moderate: number;
    low: number;
    positive: number;
  };
}

export interface LiveVisualAnnotations {
  hasAnnotations: boolean;
  windowDate: string;
  perPageAnnotations: PerPageAnnotation[];
  aggregateInsights: {
    totalAnnotations: number;
    pagesWithCriticalIssues: number;
    topPriorityAnnotations: Array<{
      annotationId: string;
      pageUrl: string;
      severity: string;
      shortLabel: string;
      description: string;
    }>;
    strongestPage: { url: string; label: string; annotationCount: number; positiveAnnotationCount: number } | null;
    weakestPage: { url: string; label: string; criticalCount: number; highCount: number } | null;
  };
  patentRelevance: string;
  costMetrics: {
    totalScreenshotsCaptured: number;
    totalAnnotationsGenerated: number;
    estimatedCostUsd: number;
    runtimeSeconds: number;
  };
}

export interface VisualComparisonDifference {
  number: number;
  category: "cta" | "social_proof" | "trust_signals" | "content_depth" | "navigation" | "visual_design";
  brandObservation: string;
  competitorObservation: string;
  impact: "critical" | "high" | "moderate" | "low";
}

export interface CompetitorVisualComparison {
  hasComparison: boolean;
  windowDate: string;
  comparisons: Array<{
    competitorName: string;
    competitorUrl: string;
    competitorRelevanceScore: number;
    homepageComparison: {
      brandScreenshotUrl: string | null;
      competitorScreenshotUrl: string | null;
      sideBySideUrl: string | null;
      differences: VisualComparisonDifference[];
    };
    servicePageComparison: {
      brandPageUrl: string | null;
      competitorPageUrl: string | null;
      brandScreenshotUrl: string | null;
      competitorScreenshotUrl: string | null;
      sideBySideUrl: string | null;
      differences: VisualComparisonDifference[] | null;
    } | null;
    summaryNarrative: string;
  }>;
  topDifferenceCategories: Array<{
    category: string;
    occurrenceCount: number;
    summary: string;
  }>;
  patentRelevance: string;
  costMetrics: {
    totalScreenshotsCaptured: number;
    runtimeSeconds: number;
  };
}

// ─── AI Search Verification ───────────────────────────────────────────────────

/** Re-export the core result types so audit consumers only import from types.ts */
export type {
  VerificationResult,
  EngineQueryResult,
  EngineSummary,
  BrandVisibilitySummary,
} from "../ai-search-verification/agent";

/** Audit-level wrapper that extends VerificationResult with synthesizer context. */
export type AiSearchVerification = import("../ai-search-verification/agent").VerificationResult & {
  /** Prose narrative generated by the synthesizer for inclusion in the audit report. */
  auditContextNarrative: string;
  /** How actual results compare to inferred predictions (e.g. low domain authority → low AI visibility). */
  comparisonToPredictions: string;
};

// ─── Error types ─────────────────────────────────────────────────────────────

export class AuditDataSourceError extends Error {
  constructor(
    message: string,
    public readonly source: string,
    public readonly cause?: unknown,
  ) {
    super(message);
    this.name = "AuditDataSourceError";
  }
}

export class AuditSynthesisError extends Error {
  constructor(message: string, public readonly cause?: unknown) {
    super(message);
    this.name = "AuditSynthesisError";
  }
}