const GATEWAY_URL = 'https://ai-gateway.vercel.sh/v1/chat/completions';
const DEFAULT_VISION_MODEL =
  process.env.SCAN_VISION_MODEL || 'google/gemini-2.5-flash-lite';

const CARD_PROMPT = `You are a specialized trading card recognition system. Analyze this image and determine if it contains a trading card (Magic: The Gathering, Pokemon, Yu-Gi-Oh, Lorcana, etc.).

HOLOGRAPHIC / FOIL CARDS: Many cards have reflective foil surfaces with glare or rainbow streaks. Do NOT reject these as "not a card" — read through glare when possible and extract any visible name, set, and collector number.

CRITICAL: Only respond with card data if you can clearly identify a TRADING CARD in the image. Ignore random objects, books, papers, phone screens, screenshots, and non-card gaming items. Blurry images with no readable card frame should be rejected.

Respond with JSON only (no markdown fences) using this shape:
{
  "isCard": true,
  "cardName": "exact card name",
  "setName": "set name or null",
  "setCode": "set code or null",
  "cardNumber": "collector number or null",
  "game": "mtg, pokemon, or lorcana",
  "cardType": "creature, instant, etc.",
  "rarity": "common, uncommon, rare, mythic, etc.",
  "manaCost": "mana cost or null",
  "hp": "HP or power or null",
  "abilities": ["ability strings"],
  "confidence": 85,
  "rawText": "all visible text",
  "reason": null
}

If NO trading card is clearly visible, respond with:
{
  "isCard": false,
  "cardName": null,
  "setName": null,
  "setCode": null,
  "cardNumber": null,
  "game": null,
  "cardType": null,
  "rarity": null,
  "manaCost": null,
  "hp": null,
  "abilities": [],
  "confidence": 0,
  "rawText": null,
  "reason": "No trading card detected in image"
}

Be conservative — only extract data you can clearly read. Quality over quantity.`;

const CARD_VISION_SCHEMA = {
  name: 'card_scan_result',
  strict: true,
  schema: {
    type: 'object',
    additionalProperties: false,
    properties: {
      isCard: { type: 'boolean' },
      cardName: { type: ['string', 'null'] },
      setName: { type: ['string', 'null'] },
      setCode: { type: ['string', 'null'] },
      cardNumber: { type: ['string', 'null'] },
      game: { type: ['string', 'null'] },
      cardType: { type: ['string', 'null'] },
      rarity: { type: ['string', 'null'] },
      manaCost: { type: ['string', 'null'] },
      hp: { type: ['string', 'null'] },
      abilities: {
        type: 'array',
        items: { type: 'string' },
      },
      confidence: { type: 'number' },
      rawText: { type: ['string', 'null'] },
      reason: { type: ['string', 'null'] },
    },
    required: [
      'isCard',
      'cardName',
      'setName',
      'setCode',
      'cardNumber',
      'game',
      'cardType',
      'rarity',
      'manaCost',
      'hp',
      'abilities',
      'confidence',
      'rawText',
      'reason',
    ],
  },
};

export class VisionParseError extends Error {
  constructor(message) {
    super(message);
    this.name = 'VisionParseError';
  }
}

function parseVisionJson(content) {
  if (!content || typeof content !== 'string') {
    throw new VisionParseError('Empty vision model response');
  }

  const cleanContent = content.replace(/```json\n?/g, '').replace(/```\n?/g, '').trim();
  try {
    return JSON.parse(cleanContent);
  } catch {
    throw new VisionParseError('Failed to parse structured vision response');
  }
}

function normalizeGame(game) {
  if (!game) return null;
  const value = String(game).trim().toLowerCase();
  if (value === 'mtg' || value.includes('magic')) return 'mtg';
  if (value.includes('pokemon') || value.includes('pokémon')) return 'pokemon';
  if (value.includes('lorcana')) return 'lorcana';
  return value;
}

function buildGatewayBody(imageDataUrl, { structured = true } = {}) {
  const body = {
    model: DEFAULT_VISION_MODEL,
    temperature: 0.1,
    messages: [{
      role: 'user',
      content: [
        { type: 'text', text: CARD_PROMPT },
        { type: 'image_url', image_url: { url: imageDataUrl } },
      ],
    }],
  };

  if (structured) {
    body.response_format = {
      type: 'json_schema',
      json_schema: CARD_VISION_SCHEMA,
    };
  }

  return body;
}

/**
 * Server-side vision analysis via Vercel AI Gateway. Requires AI_GATEWAY_API_KEY.
 * @param {string} imageDataUrl - data:image/jpeg;base64,... capture from scanner
 */
export async function analyzeCardImage(imageDataUrl) {
  const apiKey = process.env.AI_GATEWAY_API_KEY;
  if (!apiKey) {
    throw new Error('AI_GATEWAY_API_KEY is not configured on the server');
  }

  if (!imageDataUrl?.includes(',')) {
    throw new Error('Invalid image data format');
  }

  let response = await fetch(GATEWAY_URL, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      Authorization: `Bearer ${apiKey}`,
    },
    body: JSON.stringify(buildGatewayBody(imageDataUrl)),
  });

  if (!response.ok && response.status === 400) {
    response = await fetch(GATEWAY_URL, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        Authorization: `Bearer ${apiKey}`,
      },
      body: JSON.stringify(buildGatewayBody(imageDataUrl, { structured: false })),
    });
  }

  if (!response.ok) {
    const errorData = await response.json().catch(() => ({}));
    const message = errorData.error?.message || errorData.message || 'Unknown error';
    throw new Error(`Vision API error: ${response.status} - ${message}`);
  }

  const data = await response.json();
  const content = data.choices?.[0]?.message?.content;
  if (!content) {
    throw new VisionParseError('No response from vision model');
  }

  const result = parseVisionJson(content);

  return {
    isCard: result.isCard || false,
    cardName: result.cardName || null,
    setName: result.setName || null,
    setCode: result.setCode || null,
    cardNumber: result.cardNumber || null,
    game: normalizeGame(result.game),
    cardType: result.cardType || null,
    rarity: result.rarity || null,
    manaCost: result.manaCost || null,
    hp: result.hp || null,
    abilities: result.abilities || [],
    confidence: result.confidence || 0,
    rawText: result.rawText || content,
    reason: result.reason || null,
  };
}
