/**
 * EU Laissez-Passer MRZ Parser
 * TD3 format (2 lines × 44 chars, ICAO Doc 9303)
 */

export interface MRZData {
  documentType: string; // P for passport, A for alien, C for crew
  issuingCountry: string; // ISO 3166-1 alpha-3 code (EUE for EU Laissez-Passer)
  documentNumber: string;
  documentNumberCheckDigit: string;
  dateOfBirth: string; // YYMMDD
  dateOfBirthCheckDigit: string;
  sex: 'M' | 'F' | '<'; // M=Male, F=Female, <=Not specified
  expirationDate: string; // YYMMDD
  expirationDateCheckDigit: string;
  nationality: string; // ISO 3166-1 alpha-3 code
  personalNumber: string;
  personalNumberCheckDigit: string;
  compositeCheckDigit: string;
  surname: string;
  givenNames: string;
}

/**
 * Parse MRZ from TD3 format (2 lines × 44 characters)
 */
export function parseMRZ(mrzLines: string[]): MRZData {
  if (mrzLines.length !== 2) {
    throw new Error('MRZ must have exactly 2 lines');
  }

  const line1 = mrzLines[0]!.padEnd(44, '<');
  const line2 = mrzLines[1]!.padEnd(44, '<');

  if (line1.length !== 44 || line2.length !== 44) {
    throw new Error('Each MRZ line must be 44 characters');
  }

  // Line 1: Document type, issuing country, name
  const documentType = line1[0]!;
  const issuingCountry = line1.substring(2, 5);
  const nameField = line1.substring(5, 44).trim();

  // Parse name (surname and given names separated by <<)
  const nameParts = nameField.split('<<');
  const surname = nameParts[0]?.replace(/</g, ' ').trim() || '';
  const givenNames = nameParts[1]?.replace(/</g, ' ').trim() || '';

  // Line 2: Document number, check digit, date of birth, sex, expiration, nationality, personal number, check digits
  const documentNumber = line2.substring(0, 9).replace(/</g, '').trim();
  const documentNumberCheckDigit = line2[9]!;
  const nationality = line2.substring(10, 13);
  const dateOfBirth = line2.substring(13, 19);
  const dateOfBirthCheckDigit = line2[19]!;
  const sex = line2[20]! as 'M' | 'F' | '<';
  const expirationDate = line2.substring(21, 27);
  const expirationDateCheckDigit = line2[27]!;
  const personalNumber = line2.substring(28, 42).replace(/</g, '').trim();
  const personalNumberCheckDigit = line2[42]!;
  const compositeCheckDigit = line2[43]!;

  // Validate check digits
  validateCheckDigit(documentNumber, documentNumberCheckDigit);
  validateCheckDigit(dateOfBirth, dateOfBirthCheckDigit);
  validateCheckDigit(expirationDate, expirationDateCheckDigit);
  validateCheckDigit(personalNumber || '', personalNumberCheckDigit);
  validateCompositeCheckDigit(line2.substring(0, 10) + line2.substring(13, 20) + line2.substring(21, 43), compositeCheckDigit);

  return {
    documentType,
    issuingCountry,
    documentNumber,
    documentNumberCheckDigit,
    dateOfBirth,
    dateOfBirthCheckDigit,
    sex,
    expirationDate,
    expirationDateCheckDigit,
    nationality,
    personalNumber,
    personalNumberCheckDigit,
    compositeCheckDigit,
    surname,
    givenNames,
  };
}

/**
 * Validate check digit using ICAO algorithm
 */
function validateCheckDigit(data: string, checkDigit: string): boolean {
  const weights = [7, 3, 1];
  let sum = 0;

  for (let i = 0; i < data.length; i++) {
    const char = data[i]!;
    let value: number;

    if (char >= '0' && char <= '9') {
      value = parseInt(char, 10);
    } else if (char >= 'A' && char <= 'Z') {
      value = char.charCodeAt(0) - 55;
    } else if (char === '<') {
      value = 0;
    } else {
      throw new Error(`Invalid character in MRZ: ${char}`);
    }

    sum += value * weights[i % 3]!;
  }

  const calculatedCheckDigit = (sum % 10).toString();
  if (calculatedCheckDigit !== checkDigit) {
    throw new Error(`Check digit validation failed. Expected ${checkDigit}, got ${calculatedCheckDigit}`);
  }

  return true;
}

/**
 * Validate composite check digit
 */
function validateCompositeCheckDigit(data: string, checkDigit: string): boolean {
  return validateCheckDigit(data, checkDigit);
}

/**
 * Format date from YYMMDD to ISO format
 */
export function formatMRZDate(mrzDate: string): string {
  const year = parseInt(mrzDate.substring(0, 2), 10);
  const month = mrzDate.substring(2, 4);
  const day = mrzDate.substring(4, 6);

  // Assume years 00-30 are 2000-2030, 31-99 are 1931-1999
  const fullYear = year <= 30 ? 2000 + year : 1900 + year;

  return `${fullYear}-${month}-${day}`;
}

/**
 * Validate document number format
 */
export function validateDocumentNumber(documentNumber: string, issuingCountry: string): boolean {
  // EU Laissez-Passer document numbers should start with EUE
  if (issuingCountry === 'EUE') {
    // Add specific validation rules for EU-LP document numbers
    return documentNumber.length >= 6 && documentNumber.length <= 9;
  }

  // General validation: alphanumeric, 6-9 characters
  return /^[A-Z0-9]{6,9}$/.test(documentNumber);
}

/**
 * Recognize issuer code
 */
export function recognizeIssuerCode(code: string): { country: string; type: string } | null {
  const issuerCodes: Record<string, { country: string; type: string }> = {
    EUE: { country: 'European Union', type: 'Laissez-Passer' },
    USA: { country: 'United States', type: 'Passport' },
    GBR: { country: 'United Kingdom', type: 'Passport' },
    FRA: { country: 'France', type: 'Passport' },
    DEU: { country: 'Germany', type: 'Passport' },
  };

  return issuerCodes[code] || null;
}

