import { createModuleLogger } from '../../utils/logger.js';
import { OpenRouterClient, createOpenRouterClient } from './client.js';
import type { ChatMessage } from './client.js';
import type { QualityReport } from '../../types/api.js';
import type { CharacterDNA } from '../../types/character.js';

const logger = createModuleLogger('vlm-analyzer');

const DEFAULT_THRESHOLD = 7.0;

const SCORING_WEIGHTS = {
  characterAccuracy: 0.4,
  bodyConsistency: 0.2,
  environmentQuality: 0.2,
  overallAesthetic: 0.2,
};

export class VLMAnalyzer {
  private readonly client: OpenRouterClient;

  constructor(client: OpenRouterClient) {
    this.client = client;
  }

  buildScoringPrompt(dna: CharacterDNA): string {
    return [
      'You are an image quality analyst. Score the following image based on how well it matches the character description.',
      '',
      'Character Description:',
      `- Name: ${dna.identity.name}, Age: ${dna.identity.age}`,
      `- Body type: ${dna.physicalMeasurements.body_type}, Height: ${dna.physicalMeasurements.height_cm}cm`,
      `- Skin tones: base ${dna.skinMap.base}, shadow ${dna.skinMap.shadow}, highlight ${dna.skinMap.highlight}`,
      `- Eye shape: ${dna.faceAnatomy.eye_shape}, Eye color: ${dna.faceAnatomy.eye_color}`,
      `- Hair: ${dna.hairDNA.style} ${dna.hairDNA.length} ${dna.hairDNA.texture}, colors: root ${dna.hairDNA.root_color}, mid ${dna.hairDNA.mid_color}`,
      `- Expression: ${dna.expressionMotion.default_expression}, Smile: ${dna.expressionMotion.smile_type}`,
      '',
      'Score the image in these 4 categories (0-10 each):',
      '1. characterAccuracy - Face, hair, skin tone accuracy vs description',
      '2. bodyConsistency - Body type and proportions consistency',
      '3. environmentQuality - Environment, lighting, composition quality',
      '4. overallAesthetic - Overall aesthetic appeal',
      '',
      'Respond ONLY with valid JSON in this exact format, no other text:',
      '{"characterAccuracy":<number>,"bodyConsistency":<number>,"environmentQuality":<number>,"overallAesthetic":<number>,"feedback":"<brief feedback>"}',
    ].join('\n');
  }

  parseScores(response: string): {
    characterAccuracy: number;
    bodyConsistency: number;
    environmentQuality: number;
    overallAesthetic: number;
  } {
    // Extract JSON from the response (handle markdown code blocks)
    const jsonMatch = response.match(/\{[\s\S]*?\}/);
    if (!jsonMatch) {
      throw new Error('No JSON object found in VLM response');
    }

    const parsed = JSON.parse(jsonMatch[0]);

    const characterAccuracy = clampScore(parsed.characterAccuracy);
    const bodyConsistency = clampScore(parsed.bodyConsistency);
    const environmentQuality = clampScore(parsed.environmentQuality);
    const overallAesthetic = clampScore(parsed.overallAesthetic);

    return { characterAccuracy, bodyConsistency, environmentQuality, overallAesthetic };
  }

  async analyzeImage(
    imageUrl: string,
    dna: CharacterDNA,
    imageId: string,
    taskId: string,
    threshold: number = DEFAULT_THRESHOLD,
  ): Promise<QualityReport> {
    const scoringPrompt = this.buildScoringPrompt(dna);

    const messages: ChatMessage[] = [
      { role: 'system', content: scoringPrompt },
      {
        role: 'user',
        content: [
          { type: 'text', text: 'Analyze this image and provide quality scores.' },
          { type: 'image_url', image_url: { url: imageUrl } },
        ],
      },
    ];

    logger.debug({ imageId, taskId }, 'Sending image for VLM analysis');

    const response = await this.client.chatCompletionWithVision(messages, {
      temperature: 0.7,
      max_tokens: 500,
    });

    const content = response.choices[0]?.message?.content ?? '';
    const scores = this.parseScores(content);

    const totalScore =
      scores.characterAccuracy * SCORING_WEIGHTS.characterAccuracy +
      scores.bodyConsistency * SCORING_WEIGHTS.bodyConsistency +
      scores.environmentQuality * SCORING_WEIGHTS.environmentQuality +
      scores.overallAesthetic * SCORING_WEIGHTS.overallAesthetic;

    const roundedTotal = Math.round(totalScore * 100) / 100;

    // Extract feedback from parsed JSON or use content
    let feedback = '';
    try {
      const jsonMatch = content.match(/\{[\s\S]*?\}/);
      if (jsonMatch) {
        const parsed = JSON.parse(jsonMatch[0]);
        feedback = parsed.feedback ?? '';
      }
    } catch {
      feedback = content;
    }

    const report: QualityReport = {
      imageId,
      characterId: dna.id,
      taskId,
      scores,
      totalScore: roundedTotal,
      passed: roundedTotal >= threshold,
      feedback,
      createdAt: new Date().toISOString(),
    };

    logger.info(
      { imageId, totalScore: roundedTotal, passed: report.passed },
      'VLM analysis complete',
    );

    return report;
  }
}

function clampScore(value: unknown): number {
  const num = Number(value);
  if (isNaN(num)) return 0;
  return Math.min(10, Math.max(0, Math.round(num * 100) / 100));
}

export function createVLMAnalyzer(): VLMAnalyzer {
  return new VLMAnalyzer(createOpenRouterClient());
}
