export interface UserPII {
  id: string
  email?: string | null
  phone?: string | null
}

export interface VendorPII {
  id: string
  ownerEmail?: string | null
  ownerPhone?: string | null
}

export interface RedactionMap {
  /** Raw PII string → "{user_a}" pseudo-id */
  forward: Map<string, string>
  /** "{user_a}" → raw PII string (for substituting back into AI output) */
  reverse: Map<string, string>
}

function toAlpha(n: number): string {
  let result = ''
  let num = n
  do {
    result = String.fromCharCode(97 + (num % 26)) + result
    num = Math.floor(num / 26) - 1
  } while (num >= 0)
  return result
}

function normalizePhone(phone: string): string {
  return phone.replace(/[\s\-().+]/g, '')
}

export function buildRedactionMap(
  users: Map<string, UserPII>,
  vendors: Map<string, VendorPII>,
): RedactionMap {
  const forward = new Map<string, string>()
  const reverse = new Map<string, string>()

  const sortedUsers = [...users.values()].sort((a, b) => a.id.localeCompare(b.id))
  const sortedVendors = [...vendors.values()].sort((a, b) => a.id.localeCompare(b.id))

  let userIdx = 0
  for (const u of sortedUsers) {
    const pseudoBase = `{user_${toAlpha(userIdx)}}`
    let added = false
    if (u.email) {
      forward.set(u.email, pseudoBase)
      if (!added) {
        reverse.set(pseudoBase, u.email)
        added = true
      }
    }
    if (u.phone) {
      const normalized = normalizePhone(u.phone)
      forward.set(normalized, pseudoBase)
      if (!added) {
        reverse.set(pseudoBase, normalized)
      }
    }
    userIdx++
  }

  let vendorIdx = 0
  for (const v of sortedVendors) {
    const pseudoBase = `{vendor_${toAlpha(vendorIdx)}}`
    let added = false
    if (v.ownerEmail) {
      forward.set(v.ownerEmail, pseudoBase)
      if (!added) {
        reverse.set(pseudoBase, v.ownerEmail)
        added = true
      }
    }
    if (v.ownerPhone) {
      const normalized = normalizePhone(v.ownerPhone)
      forward.set(normalized, pseudoBase)
      if (!added) {
        reverse.set(pseudoBase, normalized)
      }
    }
    vendorIdx++
  }

  return { forward, reverse }
}

export function redactForPrompt(text: string, map: RedactionMap): string {
  if (map.forward.size === 0) return text

  const emailKeys: string[] = []
  const phoneKeys: string[] = []

  for (const key of map.forward.keys()) {
    if (/^\d+$/.test(key)) {
      phoneKeys.push(key)
    } else {
      emailKeys.push(key)
    }
  }

  emailKeys.sort((a, b) => b.length - a.length)
  phoneKeys.sort((a, b) => b.length - a.length)

  let result = text

  for (const email of emailKeys) {
    const pseudoId = map.forward.get(email)!
    const escaped = email.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
    result = result.replace(new RegExp(escaped, 'g'), pseudoId)
  }

  for (const digits of phoneKeys) {
    const pseudoId = map.forward.get(digits)!
    const digitParts = digits
      .split('')
      .map((d) => d.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'))
      .join('[\\s\\-().]*')
    const phoneRegex = new RegExp(`\\+?${digitParts}`, 'g')
    result = result.replace(phoneRegex, pseudoId)
  }

  return result
}

export function substitutePseudoIds(text: string, map: RedactionMap): string {
  if (map.reverse.size === 0) return text

  let result = text

  for (const [pseudoId, original] of map.reverse.entries()) {
    const escaped = pseudoId.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
    result = result.replace(new RegExp(escaped, 'g'), original)
  }

  return result
}
