const { upsertCard } = require('../models/cardModel');
const { upsertRarity } = require('../models/rarityModel');
const { upsertSet } = require('../models/setModel');
const { insertCardSetRarity } = require('../models/cardSetRarityModel');
const { insertCardImage } = require('../models/cardImageModel');
const { getLocalDBVersion, setLocalDBVersion } = require('../models/dbVersionModel');
const { fetchAllCards, fetchAllSets, fetchDatabaseVersion } = require('../services/ygoproService');
const db = require('../config/db');

const BATCH_SIZE = 50;

async function importSetsInternal() {
  const sets = await fetchAllSets();
  let added = 0;

  for (let i = 0; i < sets.length; i += BATCH_SIZE) {
    const batch = sets.slice(i, i + BATCH_SIZE);
    await Promise.all(batch.map(async (set) => {
      await upsertSet(set);
      added++;
    }));
  }

  return {
    added,
    total: sets.length
  };
}

// Express handler for /sets endpoint
async function importSets(req, res) {
  try {
    const result = await importSetsInternal();
    res.json(result);
  } catch (err) {
    console.error('Error importing sets:', err);
    res.status(500).json({ error: 'Failed to import sets' });
  }
}

async function importCardsInternal() {
  const startTime = Date.now();
  const cards = await fetchAllCards();
  const totalCards = cards.length;

  let addedCards = 0, addedImages = 0, addedRarities = 0;

  const rarityCache = {};
  const setCache = {};

  const [setsRows] = await db.execute('SELECT id, set_name FROM sets');
  for (const row of setsRows) {
    setCache[row.set_name] = row.id;
  }

  const [rarityRows] = await db.execute('SELECT id, rarity_name FROM rarities');
  for (const row of rarityRows) {
    rarityCache[row.rarity_name] = row.id;
  }

  for (let i = 0; i < totalCards; i += BATCH_SIZE) {
    const batch = cards.slice(i, i + BATCH_SIZE);
    const conn = await db.getConnection();
    try {
      await conn.beginTransaction();

      await Promise.all(batch.map(async (card) => {
        await conn.execute(`
          INSERT INTO cards
            (id, name, card_type, frame_type, level, race, attribute, link_val, tcg_date, ocg_date)
          VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
          ON DUPLICATE KEY UPDATE
            name = VALUES(name),
            card_type = VALUES(card_type),
            frame_type = VALUES(frame_type),
            level = VALUES(level),
            race = VALUES(race),
            attribute = VALUES(attribute),
            link_val = VALUES(link_val),
            tcg_date = VALUES(tcg_date),
            ocg_date = VALUES(ocg_date)
        `, [
          card.id,
          card.name,
          card.type,
          card.frameType,
          card.level || null,
          card.race || null,
          card.attribute || null,
          card.linkval || null,
          card.tcg_date || null,
          card.ocg_date || null
        ]);
        addedCards++;

        if (Array.isArray(card.card_sets)) {
          for (const set of card.card_sets) {
            if (!rarityCache[set.set_rarity]) {
              await conn.execute(`
                INSERT INTO rarities (rarity_name, rarity_code)
                VALUES (?, ?)
                ON DUPLICATE KEY UPDATE rarity_code = VALUES(rarity_code)
              `, [set.set_rarity, set.set_rarity_code]);
              const [rows] = await conn.execute('SELECT id FROM rarities WHERE rarity_name = ? LIMIT 1', [set.set_rarity]);
              rarityCache[set.set_rarity] = rows[0].id;
              addedRarities++;
            }
            const rarity_id = rarityCache[set.set_rarity];
            const set_id = setCache[set.set_name];
            if (set_id) {
              await conn.execute(`
                INSERT INTO card_sets_rarity (card_id, set_id, rarity_id, card_set_code)
                VALUES (?, ?, ?, ?)
                ON DUPLICATE KEY UPDATE card_set_code = VALUES(card_set_code)
              `, [card.id, set_id, rarity_id, set.set_code]);
            }
          }
        }

        if (Array.isArray(card.card_images)) {
          for (const img of card.card_images) {
            await conn.execute(`
              INSERT INTO card_images (image_id, card_id, image_url)
              VALUES (?, ?, ?)
              ON DUPLICATE KEY UPDATE image_url = VALUES(image_url)
            `, [img.id, card.id, img.image_url]);
            addedImages++;
          }
        }
      }));

      await conn.commit();
    } catch (err) {
      await conn.rollback();
      throw err;
    } finally {
      conn.release();
    }

  }

  const durationSeconds = ((Date.now() - startTime) / 1000).toFixed(2);

  return {
    total_cards: totalCards,
    cards_added: addedCards,
    images_added: addedImages,
    rarities_added: addedRarities,
    duration_seconds: parseFloat(durationSeconds)
  };
}

// Express handler for /cards
async function importCards(req, res) {
  try {
    const result = await importCardsInternal();
    res.json(result);
  } catch (err) {
    console.error('Error importing cards:', err);
    res.status(500).json({ error: 'Failed to import cards' });
  }
}


async function importFullDatabase(req, res) {
  const startTime = Date.now();
  try {
    const remoteVersion = await fetchDatabaseVersion();
    const localVersion = await getLocalDBVersion();

    if (localVersion && localVersion.database_version === remoteVersion.database_version) {
      return res.json({ message: 'Database is already up to date.', version: remoteVersion.database_version });
    }

    const setsStats = await importSetsInternal();
    const cardsStats = await importCardsInternal();
    await setLocalDBVersion(remoteVersion.database_version, remoteVersion.last_update);

    res.json({
      message: 'Database import completed successfully.',
      version: remoteVersion.database_version,
      sets: setsStats,
      cards: cardsStats,
      duration_seconds: parseFloat(((Date.now() - startTime) / 1000).toFixed(2)),
    });
  } catch (err) {
    console.error('Error in full database import:', err);
    res.status(500).json({ error: 'Failed to import database' });
  }
}

module.exports = { importCards, importCardsInternal, importSets, importSetsInternal, importFullDatabase };