import type { Transaction } from "../generated/kysely-tailordb";
import { AddressNotFoundError, InvalidCountryCodeError } from "../lib/errors.generated";
import { ok, err } from "@tailor-platform/erp-kit/module";

export type UpdatePartnerAddressInput = {
  id: string;
  line1?: string;
  line2?: string | null;
  city?: string;
  state?: string | null;
  postalCode?: string;
  country?: string;
};
/**
 * Function: updatePartnerAddress
 *
 * Updates mutable fields of an existing partner address.
 * addressType is immutable and not accepted as input.
 */
export async function run<CF extends Record<string, unknown>>(
  db: Transaction,
  input: UpdatePartnerAddressInput & Omit<Partial<CF>, "status">,
) {
  const { id, line1, line2, city, state, postalCode, country } = input;

  const KNOWN_KEYS = new Set(["id", "line1", "line2", "city", "state", "postalCode", "country"]);
  const customFields: Record<string, unknown> = {};
  for (const [key, value] of Object.entries(input as Record<string, unknown>)) {
    if (!KNOWN_KEYS.has(key)) {
      customFields[key] = value;
    }
  }

  // 1. Check address exists
  const address = await db
    .selectFrom("PartnerAddress")
    .selectAll()
    .where("id", "=", id)
    .forUpdate()
    .executeTakeFirst();

  if (!address) {
    return err(new AddressNotFoundError(id));
  }

  // 2. Validate country if provided (ISO 3166-1 alpha-2: two uppercase letters)
  if (country !== undefined && !/^[A-Z]{2}$/.test(country)) {
    return err(new InvalidCountryCodeError(country));
  }

  // 3. Apply updates
  const updates: Record<string, unknown> = {
    ...customFields,
    updatedAt: new Date(),
  };
  if (line1 !== undefined) updates.line1 = line1;
  if (line2 !== undefined) updates.line2 = line2;
  if (city !== undefined) updates.city = city;
  if (state !== undefined) updates.state = state;
  if (postalCode !== undefined) updates.postalCode = postalCode;
  if (country !== undefined) updates.country = country;

  const updatedAddress = await db
    .updateTable("PartnerAddress")
    .set(updates)
    .where("id", "=", id)
    .returningAll()
    .executeTakeFirstOrThrow();

  return ok({ address: updatedAddress });
}
