import { fetchSales } from './erpClient';
import { discoverTableIds, deleteRowsByMonth, deleteAllRows, insertRecords } from './nocodbClient';
import { getMuseumsFromProduct, getChannelLabel, getDistrict } from '../config/museumMapping';
import type { ERPSaleRecord, AggregatedRecord } from '../types';

function generateMonthBoundaries(startYear: number, startMonth: number): Array<[string, string]> {
  const now = new Date();
  const endYear = now.getFullYear();
  const endMonth = now.getMonth() + 1;
  const boundaries: Array<[string, string]> = [];

  let y = startYear;
  let m = startMonth;
  while (y < endYear || (y === endYear && m <= endMonth)) {
    const start = `${y}-${String(m).padStart(2, '0')}-01T00:00:00`;
    const nextM = m === 12 ? 1 : m + 1;
    const nextY = m === 12 ? y + 1 : y;
    const end = `${nextY}-${String(nextM).padStart(2, '0')}-01T00:00:00`;
    boundaries.push([start, end]);
    y = nextY;
    m = nextM;
  }

  return boundaries;
}

function currentMonthBoundary(): [string, string] {
  const now = new Date();
  const y = now.getFullYear();
  const m = now.getMonth() + 1;
  const start = `${y}-${String(m).padStart(2, '0')}-01T00:00:00`;
  const nextM = m === 12 ? 1 : m + 1;
  const nextY = m === 12 ? y + 1 : y;
  const end = `${nextY}-${String(nextM).padStart(2, '0')}-01T00:00:00`;
  return [start, end];
}

export function aggregateTransactions(sales: ERPSaleRecord[]): AggregatedRecord[] {
  const map = new Map<string, AggregatedRecord>();

  for (const sale of sales) {
    const date = sale.TransactionDate.split(' ')[0];
    const rawChannel = sale.OperatingAreaName;
    const channel = getChannelLabel(rawChannel);
    // B2C: each ticket = one visitor (1 PDF per person)
    // Other channels: PeopleCount = actual visitors (group tickets)
    const isB2C = rawChannel === 'B2C';

    for (const product of sale.Products) {
      const { museums, split } = getMuseumsFromProduct(product.ProductDescription);
      const isCombo = museums.length > 1;

      for (const museum of museums) {
        const comboWith = isCombo
          ? museums.filter(m => m !== museum).join(', ')
          : '';
        const ticketType = isCombo ? 'combo' : 'single';
        const district = getDistrict(museum);
        const key = `${date}|${museum}|${channel}|${ticketType}`;

        let entry = map.get(key);
        if (!entry) {
          entry = {
            Date: date,
            District: district,
            MuseumName: museum,
            Channel: channel,
            TicketType: ticketType,
            ComboMuseums: museums.length,
            ComboWith: comboWith,
            Visits: 0,
            Tickets: 0,
            GrossRevenue: 0,
            NetRevenue: 0,
          };
          map.set(key, entry);
        }

        const visitors = isB2C ? product.UnitQuantity : product.PeopleCount;
        entry.Visits += visitors * split;
        entry.Tickets += product.UnitQuantity * split;
        entry.GrossRevenue += product.TotalPrice * split;
        entry.NetRevenue += (product.TotalPrice - product.TaxAmount) * split;
      }
    }
  }

  return Array.from(map.values());
}

export interface SyncResult {
  status: string;
  mode: string;
  transactionsFetched: number;
  recordsWritten: number;
  duration: string;
}

export async function runSync(mode: 'full' | 'incremental' = 'incremental'): Promise<SyncResult> {
  const start = Date.now();

  const tables = await discoverTableIds();
  const tableId = tables['DailySales'];
  if (!tableId) throw new Error("NocoDB table 'DailySales' not found");

  let months: Array<[string, string]>;
  if (mode === 'full') {
    months = generateMonthBoundaries(2024, 1);
  } else {
    months = [currentMonthBoundary()];
  }

  // Fetch from ERP sequentially (API can't handle concurrent requests)
  const allSales: ERPSaleRecord[] = [];
  for (const [startDate, endDate] of months) {
    console.log(`  Fetching ${startDate.slice(0, 7)}...`);
    const chunk = await fetchSales(startDate, endDate) as ERPSaleRecord[];
    allSales.push(...chunk);
  }

  const records = aggregateTransactions(allSales);

  // Write to NocoDB
  if (mode === 'full') {
    console.log('  Clearing all DailySales rows...');
    await deleteAllRows(tableId);
  } else {
    const yearMonth = months[0][0].slice(0, 7);
    console.log(`  Clearing ${yearMonth} rows...`);
    await deleteRowsByMonth(tableId, yearMonth);
  }

  console.log(`  Inserting ${records.length} records...`);
  const written = await insertRecords(tableId, records);

  const duration = ((Date.now() - start) / 1000).toFixed(1) + 's';

  return {
    status: 'ok',
    mode,
    transactionsFetched: allSales.length,
    recordsWritten: written,
    duration,
  };
}
