/**
 * SWOT Analysis Pipeline
 * Single-call pipeline for AI-powered SWOT analysis generation.
 */

import { generateWithAI } from '../../utils/aiProvider';
import {
  SwotAnalysisInputs,
  SwotAnalysisOutput,
  buildSwotAnalysisPrompt,
  buildSwotRefinementPrompt,
} from './swotAnalysisPrompts';
import { parseJsonFromAI } from './parseJsonFromAI';

export interface SwotAnalysisPipelineResult {
  analysis: SwotAnalysisOutput;
  pipelineVersion: string;
  provider: string;
  aiModel: string;
  tokensUsed: number;
  inputTokens: number;
  outputTokens: number;
  processingTimeMs: number;
  latencyMs: number;
  finishReason: string;
  apiKeyMasked?: string;
  overallConfidence: number;
  fieldConfidences: Record<string, number>;
}

export class SwotAnalysisPipeline {
  private inputs: SwotAnalysisInputs;
  private progressCallback: (progress: number, step: string) => void;
  private startTime: number;
  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 = '1.0';

  constructor(inputs: SwotAnalysisInputs, 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<SwotAnalysisPipelineResult> {
    const pipelineStart = Date.now();

    this.progressCallback(10, 'Preparing SWOT analysis inputs...');

    this.progressCallback(30, 'Generating comprehensive SWOT analysis...');
    const analysis = await this.generateAnalysis();

    if (!analysis) {
      throw new Error('SWOT analysis generation failed — no valid response from AI');
    }

    // Validate and fill in any missing sections
    this.progressCallback(80, 'Validating output...');
    const validated = this.validateAndEnrich(analysis);

    this.progressCallback(95, 'Finalising...');
    const pipelineEnd = Date.now();

    return {
      analysis: validated,
      pipelineVersion: SwotAnalysisPipeline.PIPELINE_VERSION,
      provider: this.lastProvider,
      aiModel: this.lastAiModel,
      tokensUsed: this.totalTokens,
      inputTokens: this.totalInputTokens,
      outputTokens: this.totalOutputTokens,
      processingTimeMs: pipelineEnd - pipelineStart,
      latencyMs: pipelineEnd - this.startTime,
      finishReason: this.lastFinishReason || 'stop',
      apiKeyMasked: this.lastApiKeyMasked || undefined,
      overallConfidence: 0,
      fieldConfidences: {},
    };
  }

  private async generateAnalysis(): Promise<SwotAnalysisOutput | null> {
    const prompt = buildSwotAnalysisPrompt(this.inputs);

    const response = await generateWithAI(
      prompt.userPrompt,
      prompt.systemPrompt,
      prompt.maxTokens,
      0.85,
      'json',
      undefined,
      undefined,
      this.userId,
    );

    this.accumulate(response);

    if (!response || !response.content) {
      console.warn('[SwotAnalysis-Pipeline] AI returned no content');
      return null;
    }

    const parsed = parseJsonFromAI(response.content);
    if (!parsed) {
      console.warn('[SwotAnalysis-Pipeline] Failed to parse AI response as JSON');
      return null;
    }

    return this.mapToOutput(parsed);
  }

  /** Refine an existing SWOT analysis by regenerating selected sections. */
  async refine(existing: SwotAnalysisOutput, sections: string[], refinementType: string, customInstructions?: string): Promise<SwotAnalysisOutput> {
    const prompt = buildSwotRefinementPrompt({
      existing,
      sections,
      refinementType: refinementType as any,
      customInstructions,
      harmonyText: this.inputs.harmonyText,
    });

    this.progressCallback(30, `Refining ${sections.join(', ')}...`);

    const response = await generateWithAI(
      prompt.userPrompt,
      prompt.systemPrompt,
      prompt.maxTokens,
      0.85,
      'json',
      undefined,
      undefined,
      this.userId,
    );

    this.accumulate(response);

    if (!response || !response.content) {
      throw new Error('SWOT refinement failed — no valid response from AI');
    }

    const parsed = parseJsonFromAI(response.content);
    if (!parsed) {
      throw new Error('SWOT refinement failed — could not parse AI response');
    }

    return this.validateAndEnrich(this.mapToOutput(parsed));
  }

  private mapToOutput(raw: any): SwotAnalysisOutput {
    return {
      strengths: Array.isArray(raw.strengths) ? raw.strengths : [],
      strengthDetails: Array.isArray(raw.strengthDetails) ? raw.strengthDetails : [],
      weaknesses: Array.isArray(raw.weaknesses) ? raw.weaknesses : [],
      weaknessDetails: Array.isArray(raw.weaknessDetails) ? raw.weaknessDetails : [],
      opportunities: Array.isArray(raw.opportunities) ? raw.opportunities : [],
      opportunityDetails: Array.isArray(raw.opportunityDetails) ? raw.opportunityDetails : [],
      threats: Array.isArray(raw.threats) ? raw.threats : [],
      threatDetails: Array.isArray(raw.threatDetails) ? raw.threatDetails : [],
      strategicSummary: raw.strategicSummary || '',
      keyRecommendations: Array.isArray(raw.keyRecommendations) ? raw.keyRecommendations : [],
      content: raw.content || '',
      metadata: raw.metadata || {
        analysisDate: new Date().toISOString().split('T')[0],
        pipelineVersion: SwotAnalysisPipeline.PIPELINE_VERSION,
      },
    };
  }

  /** Validate the analysis and fill in sensible defaults for any missing fields. */
  private validateAndEnrich(analysis: SwotAnalysisOutput): SwotAnalysisOutput {
    const ensureArray = (arr: string[], fallback: string[]): string[] =>
      arr.length > 0 ? arr : fallback;

    const ensureMatching = (items: string[], details: string[]): string[] => {
      // If details length doesn't match items, pad or trim
      if (details.length >= items.length) return details.slice(0, items.length);
      return [
        ...details,
        ...Array(Math.max(0, items.length - details.length)).fill('Detailed analysis not available — regenerate for more depth.'),
      ];
    };

    // Log which fields are missing so we can debug truncation issues
    const missingFields: string[] = [];
    if (!analysis.strategicSummary || analysis.strategicSummary.trim().length < 20) missingFields.push('strategicSummary');
    if (!analysis.keyRecommendations || analysis.keyRecommendations.length < 3) missingFields.push('keyRecommendations');
    if (analysis.strengths.length < 3) missingFields.push('strengths');
    if (analysis.weaknesses.length < 3) missingFields.push('weaknesses');
    if (analysis.opportunities.length < 3) missingFields.push('opportunities');
    if (analysis.threats.length < 3) missingFields.push('threats');
    if (missingFields.length > 0) {
      console.warn(`[SwotAnalysis-Pipeline] Missing/incomplete fields in AI output: ${missingFields.join(', ')}. Using fallback values.`);
    }

    const defaultItem = 'Analysis pending — regenerate for detailed insights';

    analysis.strengths = ensureArray(analysis.strengths, [defaultItem]);
    analysis.strengthDetails = ensureMatching(analysis.strengths, analysis.strengthDetails);
    analysis.weaknesses = ensureArray(analysis.weaknesses, [defaultItem]);
    analysis.weaknessDetails = ensureMatching(analysis.weaknesses, analysis.weaknessDetails);
    analysis.opportunities = ensureArray(analysis.opportunities, [defaultItem]);
    analysis.opportunityDetails = ensureMatching(analysis.opportunities, analysis.opportunityDetails);
    analysis.threats = ensureArray(analysis.threats, [defaultItem]);
    analysis.threatDetails = ensureMatching(analysis.threats, analysis.threatDetails);
    analysis.strategicSummary = (analysis.strategicSummary && analysis.strategicSummary.trim().length >= 20)
      ? analysis.strategicSummary
      : 'Strategic summary pending — regenerate for a comprehensive analysis.';
    analysis.keyRecommendations = ensureArray(analysis.keyRecommendations, ['Review and regenerate SWOT analysis for actionable recommendations.']);
    analysis.content = analysis.content || '';

    return analysis;
  }
}