/**
 * Guerrilla Marketing AI Pipeline
 *
 * Follows the proven Social Media pipeline pattern:
 * - Single generateWithAI() call per stage
 * - Safe JSON parsing with parseJsonFromAI()
 * - Proper try/catch returning { success, error } on failure
 * - 4 stages: Strategy → Ideas → Execution Plan → Scoring
 *
 * Stages:
 * 1. Strategy — Campaign direction, audience analysis, initial scoring
 * 2. Ideas — Creative campaign ideas with individual scoring (20/50/100)
 * 3. Execution Plan — Phased plan with tasks, timeline, budget
 * 4. Scoring — 6-dimension scoring with recommendations
 */

import { generateWithAI } from '../../utils/aiProvider';
import { parseJsonFromAI } from './parseJsonFromAI';
import {
  buildGuerrillaStrategyPrompt,
  buildGuerrillaIdeasPrompt,
  buildGuerrillaExecutionPlanPrompt,
  buildGuerrillaScoringPrompt,
  GuerrillaMarketingPipelineInputs,
} from './guerrillaMarketingPrompts';

// ============================================
// TYPES
// ============================================

export interface GuerrillaMarketingPipelineResult {
  success: boolean;
  stage: string;
  strategy?: Record<string, any>;
  ideas?: Record<string, any>[];
  executionPlan?: Record<string, any>[];
  scoring?: Record<string, any>;
  tokensUsed: number;
  inputTokens: number;
  outputTokens: number;
  model: string;
  provider: string;
  latencyMs: number;
  error?: string;
}

// ============================================
// SAFE AI GENERATION HELPER
// ============================================

/**
 * Calls generateWithAI and safely parses the JSON response.
 * Follows the Social Media pipeline pattern:
 * - Checks for empty/null content (Ollama sometimes returns hasContent: false)
 * - Uses parseJsonFromAI for robust parsing
 * - Returns null on failure instead of throwing
 */
async function safeGenerate(
  prompt: string,
  systemPrompt: string,
  maxTokens: number,
  temperature: number = 0.7,
): Promise<{ parsed: Record<string, any> | null; tokensUsed: number; inputTokens: number; outputTokens: number; model: string; provider: string } | null> {
  // BUG #98: append a per-call variation token so each Regenerate produces a
  // fresh strategy/ideas/plan (bypasses any provider-side prompt caching).
  const variationTag = `\n\n[Generation variation ${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}: produce fresh, original output that does not repeat any previous generation.]`;
  const result = await generateWithAI(prompt + variationTag, systemPrompt, maxTokens, temperature, 'json');

  if (!result || !result.content) {
    console.warn('[GuerrillaMarketing-Pipeline] AI returned empty content');
    return null;
  }

  const parsed = parseJsonFromAI(result.content);

  if (!parsed) {
    console.warn('[GuerrillaMarketing-Pipeline] Failed to parse AI response as JSON. Raw length:', result.content?.length || 0);
    return null;
  }

  return {
    parsed,
    tokensUsed: result.tokenUsage?.totalTokens || 0,
    inputTokens: result.tokenUsage?.inputTokens || 0,
    outputTokens: result.tokenUsage?.outputTokens || 0,
    model: result.model || 'unknown',
    provider: result.provider || 'unknown',
  };
}

/**
 * Find an array in a parsed object, trying multiple key names.
 * Also checks one level deep (AI sometimes wraps data in a nested object).
 */
function findArray(parsed: Record<string, any>, keyNames: string[]): any[] | null {
  // Direct lookup
  for (const key of keyNames) {
    if (Array.isArray(parsed[key]) && parsed[key].length > 0) {
      return parsed[key];
    }
  }
  // Check one level deep
  for (const key of Object.keys(parsed)) {
    const val = parsed[key];
    if (val && typeof val === 'object' && !Array.isArray(val)) {
      for (const innerKey of keyNames) {
        if (Array.isArray(val[innerKey]) && val[innerKey].length > 0) {
          return val[innerKey];
        }
      }
    }
  }
  return null;
}

// ============================================
// STAGE 1: STRATEGY
// ============================================

async function generateStrategy(
  inputs: GuerrillaMarketingPipelineInputs,
  onProgress?: (progress: number, step: string) => void,
): Promise<{ strategy: Record<string, any>; tokensUsed: number; inputTokens: number; outputTokens: number; model: string; provider: string }> {
  onProgress?.(5, 'Analysing campaign strategy...');

  const { systemPrompt, userPrompt, maxTokens } = buildGuerrillaStrategyPrompt(inputs);

  const result = await safeGenerate(userPrompt, systemPrompt, maxTokens, 0.7);

  if (!result || !result.parsed) {
    throw new Error('Failed to generate strategy: AI returned invalid or empty response');
  }

  // Extract strategy from possible wrapper keys
  const strategy = result.parsed.strategy || result.parsed;
  if (!strategy || typeof strategy !== 'object') {
    throw new Error('AI strategy response missing strategy object');
  }

  onProgress?.(25, 'Strategy defined');
  return { strategy, tokensUsed: result.tokensUsed, inputTokens: result.inputTokens, outputTokens: result.outputTokens, model: result.model, provider: result.provider };
}

// ============================================
// STAGE 2: IDEAS
// ============================================

async function generateIdeas(
  inputs: GuerrillaMarketingPipelineInputs,
  strategy: Record<string, any>,
  ideaCount: number = 20,
  onProgress?: (progress: number, step: string) => void,
): Promise<{ ideas: Record<string, any>[]; tokensUsed: number; inputTokens: number; outputTokens: number; model: string; provider: string }> {
  onProgress?.(30, 'Generating creative ideas...');

  const { systemPrompt, userPrompt, maxTokens } = buildGuerrillaIdeasPrompt(inputs, { strategy }, ideaCount);

  const result = await safeGenerate(userPrompt, systemPrompt, maxTokens, 0.8);

  if (!result || !result.parsed) {
    console.warn('[GuerrillaMarketing-Pipeline] Idea generation failed, returning empty ideas');
    onProgress?.(55, 'Idea generation skipped (AI error)');
    return { ideas: [], tokensUsed: 0, inputTokens: 0, outputTokens: 0, model: 'unknown', provider: 'unknown' };
  }

  const parsed = result.parsed;

  // Extract ideas from possible wrapper keys
  const ideas = findArray(parsed, ['ideas', 'campaignIdeas', 'campaigns', 'guerrillaIdeas']) || [];

  // Ensure each idea has an id and scoring
  const processedIdeas = ideas.map((idea: any, index: number) => ({
    id: idea.id || `idea-${index + 1}`,
    title: idea.title || `Idea ${index + 1}`,
    description: idea.description || '',
    concept: idea.concept || '',
    category: idea.category || inputs.campaignCategory || 'guerrilla-marketing',
    targetAudience: idea.targetAudience || '',
    estimatedReach: idea.estimatedReach || '',
    estimatedCost: idea.estimatedCost || '',
    executionComplexity: idea.executionComplexity || 'moderate',
    timeToExecute: idea.timeToExecute || '',
    location: idea.location || '',
    scoring: idea.scoring || {
      creativity: 5,
      feasibility: 5,
      impact: 5,
      viralPotential: 5,
      brandAlignment: 5,
      communityValue: 5,
      overallScore: 5,
    },
    keyElements: idea.keyElements || [],
    risks: idea.risks || [],
    tags: idea.tags || [],
    selected: false,
  }));

  onProgress?.(55, `${processedIdeas.length} ideas generated`);
  return { ideas: processedIdeas, tokensUsed: result.tokensUsed, inputTokens: result.inputTokens, outputTokens: result.outputTokens, model: result.model, provider: result.provider };
}

// ============================================
// STAGE 3: EXECUTION PLAN
// ============================================

async function generateExecutionPlan(
  inputs: GuerrillaMarketingPipelineInputs,
  strategy: Record<string, any>,
  ideas: Record<string, any>[],
  onProgress?: (progress: number, step: string) => void,
): Promise<{ executionPlan: Record<string, any>[]; tokensUsed: number; inputTokens: number; outputTokens: number; model: string; provider: string }> {
  onProgress?.(60, 'Creating execution plan...');

  const { systemPrompt, userPrompt, maxTokens } = buildGuerrillaExecutionPlanPrompt(
    inputs,
    { strategy, ideas },
  );

  const result = await safeGenerate(userPrompt, systemPrompt, maxTokens, 0.7);

  if (!result || !result.parsed) {
    console.warn('[GuerrillaMarketing-Pipeline] Execution plan generation failed, returning empty plan');
    onProgress?.(80, 'Execution plan generation skipped (AI error)');
    return { executionPlan: [], tokensUsed: 0, inputTokens: 0, outputTokens: 0, model: 'unknown', provider: 'unknown' };
  }

  const parsed = result.parsed;

  // Extract execution plan from possible wrapper keys
  const executionPlan = findArray(parsed, ['executionPlan', 'phases', 'plan', 'phases']) || [];

  // Process plan phases
  const processedPlan = executionPlan.map((phase: any, index: number) => ({
    id: phase.id || `phase-${index + 1}`,
    phase: phase.phase || `Phase ${index + 1}`,
    duration: phase.duration || '',
    description: phase.description || '',
    tasks: Array.isArray(phase.tasks) ? phase.tasks.map((task: any, taskIdx: number) => ({
      id: task.id || `task-${index + 1}-${taskIdx + 1}`,
      title: task.title || `Task ${taskIdx + 1}`,
      description: task.description || '',
      assignedRole: task.assignedRole || '',
      estimatedHours: task.estimatedHours || 0,
      deadline: task.deadline || '',
      dependencies: task.dependencies || [],
      status: task.status || 'pending',
    })) : [],
    milestones: phase.milestones || [],
    budgetAllocation: phase.budgetAllocation || { amount: '', percentage: 0, items: [] },
  }));

  onProgress?.(80, 'Execution plan created');
  return { executionPlan: processedPlan, tokensUsed: result.tokensUsed, inputTokens: result.inputTokens, outputTokens: result.outputTokens, model: result.model, provider: result.provider };
}

// ============================================
// STAGE 4: SCORING
// ============================================

async function generateScoring(
  inputs: GuerrillaMarketingPipelineInputs,
  strategy: Record<string, any>,
  ideas: Record<string, any>[],
  executionPlan: Record<string, any>[],
  onProgress?: (progress: number, step: string) => void,
): Promise<{ scoring: Record<string, any>; tokensUsed: number; inputTokens: number; outputTokens: number; model: string; provider: string }> {
  onProgress?.(85, 'Evaluating campaign...');

  const { systemPrompt, userPrompt, maxTokens } = buildGuerrillaScoringPrompt(
    inputs,
    { strategy, ideas, executionPlan },
  );

  const result = await safeGenerate(userPrompt, systemPrompt, maxTokens, 0.7);

  if (!result || !result.parsed) {
    console.warn('[GuerrillaMarketing-Pipeline] Scoring generation failed, returning default scores');
    onProgress?.(95, 'Scoring skipped (AI error)');
    // Return default scoring
    return {
      scoring: {
        creativity: { score: 50, label: 'Moderate', analysis: 'AI scoring unavailable', recommendations: [] },
        feasibility: { score: 50, label: 'Moderate', analysis: 'AI scoring unavailable', recommendations: [] },
        impact: { score: 50, label: 'Moderate', analysis: 'AI scoring unavailable', recommendations: [] },
        viralPotential: { score: 50, label: 'Moderate', analysis: 'AI scoring unavailable', recommendations: [] },
        brandAlignment: { score: 50, label: 'Moderate', analysis: 'AI scoring unavailable', recommendations: [] },
        communityValue: { score: 50, label: 'Moderate', analysis: 'AI scoring unavailable', recommendations: [] },
        overallScore: 50,
        overallLabel: 'Moderate',
        topRecommendations: ['Review and enhance campaign strategy', 'Consider budget adjustments'],
      },
      tokensUsed: 0,
      inputTokens: 0,
      outputTokens: 0,
      model: 'unknown',
      provider: 'unknown',
    };
  }

  const scoring = result.parsed.scoring || result.parsed;

  onProgress?.(95, 'Campaign evaluated');
  return { scoring, tokensUsed: result.tokensUsed, inputTokens: result.inputTokens, outputTokens: result.outputTokens, model: result.model, provider: result.provider };
}

// ============================================
// MAIN PIPELINE
// ============================================

/**
 * Runs the Guerrilla Marketing AI pipeline.
 *
 * 4 stages executed sequentially:
 * 1. Strategy — Campaign direction, audience analysis
 * 2. Ideas — Creative campaign ideas with scoring
 * 3. Execution Plan — Phased plan with tasks, timeline, budget
 * 4. Scoring — 6-dimension scoring with recommendations
 */
export async function runGuerrillaMarketingPipeline(
  inputs: GuerrillaMarketingPipelineInputs,
  ideaCount: number = 20,
  onProgress?: (progress: number, step: string) => void,
): Promise<GuerrillaMarketingPipelineResult> {
  const startTime = Date.now();

  try {
    // Stage 1: Strategy (fatal if fails)
    const strategyResult = await generateStrategy(inputs, onProgress);

    // Stage 2: Ideas (non-fatal if fails)
    const ideasResult = await generateIdeas(inputs, strategyResult.strategy, ideaCount, onProgress);

    // Stage 3: Execution Plan (non-fatal if fails)
    const executionPlanResult = await generateExecutionPlan(
      inputs, strategyResult.strategy, ideasResult.ideas, onProgress
    );

    // Stage 4: Scoring (non-fatal if fails)
    const scoringResult = await generateScoring(
      inputs, strategyResult.strategy, ideasResult.ideas, executionPlanResult.executionPlan, onProgress
    );

    const totalTokens =
      strategyResult.tokensUsed +
      ideasResult.tokensUsed +
      executionPlanResult.tokensUsed +
      scoringResult.tokensUsed;
    const totalInputTokens =
      strategyResult.inputTokens + ideasResult.inputTokens + executionPlanResult.inputTokens + scoringResult.inputTokens;
    const totalOutputTokens =
      strategyResult.outputTokens + ideasResult.outputTokens + executionPlanResult.outputTokens + scoringResult.outputTokens;

    const lastModel = scoringResult.model || executionPlanResult.model || ideasResult.model || strategyResult.model;
    const lastProvider = scoringResult.provider || executionPlanResult.provider || ideasResult.provider || strategyResult.provider;

    console.log(`[GuerrillaMarketing-Pipeline] Pipeline complete. Strategy keys: ${Object.keys(strategyResult.strategy).join(', ')}. Ideas: ${ideasResult.ideas.length}. Plan phases: ${executionPlanResult.executionPlan.length}.`);

    return {
      success: true,
      stage: 'complete',
      strategy: strategyResult.strategy,
      ideas: ideasResult.ideas,
      executionPlan: executionPlanResult.executionPlan,
      scoring: scoringResult.scoring,
      tokensUsed: totalTokens,
      inputTokens: totalInputTokens,
      outputTokens: totalOutputTokens,
      model: lastModel,
      provider: lastProvider,
      latencyMs: Date.now() - startTime,
    };
  } catch (error: any) {
    console.error('[GuerrillaMarketing-Pipeline] Pipeline failed:', error.message);
    return {
      success: false,
      stage: 'pipeline-error',
      tokensUsed: 0,
      inputTokens: 0,
      outputTokens: 0,
      model: 'unknown',
      provider: 'unknown',
      latencyMs: Date.now() - startTime,
      error: error.message || 'Unknown pipeline error',
    };
  }
}

// ============================================
// LEGACY CLASS EXPORT (for backward compatibility with route)
// ============================================

export class GuerrillaMarketingPipeline {
  private inputs: GuerrillaMarketingPipelineInputs;
  private onProgress?: (progress: number, step: string) => void;
  private ideaCount: number;

  constructor(
    inputs: GuerrillaMarketingPipelineInputs,
    onProgress?: (progress: number, step: string) => void,
    ideaCount: number = 20,
  ) {
    this.inputs = inputs;
    this.onProgress = onProgress;
    this.ideaCount = ideaCount;
  }

  async run(): Promise<{
    strategy: Record<string, any>;
    ideas: Record<string, any>[];
    executionPlan: Record<string, any>[];
    scoring: Record<string, any>;
    pipelineVersion: string;
    provider: string;
    aiModel: string;
    tokensUsed: number;
    inputTokens: number;
    outputTokens: number;
    latencyMs: number;
    overallConfidence: number;
    finishReason: string | null;
    errors: string[];
  }> {
    const startTime = Date.now();
    const result = await runGuerrillaMarketingPipeline(this.inputs, this.ideaCount, this.onProgress);

    if (!result.success) {
      return {
        strategy: {},
        ideas: [],
        executionPlan: [],
        scoring: {} as Record<string, any>,
        pipelineVersion: '1.0',
        provider: result.provider || 'unknown',
        aiModel: result.model || 'unknown',
        tokensUsed: result.tokensUsed || 0,
        inputTokens: result.inputTokens || 0,
        outputTokens: result.outputTokens || 0,
        latencyMs: result.latencyMs || 0,
        overallConfidence: 0,
        finishReason: 'error',
        errors: [result.error || 'Pipeline failed'],
      };
    }

    return {
      strategy: result.strategy || {},
      ideas: result.ideas || [],
      executionPlan: result.executionPlan || [],
      scoring: result.scoring || {},
      pipelineVersion: '1.0',
      provider: result.provider,
      aiModel: result.model,
      tokensUsed: result.tokensUsed,
      inputTokens: result.inputTokens,
      outputTokens: result.outputTokens,
      latencyMs: result.latencyMs,
      overallConfidence: 100,
      finishReason: 'stop',
      errors: [],
    };
  }
}