// ============================================================================
// CWR CATALOG BRIDGE
// ============================================================================
// Maps the live Rocket Science catalog (window.WORKS, RECORDINGS, RELEASES,
// PROFILES, PUBLISHERS, AGREEMENTS) into CWR transaction inputs that
// CwrGenBuild.buildFile() consumes. No synthetic data — only real RS records.
//
// Mapping rules:
//
//   WORK (NWR/REV transaction)
//     work.iswc          → ISWC field on NWR
//     work.title         → workTitle
//     work.duration      → "HHMMSS" duration
//     work.__rsWriterShares[] → SWR + SWT records (one per writer)
//     ws.publishingShares[]   → SPU + SPT + PWR records (one per publisher)
//     work.__rsRecordings[]   → REC records (one per master)
//
//   PROFILE (writer identity)
//     profile.ipi/cae    → ipiName on SWR
//     profile.realName   → lastName/firstName split
//     profile.pro        → societyAffiliation (ASCAP=10, BMI=21, SESAC=23…)
//
//   PUBLISHER
//     publisher.ipi      → ipiName on SPU
//     publisher.role     → publisherType (E=Original, AM=Administrator, AQ=Acquirer)
//
//   AGREEMENT (AGR transaction batch)
//     agreement.kind     → agreementType (Publishing → OG, Recording → OS, etc)
//     agreement.parties  → IPA records (Assignor=AS, Licensee=AC)
//     agreement.territories → TER records
//     agreement.start/end/retentionEndDate
//
// EXPORT: window.CwrCatalog = { worksToTxs, agreementsToTxs, summary }
// ============================================================================

(function () {
  'use strict';

  // PRO name → 3-digit CISAC society code
  const PRO_TO_SOC = {
    ASCAP: '010', BMI: '021', SESAC: '023', GMR: '071',
    PRS: '052', 'PRS for Music': '052',
    GEMA: '035', SACEM: '058', SIAE: '040',
    JASRAC: '011', SOCAN: '101', APRA: '040', 'APRA AMCOS': '040',
    STIM: '079', AKM: '012',
    MLC: '776', HFA: '073',
  };

  // Agreement kind → CWR agreement type code
  const KIND_TO_AGR_TYPE = {
    'Publishing': 'OG',         // original general
    'Publishing · Admin': 'OG',
    'Publishing · Co-Pub': 'OG',
    'Sub-Publishing': 'PG',     // sub-publishing general
    'Recording': 'OS',          // not strictly CWR but mapped
    'Administration': 'OG',
    'Songwriter': 'OS',
  };

  // Pad/format helpers
  const pad = (s, n, ch = ' ') => String(s == null ? '' : s).padEnd(n, ch).slice(0, n);
  const num = (n) => String(Math.round(+n || 0));
  const dur = (secs) => {
    if (!secs) return '000000';
    const s = +secs;
    const h = Math.floor(s / 3600), m = Math.floor((s % 3600) / 60), ss = s % 60;
    return String(h).padStart(2, '0') + String(m).padStart(2, '0') + String(ss).padStart(2, '0');
  };

  // Parse "50.00%" → 5000 (CWR uses basis points, 5 digits)
  function parseShare(str) {
    if (!str) return 0;
    if (typeof str === 'number') return Math.round(str * 100);
    const m = String(str).match(/(\d+(?:\.\d+)?)/);
    return m ? Math.round(parseFloat(m[1]) * 100) : 0;
  }

  function splitName(full) {
    if (!full) return { last: '', first: '' };
    const parts = String(full).trim().split(/\s+/);
    if (parts.length === 1) return { last: parts[0], first: '' };
    return { last: parts.slice(-1)[0], first: parts.slice(0, -1).join(' ') };
  }

  // PRO name → numeric society code (left-padded)
  function proSoc(pro) {
    return PRO_TO_SOC[pro] || PRO_TO_SOC[(pro || '').toUpperCase()] || '   ';
  }

  // Find profile record for a writer name (by aliases / artist name / real name)
  function findProfileForWriter(writerName) {
    const list = window.PROFILES || [];
    if (!writerName) return null;
    const key = writerName.toLowerCase();
    return list.find(p => {
      if ((p.name || '').toLowerCase() === key) return true;
      if ((p.realName || '').toLowerCase() === key) return true;
      if ((p.__rsRaw?.artist_name || '').toLowerCase() === key) return true;
      return false;
    }) || null;
  }

  // Find publisher record by name
  function findPublisher(name) {
    const list = window.PUBLISHERS || [];
    if (!name) return null;
    const key = name.toLowerCase();
    return list.find(p => (p.name || '').toLowerCase() === key) || null;
  }

  // Map RS publisher role → CWR publisher type
  function pubTypeFor(role) {
    if (!role) return 'E'; // original
    const r = role.toLowerCase();
    if (/admin/.test(r)) return 'AM';
    if (/sub-?pub/.test(r)) return 'SE';
    if (/acqu/.test(r)) return 'AQ';
    return 'E';
  }

  // ─── WORK → NWR transaction ──────────────────────────────────────────────
  function workToTransaction(work, opts) {
    opts = opts || {};
    const writerShares = work.__rsWriterShares || [];
    const recordings = work.__rsRecordings || [];

    const writers = writerShares.map((ws) => {
      const profile = ws.profile || findProfileForWriter(ws.Writer);
      const fullName = profile?.artist_name || ws.Writer || '';
      const realName = profile ? [profile.last_name, profile.first_name].filter(Boolean).join(', ') : '';
      const { last, first } = splitName(realName || fullName);

      // Build publisher chain for this writer
      const publishers = (ws.publishingShares || []).map((ps) => {
        const pub = ps.publisher ? findPublisher(ps.publisher.name) : findPublisher(ps.Publisher);
        return {
          submitterPublisherNumber: ps['Publishing Share ID'] || '',
          publisherName: ps.Publisher || pub?.name || '',
          publisherUnknown: ps['Publisher Unknown'] === 'Yes' ? 'Y' : 'N',
          publisherType: pubTypeFor(ps['Publisher Role'] || pub?.role),
          taxId: '',
          ipiName: pub?.ipi || pub?.__rsRaw?.IPI || '',
          ipiBase: '',
          prShare: parseShare(ps['Performance Share']),
          mrShare: parseShare(ps['Mech Share']),
          srShare: parseShare(ps['Sync Share']),
          prSoc: proSoc(pub?.society || pub?.__rsRaw?.['PRO Affiliation'] || ws['USA License']),
          mrSoc: proSoc(pub?.society || ws['USA License']),
          srSoc: proSoc(pub?.society || ws['USA License']),
          territories: (ps.territories || []).map(t => ({
            tisNum: t.Territory === 'World' ? '2136' : '2136',
            inclusionFlag: t['Inclusion/Exclusion']?.startsWith('E') ? 'E' : 'I',
          })),
        };
      });

      return {
        submitterWriterNumber: ws['Writer Share ID'] || '',
        lastName: last,
        firstName: first,
        unknown: ws['Writer Unknown'] === 'Yes' ? 'Y' : 'N',
        designation: writerDesignation(ws['Writer Role']),
        taxId: '',
        ipiName: profile?.ipi_name_number || profile?.ipi || '',
        ipiBase: '',
        prShare: parseShare(ws['Performance Share']),
        mrShare: parseShare(ws['Mech Share']),
        srShare: parseShare(ws['Sync Share']),
        prSoc: proSoc(profile?.pro_affiliation || ws['USA License']),
        mrSoc: proSoc(profile?.pro_affiliation || ws['USA License']),
        srSoc: proSoc(profile?.pro_affiliation || ws['USA License']),
        publishers,
      };
    });

    const recs = recordings.map((rec) => ({
      isrc: rec.ISRC || '',
      releaseTitle: rec['Recording Title'] || rec['Release Title'] || work.title,
      displayArtist: rec['Recording Artist'] || rec['Release Artist'] || '',
      label: rec.Label || '',
      duration: dur(rec.__durationSec || work.duration || 0),
      releaseDate: (rec['Release Date'] || '').replace(/-/g, ''),
      mediaType: 'CD',
      submitterRecordingId: rec['Recording ID'] || '',
    }));

    return {
      transactionType: 'NWR',
      submitterWorkNumber: work.id || work.__rsRaw?.['Work ID'] || '',
      iswc: work.iswc || '',
      workTitle: work.title || '',
      titleType: 'OT',
      languageCode: work.__rsRaw?.['Language'] || '',
      duration: dur(work.duration),
      cwrWorkType: '',
      versionType: 'ORI',
      writers,
      recordings: recs,
      // Identify if any non-Roman characters → trigger NCT/NWN auto-emission
      _hasNonRoman: /[^\x00-\x7F]/.test((work.title || '') + writers.map(w => w.lastName + w.firstName).join('')),
    };
  }

  function writerDesignation(role) {
    if (!role) return 'CA';
    const r = role.toLowerCase();
    if (/composer.*author|author.*composer/.test(r)) return 'CA';
    if (/composer/.test(r)) return 'C';
    if (/author|lyric/.test(r)) return 'A';
    if (/arrang/.test(r)) return 'AR';
    if (/translat/.test(r)) return 'TR';
    if (/sub.?author/.test(r)) return 'SA';
    if (/adapt/.test(r)) return 'AD';
    return 'CA';
  }

  // ─── AGREEMENT → AGR transaction ─────────────────────────────────────────
  function agreementToTransaction(agr) {
    const partyAS = agr.parties?.find(p => /assign/i.test(p.role)) || agr.parties?.[0];
    const partyAC = agr.parties?.find(p => /licen|acqui/i.test(p.role)) || agr.parties?.[1];

    const territories = (agr.territories || []).map(t => ({
      tisNum: t.code === 'WW' ? '2136' : (t.code || '2136'),
      tisCode: t.code,
      label: t.label,
      inclusionFlag: (t.rights || '').toLowerCase().startsWith('e') ? 'E' : 'I',
    }));

    const parties = [];
    if (partyAS) {
      parties.push({
        agreementRoleCode: 'AS',
        ipiName: partyAS.ipi || '',
        lastName: partyAS.name || '',
        firstName: '',
        prShare: 100,
        mrShare: 100,
        srShare: 100,
      });
    }
    if (partyAC) {
      parties.push({
        agreementRoleCode: 'AC',
        ipiName: partyAC.ipi || '',
        lastName: partyAC.name || '',
        firstName: '',
        prShare: partyAC.share || 100,
        mrShare: partyAC.share || 100,
        srShare: partyAC.share || 100,
      });
    }

    return {
      transactionType: 'AGR',
      submitterAgreementNumber: agr.id || '',
      internationalStandardCode: agr.societyAgreementNumber || '',
      agreementType: agr.typeCwr || KIND_TO_AGR_TYPE[agr.kind] || 'OG',
      agreementStartDate: (agr.start || '').replace(/-/g, ''),
      agreementEndDate: (agr.end || '').replace(/-/g, ''),
      retentionEndDate: (agr.retentionEndDate || '').replace(/-/g, ''),
      priorRoyaltyStatus: agr.priorRoyaltyStatus || 'N',
      priorRoyaltyStartDate: '',
      postTermCollectionStatus: 'N',
      postTermCollectionEndDate: '',
      dateOfSignatureOfAgreement: (agr.signatures?.[0]?.date || '').replace(/-/g, ''),
      numberOfWorks: (agr.works || []).length,
      salesManufactureClause: agr.salesOrManufacture || '',
      sharesCanChange: agr.sharesCanChange ? 'Y' : 'N',
      advanceGiven: agr.advanceGiven ? 'Y' : 'N',
      societyAssignedAgreementNumber: agr.societyAgreementNumber || '',
      territories,
      parties,
    };
  }

  // ─── Top-level converters ────────────────────────────────────────────────
  function worksToTxs(filterFn) {
    const list = window.WORKS || [];
    return list.filter(filterFn || (() => true)).map(w => workToTransaction(w));
  }

  function agreementsToTxs(filterFn) {
    const list = window.AGREEMENTS || [];
    return list.filter(filterFn || (() => true)).map(a => agreementToTransaction(a));
  }

  function summary() {
    const works = window.WORKS || [];
    const writeable = works.filter(w => (w.__rsWriterShares || []).length > 0);
    const withIswc = works.filter(w => w.iswc);
    const withRec = works.filter(w => (w.__rsRecordings || []).length > 0);
    const sharesComplete = works.filter(w => {
      const shares = (w.__rsWriterShares || []).reduce((acc, ws) => acc + parseShare(ws['Performance Share']), 0);
      return shares >= 9999 && shares <= 10001;
    });
    const recordings = window.RECORDINGS || [];
    const withIsrc = recordings.filter(r => r.isrc);
    const agrs = window.AGREEMENTS || [];
    const validAgr = agrs.filter(a => a.parties && a.parties.length >= 2 && a.start && a.end);

    return {
      works: { total: works.length, writeable: writeable.length, withIswc: withIswc.length, withRecording: withRec.length, sharesComplete: sharesComplete.length },
      recordings: { total: recordings.length, withIsrc: withIsrc.length },
      agreements: { total: agrs.length, valid: validAgr.length },
      profiles: { total: (window.PROFILES || []).length, withIpi: (window.PROFILES || []).filter(p => p.ipi).length },
      publishers: { total: (window.PUBLISHERS || []).length, withIpi: (window.PUBLISHERS || []).filter(p => p.ipi).length },
    };
  }

  window.CwrCatalog = {
    worksToTxs,
    agreementsToTxs,
    workToTransaction,
    agreementToTransaction,
    summary,
    PRO_TO_SOC,
    KIND_TO_AGR_TYPE,
  };
})();
