import { sql } from '@vercel/postgres';

import { cardNumbersEquivalent, normalizeCardNumber } from '../card-number-utils.js';

export { normalizeCardNumber };

function normalizeGame(value) {
  if (!value || typeof value !== 'string') return null;
  const lower = value.trim().toLowerCase();
  if (lower === 'mtg' || lower === 'magic') return 'MTG';
  if (lower === 'pokemon' || lower === 'pokémon') return 'Pokemon';
  if (lower === 'lorcana') return 'Lorcana';
  return value.trim();
}

function importedSetGame(game) {
  return game === 'pokemon' ? 'Pokemon' : 'MTG';
}

/**
 * Whether a pending submission's OCR payload refers to the set that was just imported.
 */
export function submissionPayloadMatchesSet(payload, { game, setCode, setName }) {
  if (!payload || typeof payload !== 'object') return false;

  const payloadGame = normalizeGame(payload.game);
  const expectedGame = importedSetGame(game);
  if (payloadGame && payloadGame !== expectedGame) {
    return false;
  }

  const code = (setCode || '').trim().toLowerCase();
  const name = (setName || '').trim().toLowerCase();
  const payloadSetCode = (payload.setCode || '').trim().toLowerCase();
  const payloadSet = (payload.set || '').trim().toLowerCase();

  if (!code && !name) return false;

  return Boolean(
    (payloadSetCode && payloadSetCode === code) ||
      (payloadSet && (payloadSet === code || payloadSet === name))
  );
}

function cardNumberMatches(catalogNumber, payloadNumber) {
  if (!payloadNumber) return true;
  if (!catalogNumber) return false;
  return cardNumbersEquivalent(catalogNumber, payloadNumber);
}

/**
 * Pick the catalog row that satisfies a submission payload within an imported set.
 * Returns the card id or null when ambiguous / no match.
 */
export function pickCatalogCardForPayload(catalogRows, payload) {
  if (!payload?.name || catalogRows.length === 0) return null;

  const cardNumber = payload.cardNumber?.trim() || null;
  const matches = catalogRows.filter((row) => cardNumberMatches(row.card_number, cardNumber));

  if (cardNumber) {
    return matches.length === 1 ? matches[0].id : null;
  }

  return matches.length === 1 ? matches[0].id : null;
}

/**
 * Find pending submissions for a set and link them to catalog rows when unambiguous.
 */
export async function reconcileSubmissionsForImportedSet({ game, setCode, setName }) {
  const summary = {
    game,
    setCode,
    setName,
    matched: 0,
    skipped: 0,
    details: [],
  };

  const pendingResult = await sql`
    SELECT id, ocr_payload
    FROM card_submissions
    WHERE status = 'pending'
    ORDER BY created_at ASC
  `;

  const relevant = pendingResult.rows.filter((row) => {
    const payload =
      typeof row.ocr_payload === 'string'
        ? JSON.parse(row.ocr_payload)
        : row.ocr_payload || {};
    return submissionPayloadMatchesSet(payload, { game, setCode, setName });
  });

  if (relevant.length === 0) {
    return summary;
  }

  const catalogResult = await sql`
    SELECT id, name, set_name, set_code, card_number, game
    FROM cards
    WHERE LOWER(set_code) = LOWER(${setCode})
       OR LOWER(set_name) = LOWER(${setName || setCode})
  `;

  const catalogRows = catalogResult.rows.filter(
    (row) => row.game === importedSetGame(game)
  );

  for (const submission of relevant) {
    const payload =
      typeof submission.ocr_payload === 'string'
        ? JSON.parse(submission.ocr_payload)
        : submission.ocr_payload || {};

    const trimmedName = payload.name?.trim().toLowerCase();
    const nameMatches = catalogRows.filter(
      (row) => row.name?.trim().toLowerCase() === trimmedName
    );
    const cardId = pickCatalogCardForPayload(nameMatches, payload);

    if (!cardId) {
      summary.skipped += 1;
      continue;
    }

    const updateResult = await sql`
      UPDATE card_submissions
      SET
        status = 'approved',
        promoted_card_id = ${cardId},
        updated_at = CURRENT_TIMESTAMP
      WHERE id = ${submission.id}
        AND status = 'pending'
      RETURNING id
    `;

    if (updateResult.rows.length === 0) {
      summary.skipped += 1;
      continue;
    }

    summary.matched += 1;
    summary.details.push({
      submissionId: submission.id,
      cardId,
      name: payload.name,
      cardNumber: payload.cardNumber || null,
    });
  }

  if (summary.matched > 0) {
    console.log(
      `[reconcileSubmissionsForImportedSet] ${game}/${setCode}: matched ${summary.matched} submission(s)`
    );
  }

  return summary;
}
