import { getUserFromRequest } from '../../../lib/permission-middleware';
import { checkScanRateLimit } from '../../../lib/rate-limit.js';
import { analyzeCardImage } from '../../../lib/scan-vision.js';
import { matchCardInCatalog, logScanAttempt } from '../../../lib/card-catalog-match.js';

function scanErrorResponse(error) {
  const msg = error?.message || '';

  if (msg.includes('AI_GATEWAY_API_KEY is not configured')) {
    return {
      status: 503,
      body: {
        error: 'Card scanning is not configured on this server (missing AI_GATEWAY_API_KEY).',
      },
    };
  }

  if (msg.includes('Vision API error: 429')) {
    return {
      status: 502,
      body: {
        error: 'Vision service quota exceeded. Check AI Gateway billing or try again later.',
      },
    };
  }

  if (msg.includes('Vision API error: 403') || msg.includes('PERMISSION_DENIED')) {
    return {
      status: 502,
      body: {
        error: 'Vision service access denied. Check AI Gateway model access and API key.',
      },
    };
  }

  if (msg.includes('scan_attempts') || msg.includes('card_submissions')) {
    return {
      status: 503,
      body: {
        error: 'Scan database tables are missing. Run npm run migrate up on the deployment database.',
      },
    };
  }

  return {
    status: 500,
    body: { error: 'Internal server error' },
  };
}

function formatCardResponse(card, ocrResult) {
  return {
    id: card.id,
    name: card.name,
    set_name: card.set_name,
    set_code: card.set_code,
    card_number: card.card_number,
    game: card.game,
    card_type: card.card_type,
    rarity: card.rarity,
    hp: card.power,
    mana_cost: card.mana_cost,
    image_url: card.image_url,
    ocr: {
      confidence: ocrResult.confidence,
      rawText: ocrResult.rawText,
      abilities: ocrResult.abilities,
    },
  };
}

function buildOcrPayload(ocrResult) {
  return {
    confidence: ocrResult.confidence,
    rawText: ocrResult.rawText,
    cardName: ocrResult.cardName,
    setName: ocrResult.setName,
    setCode: ocrResult.setCode,
    cardNumber: ocrResult.cardNumber,
    abilities: ocrResult.abilities,
  };
}

export default async function handler(req, res) {
  if (req.method !== 'POST') {
    return res.status(405).json({ error: 'Method not allowed' });
  }

  const startedAt = Date.now();

  try {
    const user = await getUserFromRequest(req);
    if (!user) {
      return res.status(401).json({ error: 'Authentication required' });
    }

    const { allowed, reset } = await checkScanRateLimit(req, user.userId);
    if (!allowed) {
      res.setHeader('Retry-After', Math.ceil((reset - Date.now()) / 1000));
      return res.status(429).json({ error: 'Too many attempts. Try again later.' });
    }

    const { imageData, game: preferredGame } = req.body || {};

    if (!imageData || typeof imageData !== 'string') {
      return res.status(400).json({ error: 'imageData is required' });
    }

    if (imageData.length > 6_000_000) {
      return res.status(400).json({ error: 'Image payload too large' });
    }

    const ocrResult = await analyzeCardImage(imageData);
    const latencyMs = Date.now() - startedAt;
    const hasPartialCard =
      ocrResult.cardName &&
      typeof ocrResult.cardName === 'string' &&
      ocrResult.cardName.trim().length > 0;

    if ((!ocrResult.isCard || ocrResult.confidence <= 60) && !hasPartialCard) {
      await logScanAttempt({
        userId: user.userId,
        ocrText: ocrResult.rawText,
        ocrConfidence: ocrResult.confidence,
        layer: 2,
        resultKind: 'not_a_card',
        latencyMs,
      });
      return res.status(200).json({
        isCard: false,
        confidence: ocrResult.confidence,
        reason: ocrResult.reason || 'No trading card detected',
      });
    }

    const matchResult = await matchCardInCatalog({
      userId: user.userId,
      name: ocrResult.cardName,
      set: ocrResult.setName,
      setCode: ocrResult.setCode,
      cardNumber: ocrResult.cardNumber,
      game: preferredGame || ocrResult.game,
      cardType: ocrResult.cardType,
      rarity: ocrResult.rarity,
      hp: ocrResult.hp,
      manaCost: ocrResult.manaCost,
      ocrData: {
        confidence: ocrResult.confidence,
        rawText: ocrResult.rawText,
        abilities: ocrResult.abilities,
      },
      scanImageUrl: null,
    });

    if (matchResult.type === 'matched') {
      await logScanAttempt({
        userId: user.userId,
        ocrText: ocrResult.rawText,
        ocrConfidence: ocrResult.confidence,
        layer: 2,
        matchedCardId: matchResult.card.id,
        resultKind: 'matched',
        latencyMs,
      });
      return res.status(200).json({
        isCard: true,
        card: formatCardResponse(matchResult.card, ocrResult),
        isExisting: matchResult.isExisting,
        message: matchResult.message,
      });
    }

    if (matchResult.type === 'disambiguation') {
      await logScanAttempt({
        userId: user.userId,
        ocrText: ocrResult.rawText,
        ocrConfidence: ocrResult.confidence,
        layer: 2,
        resultKind: 'disambiguation',
        latencyMs,
      });
      return res.status(200).json({
        isCard: true,
        card: null,
        matches: matchResult.matches,
        needsUserSelection: true,
        ocr: buildOcrPayload(ocrResult),
        message: matchResult.message,
      });
    }

    if (matchResult.type === 'submitted') {
      await logScanAttempt({
        userId: user.userId,
        ocrText: ocrResult.rawText,
        ocrConfidence: ocrResult.confidence,
        layer: 2,
        resultKind: 'submitted',
        latencyMs,
      });
      return res.status(200).json({
        isCard: true,
        card: null,
        submissionId: matchResult.submissionId,
        needsReview: true,
        ocr: buildOcrPayload(ocrResult),
        message: matchResult.message,
      });
    }

    await logScanAttempt({
      userId: user.userId,
      ocrText: ocrResult.rawText,
      ocrConfidence: ocrResult.confidence,
      layer: 2,
      resultKind: 'needs_input',
      latencyMs,
    });

    return res.status(200).json({
      isCard: true,
      card: null,
      needsUserInput: true,
      ocr: buildOcrPayload(ocrResult),
      message: matchResult.message,
    });
  } catch (error) {
    console.error('[POST /api/scan/identify]', error);
    const { status, body } = scanErrorResponse(error);
    return res.status(status).json(body);
  }
}
