/**
 * Client Portal mock data generator.
 *
 * Produces all portal-specific data types using the seeded PRNG system
 * for deterministic output. All financial values are in CLP (Chilean Pesos).
 */

import type { SeededRng } from '@/lib/mock-data/seed';
import type {
  PortalPeriod,
  FinancialTimePoint,
  PortalTopSong,
  PortalIncomeGroup,
  PortalExploitationSource,
  PortalTerritory,
  PortalStatement,
  PortalDocument,
  PortalSong,
  PortalSongDetail,
  PortalIncomeGroupDetail,
  PortalTerritoryDetail,
  PortalSourceDetail,
} from '@/lib/mock-data/types';

// ─── Constants ───────────────────────────────────────────────────────────────

const MONTH_NAMES_ES = [
  'enero', 'febrero', 'marzo', 'abril', 'mayo', 'junio',
  'julio', 'agosto', 'septiembre', 'octubre', 'noviembre', 'diciembre',
] as const;

const MONTH_ABBR_ES = [
  'Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun',
  'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic',
] as const;

const SONG_TITLES = [
  'Corazón de Fuego', 'Noche Eterna', 'Caminos del Sur', 'Lluvia en Santiago',
  'Alma Libre', 'Viento del Norte', 'Sueños de Cristal', 'Mar Profundo',
  'Estrella Fugaz', 'Ritmo Salvaje', 'Cielo Abierto', 'Tierra Prometida',
  'Luna Nueva', 'Sol de Invierno', 'Río de Plata', 'Montaña Sagrada',
  'Flor del Desierto', 'Olas del Pacífico', 'Canción sin Nombre', 'Amanecer',
] as const;

const COMPOSER_NAMES = [
  'Eduardo Iensen Rufin', 'María González', 'Carlos Pérez', 'Ana Morales',
  'Diego Fernández', 'Valentina Rojas', 'Sebastián Muñoz', 'Camila Torres',
  'Andrés Silva', 'Francisca López',
] as const;

const INCOME_CATEGORIES = [
  'Synchronisation', 'Digital Mechanical', 'Digital Performance', 'Performance',
  'Broadcast', 'Print',
] as const;

const PLATFORMS = [
  'Spotify', 'YouTube', 'SCD', 'Apple Music', 'Amazon Music', 'Deezer', 'Others',
] as const;

const TERRITORIES = [
  'Chile', 'United States', 'Spain', 'Peru', 'Argentina',
  'Mexico', 'Colombia', 'Brazil', 'United Kingdom', 'Germany',
] as const;

const DOCUMENT_TYPES: Array<'statement' | 'contract' | 'report'> = [
  'statement', 'contract', 'report',
];

// ─── Helper Functions ────────────────────────────────────────────────────────

/** Generate a quarterly period label in Spanish, e.g., "enero 2026 - marzo 2026" */
function quarterLabel(year: number, quarter: number): string {
  const startMonth = (quarter - 1) * 3;
  const endMonth = startMonth + 2;
  return `${MONTH_NAMES_ES[startMonth]} ${year} - ${MONTH_NAMES_ES[endMonth]} ${year}`;
}

/** Generate a realistic ISWC code */
function generateIswc(rng: SeededRng): string {
  const a = String(rng.randomInt(0, 999)).padStart(3, '0');
  const b = String(rng.randomInt(0, 999)).padStart(3, '0');
  const c = String(rng.randomInt(0, 999)).padStart(3, '0');
  const check = rng.randomInt(0, 9);
  return `T-${a}.${b}.${c}-${check}`;
}

// ─── Generator Functions ─────────────────────────────────────────────────────

/**
 * Generate quarterly period data.
 *
 * @param rng   - Seeded PRNG instance
 * @param count - Number of periods to generate (default 8 = 2 years)
 */
export function generatePortalPeriods(rng: SeededRng, count: number = 8): PortalPeriod[] {
  const periods: PortalPeriod[] = [];
  const statuses: PortalPeriod['status'][] = ['Activo', 'Establecido', 'Pendiente'];
  const baseYear = 2024;

  for (let i = 0; i < count; i++) {
    const quarter = (i % 4) + 1;
    const year = baseYear + Math.floor(i / 4);
    const startMonth = (quarter - 1) * 3;

    const balance = Math.round(rng.randomFloat(-10000000, 10000000));
    const advances = Math.round(rng.randomFloat(0, 5000000));
    const adjustments = Math.round(rng.randomFloat(-2000000, 2000000));
    const netEarnings = Math.round(balance - advances + adjustments);

    periods.push({
      id: `PER-${String(i + 1).padStart(3, '0')}`,
      label: quarterLabel(year, quarter),
      startDate: new Date(year, startMonth, 1),
      endDate: new Date(year, startMonth + 3, 0), // last day of end month
      status: i === 0 ? 'Activo' : rng.pick(statuses),
      balance,
      advances,
      adjustments,
      netEarnings,
    });
  }

  return periods;
}

/**
 * Generate time-series data for the financial summary chart.
 * Spans at least 18 months.
 *
 * @param rng   - Seeded PRNG instance
 * @param count - Number of months to generate (default 24)
 */
export function generateFinancialTimeSeries(rng: SeededRng, count: number = 24): FinancialTimePoint[] {
  const points: FinancialTimePoint[] = [];
  const startYear = 2024;
  const startMonth = 0; // January

  let runningBalance = Math.round(rng.randomFloat(1000000, 5000000));

  for (let i = 0; i < count; i++) {
    const monthIndex = (startMonth + i) % 12;
    const year = startYear + Math.floor((startMonth + i) / 12);
    const month = `${MONTH_ABBR_ES[monthIndex]} ${year}`;

    const netEarnings = Math.round(rng.randomFloat(-2000000, 8000000));
    runningBalance = Math.round(runningBalance + netEarnings * 0.1);

    points.push({
      month,
      netEarnings,
      finalBalance: runningBalance,
    });
  }

  return points;
}

/**
 * Generate top songs data for the analytics view.
 *
 * @param rng   - Seeded PRNG instance
 * @param count - Number of songs to generate (default 10)
 */
export function generatePortalTopSongs(rng: SeededRng, count: number = 10): PortalTopSong[] {
  const songs: PortalTopSong[] = [];
  const usedTitles = new Set<string>();

  for (let i = 0; i < count; i++) {
    let title: string = rng.pick(SONG_TITLES);
    // Ensure unique titles by appending suffix if needed
    while (usedTitles.has(title)) {
      title = `${rng.pick(SONG_TITLES)} (${rng.randomInt(2, 9)})`;
    }
    usedTitles.add(title);

    const composerCount = rng.randomInt(1, 3);
    const composers: string[] = [];
    for (let c = 0; c < composerCount; c++) {
      composers.push(rng.pick(COMPOSER_NAMES));
    }

    songs.push({
      id: `PSNG-${String(i + 1).padStart(4, '0')}`,
      title,
      composers,
      income: Math.round(rng.randomFloat(100000, 5000000)),
      percentage: 0, // will be calculated below
    });
  }

  // Calculate percentages based on total income
  const totalIncome = songs.reduce((sum, s) => sum + s.income, 0);
  for (const song of songs) {
    song.percentage = totalIncome > 0
      ? Math.round((song.income / totalIncome) * 10000) / 100
      : 0;
  }

  return songs;
}

/**
 * Generate income group data.
 *
 * @param rng   - Seeded PRNG instance
 * @param count - Number of categories (default uses all INCOME_CATEGORIES)
 */
export function generatePortalIncomeGroups(rng: SeededRng, count?: number): PortalIncomeGroup[] {
  const numCategories = count ?? INCOME_CATEGORIES.length;
  const groups: PortalIncomeGroup[] = [];

  for (let i = 0; i < numCategories; i++) {
    groups.push({
      category: INCOME_CATEGORIES[i % INCOME_CATEGORIES.length],
      amount: Math.round(rng.randomFloat(500000, 10000000)),
      percentage: 0, // will be calculated below
    });
  }

  // Calculate percentages based on total amount
  const totalAmount = groups.reduce((sum, g) => sum + g.amount, 0);
  for (const group of groups) {
    group.percentage = totalAmount > 0
      ? Math.round((group.amount / totalAmount) * 10000) / 100
      : 0;
  }

  return groups;
}

/**
 * Generate exploitation source data.
 *
 * @param rng   - Seeded PRNG instance
 * @param count - Number of sources (default uses all PLATFORMS)
 */
export function generatePortalExploitationSources(rng: SeededRng, count?: number): PortalExploitationSource[] {
  const numSources = count ?? PLATFORMS.length;
  const sources: PortalExploitationSource[] = [];

  for (let i = 0; i < numSources; i++) {
    sources.push({
      platform: PLATFORMS[i % PLATFORMS.length],
      amount: Math.round(rng.randomFloat(200000, 8000000)),
      percentage: 0, // will be calculated below
      trend: Math.round(rng.randomFloat(-30, 50) * 10) / 10,
    });
  }

  // Calculate percentages based on total amount
  const totalAmount = sources.reduce((sum, s) => sum + s.amount, 0);
  for (const source of sources) {
    source.percentage = totalAmount > 0
      ? Math.round((source.amount / totalAmount) * 10000) / 100
      : 0;
  }

  return sources;
}

/**
 * Generate territory data.
 *
 * @param rng   - Seeded PRNG instance
 * @param count - Number of territories (default uses all TERRITORIES)
 */
export function generatePortalTerritories(rng: SeededRng, count?: number): PortalTerritory[] {
  const numTerritories = count ?? TERRITORIES.length;
  const territories: PortalTerritory[] = [];

  for (let i = 0; i < numTerritories; i++) {
    territories.push({
      country: TERRITORIES[i % TERRITORIES.length],
      amount: Math.round(rng.randomFloat(100000, 12000000)),
      percentage: 0, // will be calculated below
    });
  }

  // Calculate percentages based on total amount
  const totalAmount = territories.reduce((sum, t) => sum + t.amount, 0);
  for (const territory of territories) {
    territory.percentage = totalAmount > 0
      ? Math.round((territory.amount / totalAmount) * 10000) / 100
      : 0;
  }

  return territories;
}

/**
 * Generate downloadable statement entries.
 *
 * @param rng   - Seeded PRNG instance
 * @param count - Number of statements to generate (default 8)
 */
export function generatePortalStatements(rng: SeededRng, count: number = 8): PortalStatement[] {
  const stmts: PortalStatement[] = [];
  const baseYear = 2024;

  for (let i = 0; i < count; i++) {
    const quarter = (i % 4) + 1;
    const year = baseYear + Math.floor(i / 4);

    stmts.push({
      id: `PSTM-${String(i + 1).padStart(4, '0')}`,
      periodLabel: quarterLabel(year, quarter),
      downloadUrl: `/api/portal/statements/PSTM-${String(i + 1).padStart(4, '0')}/download`,
    });
  }

  return stmts;
}

/**
 * Generate document entries.
 *
 * @param rng   - Seeded PRNG instance
 * @param count - Number of documents to generate (default 12)
 */
export function generatePortalDocuments(rng: SeededRng, count: number = 12): PortalDocument[] {
  const docs: PortalDocument[] = [];

  for (let i = 0; i < count; i++) {
    const type = rng.pick(DOCUMENT_TYPES);
    const quarter = (i % 4) + 1;
    const year = 2024 + Math.floor(i / 4);

    let name: string;
    let periodLabel: string | undefined;

    switch (type) {
      case 'statement':
        name = `Declaración ${quarterLabel(year, quarter)}`;
        periodLabel = quarterLabel(year, quarter);
        break;
      case 'contract':
        name = `Contrato ${rng.randomInt(1000, 9999)}`;
        periodLabel = undefined;
        break;
      case 'report':
        name = `Informe ${MONTH_NAMES_ES[(quarter - 1) * 3]} ${year}`;
        periodLabel = quarterLabel(year, quarter);
        break;
    }

    docs.push({
      id: `PDOC-${String(i + 1).padStart(4, '0')}`,
      name,
      type,
      periodLabel,
      downloadUrl: `/api/portal/documents/PDOC-${String(i + 1).padStart(4, '0')}/download`,
    });
  }

  return docs;
}

/**
 * Generate song catalogue entries.
 *
 * @param rng   - Seeded PRNG instance
 * @param count - Number of songs to generate (default 20)
 */
export function generatePortalSongs(rng: SeededRng, count: number = 20): PortalSong[] {
  const songs: PortalSong[] = [];
  const startDate = new Date('2020-01-01');
  const endDate = new Date('2025-12-31');

  for (let i = 0; i < count; i++) {
    const composerCount = rng.randomInt(1, 3);
    const composers: string[] = [];
    for (let c = 0; c < composerCount; c++) {
      composers.push(rng.pick(COMPOSER_NAMES));
    }

    songs.push({
      id: `PCAT-${String(i + 1).padStart(4, '0')}`,
      title: rng.pick(SONG_TITLES),
      composers,
      iswc: generateIswc(rng),
      registrationDate: rng.randomDate(startDate, endDate),
    });
  }

  return songs;
}

// ─── Detail View Generators ──────────────────────────────────────────────────

const EXTENDED_TERRITORIES = [
  'Chile', 'United States', 'Spain', 'Peru', 'Argentina',
  'Mexico', 'Colombia', 'Brazil', 'United Kingdom', 'Germany',
  'France', 'Italy', 'Japan', 'Australia', 'Canada',
  'South Korea', 'Netherlands', 'Sweden', 'Portugal', 'Belgium',
  'Switzerland', 'Austria', 'Norway', 'Denmark', 'Finland',
  'Ireland', 'New Zealand', 'Poland', 'Czech Republic', 'Greece',
  'Turkey', 'India',
] as const;

const SUB_CATEGORIES: Record<string, string[]> = {
  'Synchronisation': ['Film', 'TV Series', 'Advertising', 'Video Games'],
  'Digital Mechanical': ['Streaming On-Demand', 'Downloads', 'Ringtones'],
  'Digital Performance': ['Interactive Streaming', 'Non-Interactive Streaming', 'Webcasting'],
  'Performance': ['Live Performance', 'Background Music', 'DJ Sets'],
  'Broadcast': ['Radio', 'Television', 'Cable'],
  'Print': ['Sheet Music', 'Lyrics', 'Arrangements'],
};

/**
 * Generate detailed song data for the analytics detail view.
 *
 * @param rng   - Seeded PRNG instance
 * @param count - Number of songs (default 20)
 */
export function generatePortalSongDetails(rng: SeededRng, count: number = 20): PortalSongDetail[] {
  const songs: PortalSongDetail[] = [];
  const usedTitles = new Set<string>();

  for (let i = 0; i < count; i++) {
    let title: string = rng.pick(SONG_TITLES);
    while (usedTitles.has(title)) {
      title = `${rng.pick(SONG_TITLES)} (${rng.randomInt(2, 9)})`;
    }
    usedTitles.add(title);

    const composerCount = rng.randomInt(1, 3);
    const composers: string[] = [];
    for (let c = 0; c < composerCount; c++) {
      composers.push(rng.pick(COMPOSER_NAMES));
    }

    const lastPeriodAmount = Math.round(rng.randomFloat(100000, 5000000));
    const currentPeriodAmount = Math.round(rng.randomFloat(100000, 5000000));
    const percentageChange = lastPeriodAmount > 0
      ? Math.round(((currentPeriodAmount - lastPeriodAmount) / lastPeriodAmount) * 1000) / 10
      : 0;

    songs.push({
      id: `PSDTL-${String(i + 1).padStart(4, '0')}`,
      title,
      composers,
      lastPeriodAmount,
      currentPeriodAmount,
      percentageChange,
      topCategory: rng.pick(INCOME_CATEGORIES),
      topCategoryAmount: Math.round(rng.randomFloat(50000, 2000000)),
      topSource: rng.pick(PLATFORMS),
      topSourceAmount: Math.round(rng.randomFloat(50000, 2000000)),
      topTerritory: rng.pick(TERRITORIES),
      topTerritoryAmount: Math.round(rng.randomFloat(50000, 2000000)),
    });
  }

  return songs;
}

/**
 * Generate detailed income group data for the analytics detail view.
 *
 * @param rng - Seeded PRNG instance
 */
export function generatePortalIncomeGroupDetails(rng: SeededRng): PortalIncomeGroupDetail[] {
  const groups: PortalIncomeGroupDetail[] = [];

  for (const category of INCOME_CATEGORIES) {
    const lastPeriodAmount = Math.round(rng.randomFloat(500000, 10000000));
    const currentPeriodAmount = Math.round(rng.randomFloat(500000, 10000000));
    const percentageChange = lastPeriodAmount > 0
      ? Math.round(((currentPeriodAmount - lastPeriodAmount) / lastPeriodAmount) * 1000) / 10
      : 0;

    const subCatNames = SUB_CATEGORIES[category] ?? ['Other'];
    const subCategories = subCatNames.map((name) => {
      const subLast = Math.round(rng.randomFloat(50000, 3000000));
      const subCurrent = Math.round(rng.randomFloat(50000, 3000000));
      return {
        name,
        lastPeriodAmount: subLast,
        currentPeriodAmount: subCurrent,
        percentageChange: subLast > 0
          ? Math.round(((subCurrent - subLast) / subLast) * 1000) / 10
          : 0,
      };
    });

    groups.push({
      category,
      lastPeriodAmount,
      currentPeriodAmount,
      percentageChange,
      subCategories,
    });
  }

  return groups;
}

/**
 * Generate detailed territory data for the analytics detail view.
 *
 * @param rng   - Seeded PRNG instance
 * @param count - Number of territories (default 32)
 */
export function generatePortalTerritoryDetails(rng: SeededRng, count: number = 32): PortalTerritoryDetail[] {
  const territories: PortalTerritoryDetail[] = [];

  for (let i = 0; i < count; i++) {
    const country = EXTENDED_TERRITORIES[i % EXTENDED_TERRITORIES.length];
    const lastPeriodAmount = Math.round(rng.randomFloat(100000, 12000000));
    const currentPeriodAmount = Math.round(rng.randomFloat(100000, 12000000));
    const percentageChange = lastPeriodAmount > 0
      ? Math.round(((currentPeriodAmount - lastPeriodAmount) / lastPeriodAmount) * 1000) / 10
      : 0;

    territories.push({
      country,
      lastPeriodAmount,
      currentPeriodAmount,
      percentageChange,
    });
  }

  return territories;
}

/**
 * Generate detailed exploitation source data for the analytics detail view.
 *
 * @param rng   - Seeded PRNG instance
 * @param count - Number of sources (default 20)
 */
export function generatePortalSourceDetails(rng: SeededRng, count: number = 20): PortalSourceDetail[] {
  const sources: PortalSourceDetail[] = [];
  const extendedPlatforms = [
    ...PLATFORMS,
    'Tidal', 'Pandora', 'SoundCloud', 'Napster', 'iHeartRadio',
    'Shazam', 'TikTok', 'Instagram Reels', 'Facebook', 'Twitch',
    'Peloton', 'Anghami', 'JioSaavn',
  ];

  for (let i = 0; i < count; i++) {
    const platform = extendedPlatforms[i % extendedPlatforms.length];
    const lastPeriodAmount = Math.round(rng.randomFloat(200000, 8000000));
    const currentPeriodAmount = Math.round(rng.randomFloat(200000, 8000000));
    const percentageChange = lastPeriodAmount > 0
      ? Math.round(((currentPeriodAmount - lastPeriodAmount) / lastPeriodAmount) * 1000) / 10
      : 0;

    sources.push({
      platform,
      lastPeriodAmount,
      currentPeriodAmount,
      percentageChange,
      topSong: rng.pick(SONG_TITLES),
      topSongAmount: Math.round(rng.randomFloat(50000, 2000000)),
      topCategory: rng.pick(INCOME_CATEGORIES),
      topCategoryAmount: Math.round(rng.randomFloat(50000, 2000000)),
      topTerritory: rng.pick(TERRITORIES),
      topTerritoryAmount: Math.round(rng.randomFloat(50000, 2000000)),
    });
  }

  return sources;
}

// ─── Aggregate Generator ─────────────────────────────────────────────────────

/** All client portal data generated from a single RNG instance */
export interface ClientPortalData {
  periods: PortalPeriod[];
  financialTimeSeries: FinancialTimePoint[];
  topSongs: PortalTopSong[];
  incomeGroups: PortalIncomeGroup[];
  exploitationSources: PortalExploitationSource[];
  territories: PortalTerritory[];
  statements: PortalStatement[];
  documents: PortalDocument[];
  songs: PortalSong[];
  songDetails: PortalSongDetail[];
  incomeGroupDetails: PortalIncomeGroupDetail[];
  territoryDetails: PortalTerritoryDetail[];
  sourceDetails: PortalSourceDetail[];
}

/**
 * Generate all client portal mock data from a single RNG instance.
 * This ensures deterministic output for a given seed.
 *
 * @param rng - Seeded PRNG instance
 */
export function generateClientPortalData(rng: SeededRng): ClientPortalData {
  return {
    periods: generatePortalPeriods(rng),
    financialTimeSeries: generateFinancialTimeSeries(rng),
    topSongs: generatePortalTopSongs(rng),
    incomeGroups: generatePortalIncomeGroups(rng),
    exploitationSources: generatePortalExploitationSources(rng),
    territories: generatePortalTerritories(rng),
    statements: generatePortalStatements(rng),
    documents: generatePortalDocuments(rng),
    songs: generatePortalSongs(rng),
    songDetails: generatePortalSongDetails(rng),
    incomeGroupDetails: generatePortalIncomeGroupDetails(rng),
    territoryDetails: generatePortalTerritoryDetails(rng),
    sourceDetails: generatePortalSourceDetails(rng),
  };
}
