/**
 * MOAT Analysis Pipeline
 * Parallel two-call pipeline for AI-powered competitive advantage analysis.
 *
 * The analysis is partitioned into two INDEPENDENT top-level section groups
 * (core moat dimensions vs. strategic/enhanced sections — see MOAT_CORE_SECTIONS
 * and MOAT_STRATEGIC_SECTIONS). They are generated CONCURRENTLY with
 * Promise.allSettled and merged, roughly halving wall-clock time versus the
 * previous single 32k-token call and reducing truncation. A single targeted
 * follow-up call fills any enhanced section still missing after the merge (rare).
 */

import { generateWithAI } from '../../utils/aiProvider';
import {
  MoatAnalysisInputs,
  MoatAnalysisOutput,
  MoatSectionScore,
  buildMoatAnalysisPrompt,
  MOAT_CORE_SECTIONS,
  MOAT_STRATEGIC_SECTIONS,
} from './moatAnalysisPrompts';
import { parseJsonFromAI } from './parseJsonFromAI';

export interface MoatAnalysisPipelineResult {
  analysis: MoatAnalysisOutput;
  pipelineVersion: string;
  provider: string;
  aiModel: string;
  tokensUsed: number;
  inputTokens: number;
  outputTokens: number;
  processingTimeMs: number;
  latencyMs: number;
  overallConfidence: number;
  finishReason: string;
  apiKeyMasked?: string;
}

// Default values for missing moat sections
const DEFAULT_MOAT_SECTION: MoatSectionScore = {
  score: 1,
  level: 'none',
  summary: 'Insufficient data to assess this moat dimension.',
  strengths: ['Unable to assess — more business data needed'],
  weaknesses: ['Analysis data unavailable'],
  recommendations: ['Gather more business data to assess this dimension'],
};

export class MoatAnalysisPipeline {
  private inputs: MoatAnalysisInputs;
  private progressCallback: (progress: number, step: string) => void;
  private startTime: number;
  // BUG #138: forwarded to every generateWithAI call so generation uses the
  // organization's configured AI provider/keys (and subscription rules) instead
  // of falling back to the default/env provider chain.
  private userId?: string;

  // Token/provider tracking accumulated across all generateWithAI calls.
  private totalTokens = 0;
  private totalInputTokens = 0;
  private totalOutputTokens = 0;
  private lastProvider = 'unknown';
  private lastAiModel = 'unknown';
  private lastFinishReason: string | null = null;
  private lastApiKeyMasked: string | null = null;

  static readonly PIPELINE_VERSION = '2.0';

  constructor(inputs: MoatAnalysisInputs, progressCallback?: (progress: number, step: string) => void, userId?: string) {
    this.inputs = inputs;
    this.progressCallback = progressCallback || (() => {});
    this.startTime = Date.now();
    this.userId = userId;
  }

  /** Accumulate token usage + provider/model metadata from an AI response. */
  private accumulate(response: any): void {
    if (!response) return;
    if (response.provider) this.lastProvider = response.provider;
    if (response.model) this.lastAiModel = response.model;
    this.totalTokens += response.tokenUsage?.totalTokens ?? 0;
    this.totalInputTokens += response.tokenUsage?.inputTokens ?? 0;
    this.totalOutputTokens += response.tokenUsage?.outputTokens ?? 0;
    if (response.finishReason) this.lastFinishReason = response.finishReason;
    if (response.keyUsed) this.lastApiKeyMasked = response.keyUsed;
  }

  async run(): Promise<MoatAnalysisPipelineResult> {
    const pipelineStart = Date.now();

    // Single API call — generate the ENTIRE analysis in one shot
    this.progressCallback(20, 'Generating comprehensive MOAT analysis...');
    const analysis = await this.generateAnalysis();

    if (!analysis) {
      throw new Error('MOAT analysis generation failed — no valid response from AI');
    }

    // Validate and fill in any missing sections
    this.progressCallback(85, 'Validating output...');
    const validated = this.validateAndEnrich(analysis);

    this.progressCallback(95, 'Finalising...');
    const pipelineEnd = Date.now();

    return {
      analysis: validated,
      pipelineVersion: MoatAnalysisPipeline.PIPELINE_VERSION,
      provider: this.lastProvider,
      aiModel: this.lastAiModel,
      tokensUsed: this.totalTokens,
      inputTokens: this.totalInputTokens,
      outputTokens: this.totalOutputTokens,
      processingTimeMs: pipelineEnd - pipelineStart,
      latencyMs: pipelineEnd - this.startTime,
      overallConfidence: validated.metadata?.confidenceScore || 0.7,
      finishReason: this.lastFinishReason || 'stop',
      apiKeyMasked: this.lastApiKeyMasked || undefined,
    };
  }

  private async generateAnalysis(): Promise<MoatAnalysisOutput | null> {
    // Build two scoped prompts and generate them CONCURRENTLY. The core moat
    // dimensions and the strategic/enhanced sections are independent, so this
    // roughly halves wall-clock time versus one 32k-token call. Mirrors the
    // Promise.allSettled pattern used by interview-media-prep and speaking-engagement.
    const corePrompt = buildMoatAnalysisPrompt(this.inputs, MOAT_CORE_SECTIONS);
    const strategicPrompt = buildMoatAnalysisPrompt(this.inputs, MOAT_STRATEGIC_SECTIONS);

    const coreTask = (async () => {
      const t0 = Date.now();
      const r = await generateWithAI(corePrompt.userPrompt, corePrompt.systemPrompt, corePrompt.maxTokens, 0.85, 'json', undefined, undefined, this.userId);
      console.log(`[MoatAnalysis-PERF] core sections AI call: ${Date.now() - t0}ms`);
      return r;
    })();

    const strategicTask = (async () => {
      const t0 = Date.now();
      const r = await generateWithAI(strategicPrompt.userPrompt, strategicPrompt.systemPrompt, strategicPrompt.maxTokens, 0.85, 'json', undefined, undefined, this.userId);
      console.log(`[MoatAnalysis-PERF] strategic sections AI call: ${Date.now() - t0}ms`);
      return r;
    })();

    // BUG #137: advance real progress as each independent call lands, instead of
    // parking at 20% for the entire (longest) generation. Based on actual call
    // completion — not a fabricated timer.
    let landedCalls = 0;
    const noteCallLanded = () => {
      landedCalls++;
      const pct = 20 + Math.round((landedCalls / 2) * 55); // 20 -> ~75
      this.progressCallback(pct, landedCalls < 2 ? 'Analysing competitive dimensions...' : 'Merging analysis sections...');
    };

    const genStart = Date.now();
    const [coreOutcome, strategicOutcome] = await Promise.allSettled([
      coreTask.then((r) => { noteCallLanded(); return r; }),
      strategicTask.then((r) => { noteCallLanded(); return r; }),
    ]);
    console.log(`[MoatAnalysis-PERF] both AI calls settled: ${Date.now() - genStart}ms`);

    // Merge the two halves. Each half is parsed independently so a failure or
    // unparseable response in one does not discard the other.
    const merged: Record<string, any> = {};
    let anySucceeded = false;

    const absorb = (
      outcome: PromiseSettledResult<any>,
      label: string,
    ): void => {
      if (outcome.status === 'rejected') {
        console.warn(`[MoatAnalysis-Pipeline] ${label} call failed:`, outcome.reason?.message || outcome.reason);
        return;
      }
      const response = outcome.value;
      this.accumulate(response);
      if (!response || !response.content) {
        console.warn(`[MoatAnalysis-Pipeline] ${label} call returned no content`);
        return;
      }
      const parsed = parseJsonFromAI(response.content);
      if (!parsed) {
        console.warn(`[MoatAnalysis-Pipeline] Failed to parse ${label} response as JSON (length: ${response.content.length})`);
        return;
      }
      for (const [key, value] of Object.entries(parsed)) {
        // Prefer the first non-empty metadata we see; otherwise take each key once.
        if (key === 'metadata' && merged.metadata) continue;
        merged[key] = value;
      }
      anySucceeded = true;
    };

    absorb(coreOutcome, 'core sections');
    absorb(strategicOutcome, 'strategic sections');

    if (!anySucceeded) {
      console.warn('[MoatAnalysis-Pipeline] Both generation calls failed or returned unparseable content');
      return null;
    }

    // Safety net: if any critical enhanced section is still missing after the
    // merge (e.g. one half truncated), make a single targeted follow-up to fill
    // just those keys. Rare now that each call emits ~half the payload.
    const enhancedSections = [
      'competitiveAdvantageSummary',
      'riskAssessment',
      'kpiRecommendations',
      'priorityMatrix',
      'growthRoadmap',
    ];
    const missingSections = enhancedSections.filter(key =>
      !merged[key] || typeof merged[key] !== 'object'
    );

    if (missingSections.length > 0) {
      console.warn('[MoatAnalysis-Pipeline] Sections still missing after merge:', missingSections.join(', '));
      console.warn('[MoatAnalysis-Pipeline] Attempting targeted follow-up call...');
      try {
        const { systemPrompt } = buildMoatAnalysisPrompt(this.inputs);
        const secondResponse = await generateWithAI(
          `You previously generated a partial MOAT analysis for "${this.inputs.companyName}". The following sections were MISSING or EMPTY from your response: ${missingSections.join(', ')}.\n\nGenerate ONLY these missing sections as a valid JSON object containing just those section keys. Do NOT repeat sections that were already generated. Output ONLY valid JSON — no markdown, no code fences, no explanation.\n\nBusiness context:\n- Company: ${this.inputs.companyName}\n- Industry: ${this.inputs.industry}\n- Business Description: ${this.inputs.companyDescription || 'N/A'}\n- Target Market: ${this.inputs.targetMarket || 'N/A'}\n- Products/Services: ${this.inputs.productsServices || 'N/A'}\n- Key Strengths: ${this.inputs.currentStrengths || 'N/A'}\n- Key Challenges: ${this.inputs.currentChallenges || 'N/A'}`,
          systemPrompt,
          8000,
          0.85,
          'json',
          undefined,
          undefined,
          this.userId,
        );
        this.accumulate(secondResponse);

        if (secondResponse && secondResponse.content) {
          const secondParsed = parseJsonFromAI(secondResponse.content);
          if (secondParsed) {
            for (const key of missingSections) {
              if (secondParsed[key] && typeof secondParsed[key] === 'object') {
                merged[key] = secondParsed[key];
                console.info(`[MoatAnalysis-Pipeline] Filled missing section: ${key}`);
              }
            }
          }
        }
      } catch (retryErr: any) {
        console.warn('[MoatAnalysis-Pipeline] Follow-up call failed:', retryErr.message);
        // Continue with whatever we have — validateAndEnrich will fill the gaps.
      }
    }

    return this.mapToOutput(merged);
  }

  private validateAndEnrich(analysis: MoatAnalysisOutput): MoatAnalysisOutput {
    // Ensure all 6 moat sections exist with valid defaults for any missing fields
    const moatSections: (keyof Pick<MoatAnalysisOutput, 'brandMoat' | 'networkEffectMoat' | 'technologyMoat' | 'costAdvantageMoat' | 'distributionMoat' | 'switchingCostMoat'>)[] = [
      'brandMoat',
      'networkEffectMoat',
      'technologyMoat',
      'costAdvantageMoat',
      'distributionMoat',
      'switchingCostMoat',
    ];

    for (const section of moatSections) {
      if (!analysis[section] || typeof analysis[section] !== 'object') {
        (analysis as any)[section] = { ...DEFAULT_MOAT_SECTION };
      } else {
        const s = analysis[section] as MoatSectionScore;
        if (typeof s.score !== 'number' || s.score < 1 || s.score > 10) s.score = 1;
        if (!['none', 'nascent', 'moderate', 'strong', 'dominant'].includes(s.level)) {
          s.level = s.score <= 2 ? 'none' : s.score <= 4 ? 'nascent' : s.score <= 6 ? 'moderate' : s.score <= 8 ? 'strong' : 'dominant';
        }
        if (!s.summary || typeof s.summary !== 'string') s.summary = DEFAULT_MOAT_SECTION.summary;
        if (!Array.isArray(s.strengths) || s.strengths.length === 0) s.strengths = DEFAULT_MOAT_SECTION.strengths;
        if (!Array.isArray(s.weaknesses) || s.weaknesses.length === 0) s.weaknesses = DEFAULT_MOAT_SECTION.weaknesses;
        if (!Array.isArray(s.recommendations) || s.recommendations.length === 0) s.recommendations = DEFAULT_MOAT_SECTION.recommendations;
      }
    }

    // Validate competitiveAdvantageSummary
    if (!analysis.competitiveAdvantageSummary || typeof analysis.competitiveAdvantageSummary !== 'object') {
      console.warn('[MoatAnalysis-Pipeline] competitiveAdvantageSummary missing from AI response, using defaults');
      const scores = moatSections.map(s => (analysis[s] as MoatSectionScore)?.score || 1);
      const avgScore = Math.round((scores.reduce((a, b) => a + b, 0) / scores.length) * 10) / 10;
      analysis.competitiveAdvantageSummary = {
        coreStrengths: [],
        gaps: [],
        opportunities: [],
        risks: [],
        summary: 'Overall MOAT assessment based on individual dimension scores.',
      };
    } else {
      const cas = analysis.competitiveAdvantageSummary as any;
      // Map old field names to new field names
      if (Array.isArray(cas.primaryMoats) && !Array.isArray(cas.coreStrengths)) cas.coreStrengths = cas.primaryMoats;
      if (Array.isArray(cas.weakestMoats) && !Array.isArray(cas.gaps)) cas.gaps = cas.weakestMoats;
      if (!Array.isArray(cas.coreStrengths)) cas.coreStrengths = cas.primaryMoats || [];
      if (!Array.isArray(cas.gaps)) cas.gaps = cas.weakestMoats || [];
      if (!Array.isArray(cas.opportunities)) cas.opportunities = [];
      if (!Array.isArray(cas.risks)) cas.risks = [];
      if (!cas.summary || typeof cas.summary !== 'string') cas.summary = '';
    }

    // Validate strategicActionPlan
    if (!analysis.strategicActionPlan || typeof analysis.strategicActionPlan !== 'object') {
      analysis.strategicActionPlan = {
        shortTerm: [],
        midTerm: [],
        longTerm: [],
        priorityRecommendations: [],
        growthRoadmap: '',
      };
    } else {
      const sap = analysis.strategicActionPlan as any;
      // Map old field names to frontend field names
      if (Array.isArray(sap.immediate) && !Array.isArray(sap.shortTerm)) sap.shortTerm = sap.immediate;
      if (!Array.isArray(sap.shortTerm)) sap.shortTerm = sap.immediate || [];
      if (!Array.isArray(sap.midTerm)) sap.midTerm = [];
      if (!Array.isArray(sap.longTerm)) sap.longTerm = [];
      if (Array.isArray(sap.priorityActions) && !Array.isArray(sap.priorityRecommendations)) sap.priorityRecommendations = sap.priorityActions;
      if (!Array.isArray(sap.priorityRecommendations)) sap.priorityRecommendations = sap.priorityActions || [];
      if (!sap.growthRoadmap || typeof sap.growthRoadmap !== 'string') sap.growthRoadmap = '';
    }

    // ======== ENHANCED SECTIONS VALIDATION ========
    // Ensure ALL new sections exist — never leave them null/undefined

    // executiveSummary
    if (!analysis.executiveSummary || typeof analysis.executiveSummary !== 'object') {
      const scores = moatSections.map(s => (analysis[s] as MoatSectionScore)?.score || 1);
      const avgScore = Math.round((scores.reduce((a, b) => a + b, 0) / scores.length) * 10) / 10;
      analysis.executiveSummary = {
        overallMoatScore: avgScore,
        businessHealthScore: Math.round(avgScore * 0.9 * 10) / 10,
        competitiveStrengthScore: Math.round(avgScore * 0.85 * 10) / 10,
        marketPositionScore: Math.round(avgScore * 0.8 * 10) / 10,
        riskLevel: avgScore >= 7 ? 'low' : avgScore >= 5 ? 'medium' : avgScore >= 3 ? 'high' : 'critical',
        summary: `Overall MOAT analysis indicates a score of ${avgScore}/10 for ${this.inputs.companyName || 'the business'}. Key strengths and areas for improvement have been identified across all dimensions.`,
        keyInsights: ['Complete MOAT analysis across all six dimensions has been conducted.'],
        topAdvantages: ['Competitive positioning assessed across brand, network, technology, cost, distribution, and switching cost dimensions.'],
        criticalImprovements: ['Review individual MOAT dimension scores for specific improvement recommendations.'],
      };
    } else {
      const es = analysis.executiveSummary as any;
      if (typeof es.overallMoatScore !== 'number') {
        const scores = moatSections.map(s => (analysis[s] as MoatSectionScore)?.score || 1);
        es.overallMoatScore = Math.round((scores.reduce((a, b) => a + b, 0) / scores.length) * 10) / 10;
      }
      if (!es.keyInsights || !Array.isArray(es.keyInsights)) es.keyInsights = [];
      if (!es.topAdvantages || !Array.isArray(es.topAdvantages)) es.topAdvantages = [];
      if (!es.criticalImprovements || !Array.isArray(es.criticalImprovements)) es.criticalImprovements = [];
    }

    // scorecard
    if (!analysis.scorecard || typeof analysis.scorecard !== 'object') {
      analysis.scorecard = {
        brandMoatScore: (analysis.brandMoat as MoatSectionScore)?.score || 1,
        networkEffectMoatScore: (analysis.networkEffectMoat as MoatSectionScore)?.score || 1,
        technologyMoatScore: (analysis.technologyMoat as MoatSectionScore)?.score || 1,
        costAdvantageMoatScore: (analysis.costAdvantageMoat as MoatSectionScore)?.score || 1,
        distributionMoatScore: (analysis.distributionMoat as MoatSectionScore)?.score || 1,
        switchingCostMoatScore: (analysis.switchingCostMoat as MoatSectionScore)?.score || 1,
        overallMoatScore: analysis.executiveSummary?.overallMoatScore || 1,
        scoreExplanation: 'Overall MOAT score calculated as a weighted average across all six competitive advantage dimensions.',
      };
    }

    // swotAnalysis
    if (!analysis.swotAnalysis || typeof analysis.swotAnalysis !== 'object') {
      analysis.swotAnalysis = {
        strengths: [], weaknesses: [], opportunities: [], threats: [],
        strengthDetails: [], weaknessDetails: [], opportunityDetails: [], threatDetails: [],
      };
    } else {
      const sw = analysis.swotAnalysis as any;
      if (!Array.isArray(sw.strengths)) sw.strengths = [];
      if (!Array.isArray(sw.weaknesses)) sw.weaknesses = [];
      if (!Array.isArray(sw.opportunities)) sw.opportunities = [];
      if (!Array.isArray(sw.threats)) sw.threats = [];
      if (!Array.isArray(sw.strengthDetails)) sw.strengthDetails = [];
      if (!Array.isArray(sw.weaknessDetails)) sw.weaknessDetails = [];
      if (!Array.isArray(sw.opportunityDetails)) sw.opportunityDetails = [];
      if (!Array.isArray(sw.threatDetails)) sw.threatDetails = [];
    }

    // competitorGapAnalysis
    if (!analysis.competitorGapAnalysis || typeof analysis.competitorGapAnalysis !== 'object') {
      analysis.competitorGapAnalysis = { competitors: [], overallGaps: [], uniqueAdvantages: [], competitivePosition: '' };
    }

    // marketOpportunityAnalysis
    if (!analysis.marketOpportunityAnalysis || typeof analysis.marketOpportunityAnalysis !== 'object') {
      analysis.marketOpportunityAnalysis = { industryTrends: [], growthOpportunities: [], emergingSegments: [], untappedOpportunities: [], customerDemandAnalysis: [], futureOutlook: '' };
    }

    // riskAssessment
    if (!analysis.riskAssessment || typeof analysis.riskAssessment !== 'object') {
      console.warn('[MoatAnalysis-Pipeline] riskAssessment missing from AI response, using defaults');
      analysis.riskAssessment = { highRisks: [], mediumRisks: [], lowRisks: [], competitiveRisks: [], marketRisks: [], operationalRisks: [], financialRisks: [], technologyRisks: [], mitigationRecommendations: [] };
    }

    // kpiRecommendations
    if (!analysis.kpiRecommendations || typeof analysis.kpiRecommendations !== 'object') {
      console.warn('[MoatAnalysis-Pipeline] kpiRecommendations missing from AI response, using defaults');
      analysis.kpiRecommendations = {
        revenueGrowth: [], customerRetention: [], customerAcquisition: [], customerLifetimeValue: [],
        netPromoterScore: [], marketShare: [], brandAwareness: [], conversionMetrics: [], operationalEfficiency: [],
      };
    } else {
      const kpi = analysis.kpiRecommendations as any;
      if (!Array.isArray(kpi.revenueGrowth)) kpi.revenueGrowth = [];
      if (!Array.isArray(kpi.customerRetention)) kpi.customerRetention = [];
      if (!Array.isArray(kpi.customerAcquisition)) kpi.customerAcquisition = [];
      if (!Array.isArray(kpi.customerLifetimeValue)) kpi.customerLifetimeValue = [];
      if (!Array.isArray(kpi.netPromoterScore)) kpi.netPromoterScore = [];
      if (!Array.isArray(kpi.marketShare)) kpi.marketShare = [];
      if (!Array.isArray(kpi.brandAwareness)) kpi.brandAwareness = [];
      if (!Array.isArray(kpi.conversionMetrics)) kpi.conversionMetrics = [];
      if (!Array.isArray(kpi.operationalEfficiency)) kpi.operationalEfficiency = [];
    }

    // priorityMatrix
    if (!analysis.priorityMatrix || typeof analysis.priorityMatrix !== 'object') {
      analysis.priorityMatrix = { highImpactLowEffort: [], highImpactHighEffort: [], lowImpactLowEffort: [], lowImpactHighEffort: [] };
    } else {
      const pm = analysis.priorityMatrix as any;
      if (!Array.isArray(pm.highImpactLowEffort)) pm.highImpactLowEffort = [];
      if (!Array.isArray(pm.highImpactHighEffort)) pm.highImpactHighEffort = [];
      if (!Array.isArray(pm.lowImpactLowEffort)) pm.lowImpactLowEffort = [];
      if (!Array.isArray(pm.lowImpactHighEffort)) pm.lowImpactHighEffort = [];
    }

    // growthRoadmap
    if (!analysis.growthRoadmap || typeof analysis.growthRoadmap !== 'object') {
      analysis.growthRoadmap = {
        phase1: { phaseName: 'Foundation & Quick Wins', timeRange: 'Months 1-3', objectives: [], tasks: [], expectedOutcomes: [], kpis: [], priority: 'critical' as const },
        phase2: { phaseName: 'Scale & Differentiate', timeRange: 'Months 4-8', objectives: [], tasks: [], expectedOutcomes: [], kpis: [], priority: 'high' as const },
        phase3: { phaseName: 'Dominance & Expansion', timeRange: 'Months 9-18', objectives: [], tasks: [], expectedOutcomes: [], kpis: [], priority: 'medium' as const },
      };
    } else {
      const gr = analysis.growthRoadmap as any;
      // Map timeRange <-> timeframe (both used in different contexts)
      for (const phaseKey of ['phase1', 'phase2', 'phase3']) {
        if (gr[phaseKey]) {
          const phase = gr[phaseKey];
          if (phase.timeframe && !phase.timeRange) phase.timeRange = phase.timeframe;
          if (phase.timeRange && !phase.timeframe) phase.timeframe = phase.timeRange;
          if (phase.outcomes && !phase.expectedOutcomes) phase.expectedOutcomes = phase.outcomes;
          if (phase.expectedOutcomes && !phase.outcomes) phase.outcomes = phase.expectedOutcomes;
        }
      }
    }

    // dataSourceTracking
    if (!analysis.dataSourceTracking || typeof analysis.dataSourceTracking !== 'object') {
      analysis.dataSourceTracking = {
        sources: [{ name: 'Business Profile', type: 'internal', connected: true, lastSyncDate: new Date().toISOString().split('T')[0], dataCompleteness: 70, fieldsUsed: ['businessName', 'industry', 'targetMarket'] }],
        overallCompleteness: 70,
        lastGenerationDate: new Date().toISOString().split('T')[0],
      };
    }

    // Ensure content string exists
    if (!analysis.content || typeof analysis.content !== 'string') {
      analysis.content = '';
    }

    // Ensure metadata exists
    if (!analysis.metadata || typeof analysis.metadata !== 'object') {
      analysis.metadata = {
        analysisDate: new Date().toISOString().split('T')[0],
        pipelineVersion: MoatAnalysisPipeline.PIPELINE_VERSION,
        confidenceScore: 0.7,
      };
    } else {
      if (!analysis.metadata.analysisDate) analysis.metadata.analysisDate = new Date().toISOString().split('T')[0];
      if (!analysis.metadata.pipelineVersion) analysis.metadata.pipelineVersion = MoatAnalysisPipeline.PIPELINE_VERSION;
      if (typeof analysis.metadata.confidenceScore !== 'number') analysis.metadata.confidenceScore = 0.7;
    }

    return analysis;
  }

  private mapToOutput(parsed: any): MoatAnalysisOutput {
    // Map the AI response to the output structure, including ALL enhanced sections
    return {
      brandMoat: parsed.brandMoat || { ...DEFAULT_MOAT_SECTION },
      networkEffectMoat: parsed.networkEffectMoat || { ...DEFAULT_MOAT_SECTION },
      technologyMoat: parsed.technologyMoat || { ...DEFAULT_MOAT_SECTION },
      costAdvantageMoat: parsed.costAdvantageMoat || { ...DEFAULT_MOAT_SECTION },
      distributionMoat: parsed.distributionMoat || { ...DEFAULT_MOAT_SECTION },
      switchingCostMoat: parsed.switchingCostMoat || { ...DEFAULT_MOAT_SECTION },
      competitiveAdvantageSummary: parsed.competitiveAdvantageSummary || {
        coreStrengths: [],
        gaps: [],
        opportunities: [],
        risks: [],
        summary: '',
      },
      strategicActionPlan: parsed.strategicActionPlan || {
        shortTerm: [],
        midTerm: [],
        longTerm: [],
        priorityRecommendations: [],
        growthRoadmap: '',
      },
      // Enhanced sections — pass through from AI response
      executiveSummary: parsed.executiveSummary || undefined,
      scorecard: parsed.scorecard || undefined,
      swotAnalysis: parsed.swotAnalysis || undefined,
      competitorGapAnalysis: parsed.competitorGapAnalysis || undefined,
      marketOpportunityAnalysis: parsed.marketOpportunityAnalysis || undefined,
      riskAssessment: parsed.riskAssessment || undefined,
      kpiRecommendations: parsed.kpiRecommendations || undefined,
      priorityMatrix: parsed.priorityMatrix || undefined,
      growthRoadmap: parsed.growthRoadmap || undefined,
      dataSourceTracking: parsed.dataSourceTracking || undefined,
      content: parsed.content || '',
      metadata: {
        analysisDate: parsed.metadata?.analysisDate || new Date().toISOString().split('T')[0],
        pipelineVersion: parsed.metadata?.pipelineVersion || MoatAnalysisPipeline.PIPELINE_VERSION,
        confidenceScore: typeof parsed.metadata?.confidenceScore === 'number' ? parsed.metadata.confidenceScore : 0.7,
      },
    };
  }
}