import type { Transaction } from "../generated/kysely-tailordb";
import {
  ContactPersonNotFoundError,
  InvalidFirstNameError,
  InvalidLastNameError,
  InvalidEmailFormatError,
  MissingCommunicationChannelError,
} from "../lib/errors.generated";
import { ok, err } from "@tailor-platform/erp-kit/module";

export type UpdateContactPersonInput = {
  id: string;
  firstName?: string;
  lastName?: string;
  email?: string | null;
  phone?: string | null;
  jobTitle?: string | null;
  department?: string | null;
};
/**
 * Function: updateContactPerson
 *
 * Updates a contact person's details. Validates name fields if provided,
 * email format if provided, and ensures at least one communication channel
 * remains after the update. isPrimary is not modifiable through this command.
 */
export async function run<CF extends Record<string, unknown>>(
  db: Transaction,
  input: UpdateContactPersonInput & Omit<Partial<CF>, "status">,
) {
  const { id, firstName, lastName, email, phone, jobTitle, department, ...customFields } = input;

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

  if (!existing) {
    return err(new ContactPersonNotFoundError(id));
  }

  // 2. Validate firstName if provided
  if (firstName !== undefined && !firstName?.trim()) {
    return err(new InvalidFirstNameError(id));
  }

  // 3. Validate lastName if provided
  if (lastName !== undefined && !lastName?.trim()) {
    return err(new InvalidLastNameError(id));
  }

  // 4. Validate email format if provided and non-null
  if (email !== undefined && email !== null) {
    const trimmedEmail = email.trim();
    const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    if (!emailRegex.test(trimmedEmail)) {
      return err(new InvalidEmailFormatError(email));
    }
  }

  // 5. After update, at least one of email or phone must remain (whitespace-only values don't count)
  const mergedEmail = email !== undefined ? email : existing.email;
  const mergedPhone = phone !== undefined ? phone : existing.phone;
  if (!mergedEmail?.trim() && !mergedPhone?.trim()) {
    return err(new MissingCommunicationChannelError(id));
  }

  // 6. Build update values
  const updateValues: Record<string, unknown> = {
    ...(customFields as Record<string, unknown>),
    updatedAt: new Date(),
  };
  if (firstName !== undefined) updateValues.firstName = firstName;
  if (lastName !== undefined) updateValues.lastName = lastName;
  if (email !== undefined) updateValues.email = email ?? null;
  if (phone !== undefined) updateValues.phone = phone ?? null;
  if (jobTitle !== undefined) updateValues.jobTitle = jobTitle ?? null;
  if (department !== undefined) updateValues.department = department ?? null;

  const contact = await db
    .updateTable("ContactPerson")
    .set(updateValues)
    .where("id", "=", id)
    .returningAll()
    .executeTakeFirst();

  return ok({ contact: contact! });
}
