// ============================================================================
// CAF SYNTH · turn ASTRO agreement rows into rich CAF transmission objects
// ----------------------------------------------------------------------------
// window.AGREEMENTS is the catalog source. Rows look like:
//   { id:'AG-2024-014', a:'Pluralis Music', b:'WC Pueblo Music',
//     kind:'Co-pub', start:'2024-01-01', end:'2027-12-31',
//     territory:'Worldwide', share:'50/50', value:'$240,000',
//     parties:[{name,role,kind,ipi,share}…], territories:[…], works:[…] }
//
// CAF transmits AGREEMENTS not works, so we map each row into:
//   - submitter agreement number, type (OS/OG/PS/PG)
//   - assignor + acquirer parties with PR/MR/SR shares
//   - territories (TIS codes)
//   - usage rights (M/P + sub-codes)
//
// Determinism: same agreement.id always yields the same synthetic numbers.
//
// EXPORT: window.CafSynth = { hydrateAgreement }
// ============================================================================

(function () {
  'use strict';

  function hash(s) {
    let h = 0x811c9dc5;
    for (let i = 0; i < (s||'').length; i++) { h ^= s.charCodeAt(i); h = (h * 0x01000193) >>> 0; }
    return h;
  }
  function rng(seed) { let s = seed || 1; return () => { s = (s * 1664525 + 1013904223) >>> 0; return (s >>> 0) / 0xffffffff; }; }

  function ipiName(seed) {
    const r = rng(seed);
    const d = []; for (let i = 0; i < 9; i++) d.push(Math.floor(r() * 10));
    let sum = 0; for (let i = 0; i < 9; i++) sum += d[i] * (10 - i);
    const c = (101 - (sum % 101)) % 101;
    return d.join('') + String(c).padStart(2, '0');
  }
  function ipiBase(seed) {
    const r = rng(seed);
    const d = []; for (let i = 0; i < 9; i++) d.push(Math.floor(r() * 10));
    let sum = 0; for (let i = 0; i < 9; i++) sum += d[i] * (10 - i);
    let c = sum % 11; if (c === 10) c = 0;
    return 'I' + d.join('') + c;
  }

  // CISAC society code lookup (3-digit)
  const SOC = {
    ASCAP: 10, BMI: 21, SESAC: 23, GMR: 71, MLC: 776, HFA: 73,
    PRS: 52, MCPS: 52, GEMA: 35, SACEM: 58, SIAE: 40, SGAE: 79,
    JASRAC: 11, SOCAN: 101, APRA: 40, STIM: 79, AKM: 12, KOMCA: 19,
    BUMA: 23, STEMRA: 36, ZAIKS: 78, SUISA: 89, TONO: 90,
  };
  const socCode = (name) => SOC[(name||'').toUpperCase().replace(/[^A-Z]/g,'')] || 10;

  // TIS territory code lookup (subset; full ref data lives in ref.tis)
  const TIS = {
    'WORLDWIDE': '2136', 'WORLD': '2136',
    'US': '0840', 'USA': '0840', 'UNITED STATES': '0840',
    'UK': '0826', 'GB': '0826', 'UNITED KINGDOM': '0826',
    'CA': '0124', 'CANADA': '0124',
    'DE': '0276', 'GERMANY': '0276',
    'FR': '0250', 'FRANCE': '0250',
    'JP': '0392', 'JAPAN': '0392',
    'IT': '0380', 'ITALY': '0380',
    'ES': '0724', 'SPAIN': '0724',
    'AU': '0036', 'AUSTRALIA': '0036',
    'AR': '0032', 'ARGENTINA': '0032',
    'BR': '0076', 'BRAZIL': '0076',
    'MX': '0484', 'MEXICO': '0484',
    'CL': '0152', 'CHILE': '0152',
    'CO': '0170', 'COLOMBIA': '0170',
    'EUROPE': '2100', 'EU': '2100',
    'NORTH AMERICA': '2120',
    'SOUTH AMERICA': '2128',
  };
  const tisFor = (name) => {
    if (!name) return '2136';
    const k = String(name).toUpperCase().trim();
    return TIS[k] || '2136';
  };

  // Map ASTRO agreement.kind → CAF agreement type
  function agreementType(kind) {
    if (!kind) return 'OG';
    const k = String(kind).toLowerCase();
    if (/co-?pub/.test(k)) return 'OG';        // Original General
    if (/admin/.test(k))   return 'OS';        // Original Specific (admin = work-by-work)
    if (/sub-?pub/.test(k)) return 'PG';       // Packaged General (sub-pub agreements)
    if (/single|specific/.test(k)) return 'OS';
    return 'OG';
  }

  function pct(s) {
    if (s == null) return 0;
    const m = String(s).match(/(\d+(?:\.\d+)?)/);
    return m ? parseFloat(m[1]) : 0;
  }
  function lastFirst(name) {
    if (!name) return ['', ''];
    const t = String(name).trim();
    if (t.includes(',')) { const [l, f] = t.split(','); return [l.trim().toUpperCase(), f.trim().toUpperCase()]; }
    const parts = t.split(/\s+/);
    if (parts.length === 1) return [parts[0].toUpperCase(), ''];
    const last = parts.pop();
    return [last.toUpperCase(), parts.join(' ').toUpperCase()];
  }

  // ─── hydrateAgreement ───────────────────────────────────────────────────
  function hydrateAgreement(ag, ctx = {}) {
    if (!ag) return null;
    const seed = hash(ag.id || 'x');
    const r = rng(seed);

    // Submitter agreement number — short, ASCII, ≤14 chars
    const submitterAgreementNumber = (ag.id || 'AGR').replace(/[^A-Z0-9-]/gi, '').slice(0, 14).toUpperCase();

    // International code (ISAN-style) — synthetic
    const internationalAgreementCode = '';

    // Parties: split into Assignor (writer side) and Acquirer (publisher side)
    const partiesIn = ag.parties || [];
    const totalShare = (ag.share && /(\d+)\/(\d+)/.exec(ag.share)) || null;
    const assignorPct = totalShare ? parseInt(totalShare[1], 10) : 50;
    const acquirerPct = totalShare ? parseInt(totalShare[2], 10) : 50;

    const ipa = [];

    // Promote any party with role writer/composer/author → assignor
    const assignors = partiesIn.filter(p =>
      /writer|composer|author|songwriter/i.test(p.role || p.kind || '')
    );
    const acquirers = partiesIn.filter(p =>
      /publisher|admin|company|label|society/i.test(p.role || p.kind || '')
    );

    // If we have neither side classified, synthesize generic ones
    const ensure = (list, role, defaultName) => {
      if (list.length) return list;
      return [{ name: defaultName, role }];
    };
    const fA = ensure(assignors, 'Writer', ag.a || 'Assignor');
    const fC = ensure(acquirers, 'Publisher', ag.b || 'Acquirer');

    fA.forEach((p, i) => {
      const [last, first] = lastFirst(p.name);
      const psd = seed + (i + 1) * 7919;
      const proName = p.pro || p.affiliation || 'ASCAP';
      ipa.push({
        role: 'AS',
        ipiNameNumber: p.ipi || ipiName(psd),
        ipiBaseNumber: p.ipiBase || ipiBase(psd + 1),
        partyId: 'A' + String(hash(p.name + ag.id)).slice(-8).padStart(8, '0'),
        lastName: last, firstName: first,
        prSoc: socCode(proName), prShare: assignorPct / fA.length,
        mrSoc: socCode(proName), mrShare: assignorPct / fA.length,
        srSoc: 0, srShare: 0,
      });
    });

    fC.forEach((p, i) => {
      const [last, first] = lastFirst(p.name);
      const psd = seed + (i + 1) * 6113;
      const proName = p.pro || p.affiliation || 'ASCAP';
      ipa.push({
        role: 'AC',
        ipiNameNumber: p.ipi || ipiName(psd),
        ipiBaseNumber: p.ipiBase || ipiBase(psd + 1),
        partyId: 'C' + String(hash(p.name + ag.id)).slice(-8).padStart(8, '0'),
        lastName: last, firstName: first,
        prSoc: socCode(proName), prShare: acquirerPct / fC.length,
        mrSoc: socCode(proName), mrShare: acquirerPct / fC.length,
        srSoc: 0, srShare: 0,
      });
    });

    // Territories
    let territories = [];
    if (Array.isArray(ag.territories) && ag.territories.length) {
      territories = ag.territories.map(t => ({
        inclusion: t.exclude ? 'E' : 'I',
        tisCode: tisFor(t.name || t.code || t),
      }));
    } else {
      territories = [{ inclusion: 'I', tisCode: tisFor(ag.territory) }];
    }

    // Usage rights — sensible defaults by agreement kind
    const usages = [];
    const k = (ag.kind || '').toLowerCase();
    if (/co-?pub|admin|sub-?pub/.test(k)) {
      usages.push({ rightCode: 'P',  usageCode: '',   share: 100, includeFlag: 'I' });
      usages.push({ rightCode: 'M',  usageCode: '',   share: 100, includeFlag: 'I' });
    } else if (/sync/.test(k)) {
      usages.push({ rightCode: 'PT', usageCode: 'MP', share: 100, includeFlag: 'I' });
    } else if (/mech/.test(k)) {
      usages.push({ rightCode: 'M',  usageCode: '',   share: 100, includeFlag: 'I' });
    } else {
      usages.push({ rightCode: 'P',  usageCode: '',   share: 100, includeFlag: 'I' });
      usages.push({ rightCode: 'M',  usageCode: '',   share: 100, includeFlag: 'I' });
    }

    // Dates
    const start = ag.start;
    const end = ag.end;
    const retentionEnd = ag.retentionEnd || end;
    const dateOfSignature = ag.dateOfSignature || start;

    return {
      id: ag.id,
      submitterAgreementNumber,
      internationalAgreementCode,
      agreementType: ag.agreementType || agreementType(ag.kind),
      start, end, retentionEnd,
      priorRoyaltyStatus: ag.priorRoyaltyStatus || 'N',
      priorRoyaltyStartDate: ag.priorRoyaltyStartDate,
      postTermCollectionStatus: ag.postTermCollectionStatus || 'N',
      postTermCollectionEndDate: ag.postTermCollectionEndDate,
      dateOfSignature,
      numberOfWorks: (ag.works || []).length,
      salesManufactureClause: ag.salesManufactureClause || ' ',
      sharesChange: !!ag.sharesChange,
      advanceGiven: !!(ag.advance || ag.advanceTotal || (ag.advanceSchedule || []).length),
      societyAssignedNumber: ag.societyAssignedNumber || '',
      territories,
      parties: ipa,
      usages,
      messages: ag.messages || [],
      // Pass-through for UI
      original: ag,
    };
  }

  window.CafSynth = { hydrateAgreement, SOC, TIS, agreementType };
})();
