import { parse } from "csv-parse/sync";

import { AppError } from "../lib/errors.js";

export type ImportedContact = {
  email: string;
  full_name: string | null;
  first_name: string | null;
  last_name: string | null;
  alternate_email: string | null;
  phone: string | null;
  source: string | null;
  company: string | null;
  job_title: string | null;
  country: string | null;
  city: string | null;
  lifecycle_stage: string | null;
  notes: string | null;
  tags: string[];
};

function normalizeEmail(email: string) {
  return email.trim().toLowerCase();
}

function readValue(row: Record<string, string>, keys: string[]) {
  for (const key of keys) {
    const matchedKey = Object.keys(row).find((candidate) => candidate.trim().toLowerCase() === key.trim().toLowerCase());
    const value = matchedKey ? row[matchedKey] : undefined;
    if (typeof value === "string" && value.trim()) {
      return value.trim();
    }
  }

  return null;
}

export function parseTxtContacts(raw: string): ImportedContact[] {
  return raw
    .split(/\r?\n/)
    .map((line) => line.trim())
    .filter(Boolean)
    .map((email) => ({
      email: normalizeEmail(email),
      full_name: null,
      first_name: null,
      last_name: null,
      alternate_email: null,
      phone: null,
      source: null,
      company: null,
      job_title: null,
      country: null,
      city: null,
      lifecycle_stage: null,
      notes: null,
      tags: []
    }));
}

export function parseCsvContacts(raw: string): ImportedContact[] {
  const rows = parse(raw, {
    columns: true,
    skip_empty_lines: true,
    trim: true
  }) as Record<string, string>[];

  return rows.map((row) => {
    const email = readValue(row, ["email", "primary_email", "work_email"]);

    if (!email) {
      throw new AppError(400, "INVALID_CONTACT_FILE", "Every CSV row must include an email column.");
    }

    const firstName = readValue(row, ["first_name", "firstname", "first name", "given_name"]);
    const lastName = readValue(row, ["last_name", "lastname", "last name", "surname", "family_name"]);
    const fullName =
      (
        readValue(row, ["name", "full_name", "full name", "contact_name"]) ??
        [firstName, lastName].filter(Boolean).join(" ").trim()
      ) || null;

    return {
      email: normalizeEmail(email),
      full_name: fullName,
      first_name: firstName,
      last_name: lastName,
      alternate_email: readValue(row, ["alternate_email", "other_email", "secondary_email", "alt_email", "personal_email"]),
      phone: readValue(row, ["phone", "phone_number", "mobile", "telephone"]),
      source: readValue(row, ["source", "lead_source", "origin"]),
      company: readValue(row, ["company", "organization", "business"]),
      job_title: readValue(row, ["job_title", "title", "role", "position"]),
      country: readValue(row, ["country", "country_name"]),
      city: readValue(row, ["city", "town"]),
      lifecycle_stage: readValue(row, ["lifecycle_stage", "stage", "lead_stage", "customer_stage"]),
      notes: readValue(row, ["notes", "note", "description", "other_information", "other information"]),
      tags: (readValue(row, ["tags"]) ?? "")
        .split(",")
        .map((tag) => tag.trim())
        .filter(Boolean)
    };
  });
}

export function dedupeContacts(items: ImportedContact[]) {
  const seen = new Set<string>();

  return items.filter((item) => {
    if (!item.email.includes("@") || seen.has(item.email)) {
      return false;
    }

    seen.add(item.email);
    return true;
  });
}
