// ============================================================================
// CWR v3.1 EXTENSIONS
// ----------------------------------------------------------------------------
// Closes the remaining v3.1 gaps:
//   - XRF cross-reference type codes (full set of 11)
//   - NPA writer-name strict variant (society-toggleable)
//   - PER performance-language fields
//   - GRH submission distribution flag
//   - v3.1-only IND interested-party flag
//
// EXPORT: window.CwrV31 = { XRF_TYPES, applyV31Extensions, ...}
// ============================================================================

(function () {

  // ────────────────────────────────────────────────────────────────────────
  // XRF — cross-reference type codes
  // CWR 3.1 §5.16. The full set of 11 codes societies recognize.
  // ────────────────────────────────────────────────────────────────────────
  const XRF_TYPES = {
    'ISW': { name: 'ISWC',                    description: 'International Standard Musical Work Code' },
    'ISR': { name: 'ISRC',                    description: 'International Standard Recording Code' },
    'IPN': { name: 'IPI Name #',              description: 'CISAC IPI Name Number' },
    'IPB': { name: 'IPI Base #',              description: 'CISAC IPI Base Number' },
    'CAT': { name: 'Catalog Number',          description: 'Publisher catalog number' },
    'CWR': { name: 'CWR Work #',              description: 'Submitter work reference number (Tunecode-style)' },
    'TUN': { name: 'Tunecode',                description: 'PRS Tunecode' },
    'WRK': { name: 'Society Work #',          description: 'Society-assigned work identifier' },
    'GRD': { name: 'GRid',                    description: 'Global Release Identifier' },
    'PRO': { name: 'Proprietary',             description: 'Submitter-proprietary identifier' },
    'OTH': { name: 'Other',                   description: 'Unspecified — use sparingly' },
  };

  // ────────────────────────────────────────────────────────────────────────
  // NPA — strict variant
  // v3.1 introduced a strict mode where writer names in non-Roman alphabets
  // require:
  //   - language_code (column 21-23) — ISO 639-2 three-letter
  //   - performing_artist_first_name AND last_name both present
  //   - no leading/trailing spaces on the name fields
  // GEMA, JASRAC, KOMCA adopted strict; ASCAP/BMI/PRS use lenient.
  // ────────────────────────────────────────────────────────────────────────
  const STRICT_NPA_SOCIETIES = ['GEMA', 'JASRAC', 'KOMCA', 'AKM', 'SUISA'];

  function buildNpaStrict({ writerIpi, firstName, lastName, languageCode }) {
    if (!languageCode || languageCode.length !== 3) {
      throw new Error('NPA strict: language_code (ISO 639-2) required');
    }
    if (!firstName || !firstName.trim()) {
      throw new Error('NPA strict: first_name required');
    }
    if (!lastName || !lastName.trim()) {
      throw new Error('NPA strict: last_name required');
    }
    if (firstName !== firstName.trim() || lastName !== lastName.trim()) {
      throw new Error('NPA strict: no leading/trailing spaces on name fields');
    }
    return { writerIpi, firstName, lastName, languageCode };
  }

  // ────────────────────────────────────────────────────────────────────────
  // PER — v3.1 performance-language fields
  // v3.1 added two optional fields to PER:
  //   - performance_language_code (chars 88-90, ISO 639-2)
  //   - performance_dialect (chars 91-93, ISO 15924 script-style or society code)
  // ────────────────────────────────────────────────────────────────────────
  const PER_DIALECT_CODES = {
    'EN-US': 'English (US)',
    'EN-GB': 'English (UK)',
    'EN-AU': 'English (AU)',
    'EN-IN': 'English (IN)',
    'ES-ES': 'Spanish (Castilian)',
    'ES-MX': 'Spanish (Mexican)',
    'ES-AR': 'Spanish (Rioplatense)',
    'PT-BR': 'Portuguese (Brazilian)',
    'PT-PT': 'Portuguese (European)',
    'FR-FR': 'French (Metropolitan)',
    'FR-CA': 'French (Canadian)',
    'ZH-CN': 'Chinese (Simplified)',
    'ZH-TW': 'Chinese (Traditional)',
  };

  function buildPerV31Suffix({ languageCode, dialect }) {
    const lang = (languageCode || '   ').padEnd(3, ' ').slice(0, 3);
    const dial = (dialect || '     ').padEnd(5, ' ').slice(0, 5);
    return lang + dial;
  }

  // ────────────────────────────────────────────────────────────────────────
  // GRH — v3.x submission distribution flag
  // Field at offset 19 (after batch_request 12-18). Values:
  //   'A' = Annual submission
  //   'M' = Monthly
  //   'Q' = Quarterly
  //   'O' = One-time / ad-hoc
  //   'C' = Catalog correction
  //   ' ' = Not specified (default for legacy)
  // ────────────────────────────────────────────────────────────────────────
  const GRH_DISTRIBUTION_FLAGS = {
    'A': 'Annual',
    'M': 'Monthly',
    'Q': 'Quarterly',
    'O': 'One-time',
    'C': 'Catalog correction',
  };

  function setGrhDistributionFlag(line, flag) {
    if (!line.startsWith('GRH')) return line;
    const f = (flag || ' ').slice(0, 1);
    if (line.length < 20) return line + f;
    return line.slice(0, 19) + f + line.slice(20);
  }

  // ────────────────────────────────────────────────────────────────────────
  // IND — v3.1 interested-party flag
  // CWR 3.1 added "interested party" flag at end of IND record:
  //   'Y' = This IPI is an interested party in the work
  //   'N' = Not an interested party (default)
  // ────────────────────────────────────────────────────────────────────────
  function setIndInterestedPartyFlag(line, flag) {
    if (!line.startsWith('IND')) return line;
    const f = flag === true || flag === 'Y' ? 'Y' : 'N';
    return line + f;
  }

  // ────────────────────────────────────────────────────────────────────────
  // Apply all v3.1 extensions to a transmission
  // ────────────────────────────────────────────────────────────────────────
  function applyV31Extensions(lines, opts = {}) {
    const out = [];
    const errors = [];
    const society = opts.society;
    const strictNpa = STRICT_NPA_SOCIETIES.includes(society);

    for (const line of lines) {
      let mutated = line;

      // GRH distribution flag
      if (line.startsWith('GRH') && opts.distributionFlag) {
        mutated = setGrhDistributionFlag(mutated, opts.distributionFlag);
      }

      // IND interested-party flag
      if (line.startsWith('IND') && opts.indInterestedParty !== undefined) {
        mutated = setIndInterestedPartyFlag(mutated, opts.indInterestedParty);
      }

      // NPA strict validation
      if (line.startsWith('NPA') && strictNpa) {
        // language_code at offset 21-24
        const lang = line.slice(21, 24);
        if (!/^[a-z]{3}$/i.test(lang)) {
          errors.push({
            code: 'NPA_STRICT_LANG',
            society,
            msg: `${society} (strict NPA): language_code (ISO 639-2) required`,
          });
        }
      }

      out.push(mutated);
    }

    return { lines: out, errors };
  }

  // ────────────────────────────────────────────────────────────────────────
  // Build XRF record (CWR 3.x)
  // ────────────────────────────────────────────────────────────────────────
  function buildXrfRecord({ transactionSeq, recordSeq, identifierType, identifier, identifierContext }) {
    if (!XRF_TYPES[identifierType]) {
      throw new Error('Unknown XRF type: ' + identifierType);
    }
    // Format: XRF + transactionSeq(8) + recordSeq(8) + identifierType(3) +
    //         identifier(14) + identifierContext(2) = 38 + record-version-suffix(2) = 40
    const ts = String(transactionSeq).padStart(8, '0');
    const rs = String(recordSeq).padStart(8, '0');
    const id = (identifier || '').padEnd(14, ' ').slice(0, 14);
    const ctx = (identifierContext || '  ').padEnd(2, ' ').slice(0, 2);
    return 'XRF' + ts + rs + identifierType + id + ctx;
  }

  // ────────────────────────────────────────────────────────────────────────
  // EXPORT
  // ────────────────────────────────────────────────────────────────────────
  window.CwrV31 = {
    XRF_TYPES,
    STRICT_NPA_SOCIETIES,
    PER_DIALECT_CODES,
    GRH_DISTRIBUTION_FLAGS,
    buildNpaStrict,
    buildPerV31Suffix,
    setGrhDistributionFlag,
    setIndInterestedPartyFlag,
    buildXrfRecord,
    applyV31Extensions,
  };
})();
