const { parse } = require('csv-parse/sync');
const UnitOfWork = require('../../database/UnitOfWork');
const TaxRepository = require('../../repositories/tax/taxRepository');

const HEADERS = [
  'Country',
  'Super-Reduced Rate (%)',
  'Reduced Rate (%)',
  'Parking Rate (%)',
  'Standard Rate (%)'
];

function parseRate(raw) {
  if (!raw) return null;
  const cleaned = String(raw).replace(/"/g, '').replace(/%/g, '').trim();
  if (!cleaned || cleaned === '-') return null;
  const parts = cleaned.split('/').map((p) => p.trim().replace(',', '.'));
  const nums = parts.map((p) => Number(p)).filter((n) => !Number.isNaN(n));
  if (!nums.length) return null;
  return Math.max(...nums);
}

function extractCountry(value) {
  const str = String(value || '').trim();
  const match = str.match(/^(.*)\((\w{2,3})\)\s*$/);
  if (match) return { name: match[1].trim(), code: match[2].trim().toUpperCase() };
  return { name: str, code: str.slice(0, 2).toUpperCase() };
}

function normalizeRows(rows) {
  return rows.map((row) => {
    const country = extractCountry(row['Country']);
    return {
      country_name: country.name,
      country_code: country.code,
      rates: {
        standard_rate: parseRate(row['Standard Rate (%)']),
        reduced_rate: parseRate(row['Reduced Rate (%)']),
        super_reduced_rate: parseRate(row['Super-Reduced Rate (%)']),
        parking_rate: parseRate(row['Parking Rate (%)'])
      }
    };
  });
}

async function importRates(entries, actorUserId) {
  const uow = new UnitOfWork();
  await uow.start();
  const repo = new TaxRepository(uow);
  try {
    const uniqueCountries = [];
    const seen = new Set();
    for (const e of entries) {
      if (!seen.has(e.country_code)) {
        uniqueCountries.push({ code: e.country_code, name: e.country_name });
        seen.add(e.country_code);
      }
    }
    const countryStats = await repo.upsertCountries(uniqueCountries, actorUserId);
    const codeMap = await repo.getCountriesByCodes(Array.from(seen));
    const payloads = entries
      .map((e) => ({ country_id: codeMap[e.country_code]?.id, rates: e.rates }))
      .filter((p) => p.country_id);
    const rateStats = await repo.bulkImportVatRates(payloads, actorUserId);
    await uow.commit();
    return {
      totalRows: entries.length,
      countriesCreated: countryStats.created,
      countriesUpdated: countryStats.updated,
      ratesUpdated: rateStats.ratesUpdated,
      ratesSkipped: rateStats.ratesSkipped
    };
  } catch (err) {
    await uow.rollback();
    throw err;
  }
}

async function listCurrentRates() {
  const uow = new UnitOfWork();
  await uow.start();
  const repo = new TaxRepository(uow);
  try {
    const data = await repo.getAllCurrentVatRates();
    await uow.commit();
    return data;
  } catch (err) {
    await uow.rollback();
    throw err;
  }
}

async function getHistory(countryCode) {
  const uow = new UnitOfWork();
  await uow.start();
  const repo = new TaxRepository(uow);
  try {
    const country = await repo.getCountryByCode(countryCode);
    if (!country) throw new Error('Country not found');
    const history = await repo.getVatHistory(country.id);
    await uow.commit();
    return { country, history };
  } catch (err) {
    await uow.rollback();
    throw err;
  }
}

module.exports = {
  parseCsv(buffer) {
    const records = parse(buffer, { columns: true, skip_empty_lines: true, trim: true });
    const headers = Object.keys(records[0] || {});
    const missing = HEADERS.filter((h) => !headers.includes(h));
    if (missing.length) throw new Error(`Missing headers: ${missing.join(', ')}`);
    return normalizeRows(records);
  },
  importRates,
  listCurrentRates,
  getHistory
};
