/**
 * Utilities for combining owner names per unit and collecting
 * all mailing addresses (primary + alternates) for form generation.
 */

export interface OwnerRecord {
  id: string;
  first_name?: string | null;
  last_name?: string | null;
  owner_name?: string;
  property_address?: string | null;
  street_address?: string | null;
  mailing_address?: string | null;
  alternate_address_1?: string | null;
  alternate_address_2?: string | null;
  unit_id?: string | null;
  units?: { unit_number?: string; account_number?: string; address?: string } | null;
  [key: string]: any;
}

export interface AddressCopy {
  /** Label like "Mailing", "Alternate 1", "Alternate 2" */
  label: string;
  address: string;
}

/**
 * Get the display name for a single owner.
 */
export function getOwnerName(owner: OwnerRecord): string {
  if (owner.owner_name) return owner.owner_name;
  return [owner.first_name, owner.last_name].filter(Boolean).join(" ").trim() || "Unknown Owner";
}

/**
 * Combine names of multiple owners into a single string.
 * E.g. "John Doe & Jane Doe" or "John Doe, Jane Doe & Bob Smith"
 */
export function combineOwnerNames(owners: OwnerRecord[]): string {
  if (!owners || owners.length === 0) return "Unknown Owner";
  const names = owners.map(getOwnerName).filter(n => n && n !== "Unknown Owner");
  const unique = [...new Set(names)];
  if (unique.length === 0) return "Unknown Owner";
  if (unique.length === 1) return unique[0];
  if (unique.length === 2) return `${unique[0]} & ${unique[1]}`;
  return unique.slice(0, -1).join(", ") + " & " + unique[unique.length - 1];
}

/**
 * Collect all distinct mailing addresses for a set of co-owners.
 * For each owner, returns ONLY their mailing_address when one is provided;
 * otherwise falls back to property_address. Alternate addresses are always
 * included if present. This ensures correspondence (violations, letters,
 * notices) does not double-mail to both the unit and a separate mailing
 * address when the owner has designated a mailing address elsewhere.
 */
export function collectAllAddresses(owners: OwnerRecord[]): AddressCopy[] {
  const addresses: AddressCopy[] = [];
  const seen = new Set<string>();

  for (const owner of owners) {
    // Prefer mailing_address; only fall back to the property address when
    // the owner has NOT provided a separate mailing address.
    const explicitMailing = (owner.mailing_address || "").trim();
    const property = (owner.property_address || owner.street_address || "").trim();
    const primary = explicitMailing || property;
    const primaryLabel = explicitMailing ? "Mailing" : "Property Address";
    if (primary && !seen.has(primary.toLowerCase())) {
      seen.add(primary.toLowerCase());
      addresses.push({ label: primaryLabel, address: primary });
    }

    if (owner.alternate_address_1 && !seen.has(owner.alternate_address_1.trim().toLowerCase())) {
      seen.add(owner.alternate_address_1.trim().toLowerCase());
      addresses.push({ label: "Alternate 1", address: owner.alternate_address_1 });
    }

    if (owner.alternate_address_2 && !seen.has(owner.alternate_address_2.trim().toLowerCase())) {
      seen.add(owner.alternate_address_2.trim().toLowerCase());
      addresses.push({ label: "Alternate 2", address: owner.alternate_address_2 });
    }
  }

  // Fallback: if no addresses found, try property address
  if (addresses.length === 0) {
    const prop = owners[0]?.property_address || owners[0]?.street_address || "";
    if (prop) addresses.push({ label: "Mailing", address: prop });
  }

  return addresses;
}

/**
 * Group owners by unit_id. Owners with the same unit_id are co-owners.
 * Owners without a unit_id are treated individually.
 */
export function groupOwnersByUnit(owners: OwnerRecord[]): Map<string, OwnerRecord[]> {
  const groups = new Map<string, OwnerRecord[]>();
  let noUnitCounter = 0;

  for (const owner of owners) {
    const key = owner.unit_id || `__no_unit_${noUnitCounter++}`;
    const group = groups.get(key) || [];
    group.push(owner);
    groups.set(key, group);
  }

  return groups;
}

/**
 * Split a mailing address string into separate lines.
 * If the address already contains newlines, split on those.
 * Otherwise, try to split before a city/state/zip pattern (e.g. "City, ST 12345").
 * Returns an array of non-empty trimmed lines.
 */
export function splitMailingAddressLines(address: string | null | undefined): string[] {
  if (!address) return [];
  const trimmed = address.trim();
  if (!trimmed) return [];

  // If it already has newlines, respect them
  if (trimmed.includes('\n')) {
    return trimmed.split('\n').map(l => l.trim()).filter(l => l);
  }

  // Pattern 1: "Street, City, ST, 12345" or "Street, City, ST, 12345-6789" (comma before zip)
  const commaBeforeZip = trimmed.match(/^(.+?),\s+([A-Za-z\s]+,\s*[A-Z]{2},\s*\d{5}(?:-\d{4})?)$/);
  if (commaBeforeZip) {
    return [commaBeforeZip[1].trim(), commaBeforeZip[2].trim()];
  }

  // Pattern 2: "Street, City, ST 12345" (standard format)
  const csz = trimmed.match(/^(.+?),\s+([A-Za-z\s]+,\s*[A-Z]{2}\s+\d{5}(?:-\d{4})?)$/);
  if (csz) {
    return [csz[1].trim(), csz[2].trim()];
  }

  // Pattern 3: "Street, City, Florida 32956" (full state name)
  const fullState = trimmed.match(/^(.+?),\s+([A-Za-z\s]+,\s*[A-Za-z]+\s+\d{5}(?:-\d{4})?)$/);
  if (fullState) {
    return [fullState[1].trim(), fullState[2].trim()];
  }

  // Fallback: return as single line
  return [trimmed];
}
