import type { BulkUserAppointment, BulkUserItem } from "../../../lib/adminApi";

export function parseUserCSV(text: string): BulkUserItem[] {
  const records = parseCSVRecords(text.replace(/^\uFEFF/, ""));
  if (records.length < 2) {
    return [];
  }

  const headers = records[0].map(normalizeHeader);
  const data: BulkUserItem[] = [];

  for (let i = 1; i < records.length; i++) {
    const values = records[i].map((v) => v.trim());
    if (values.every((value) => value === "")) continue;
    const item: Partial<BulkUserItem> & {
      metadata: Record<string, unknown>;
    } = {
      metadata: {},
    };
    const additionalAppointment: BulkUserAppointment & {
      metadata: Record<string, unknown>;
    } = {
      metadata: {},
    };

    for (let index = 0; index < headers.length; index++) {
      const header = headers[index];
      const value = values[index];
      if (value === undefined || value === "") continue;

      if (header === "email") {
        item.email = value;
      } else if (header === "name") {
        item.name = value;
      } else if (header === "phone") {
        item.phone = value;
      } else if (header === "role") {
        item.role = value;
      } else if (header === "tenant") {
        item.tenantSlug = value;
      } else if (header === "tenant_slug" || header === "companycode") {
        item.tenantSlug = value;
        item.tenantImport = {
          ...(item.tenantImport ?? {}),
          slug: value,
        };
      } else if (header === "tenant_id") {
        item.tenantId = value;
        item.tenantImport = {
          ...(item.tenantImport ?? {}),
          sourceTenantId: value,
        };
      } else if (header === "tenant_name") {
        item.tenantImport = {
          ...(item.tenantImport ?? {}),
          name: value,
        };
      } else if (header === "tenant_type") {
        item.tenantImport = {
          ...(item.tenantImport ?? {}),
          type: value,
        };
      } else if (header === "parent_tenant_id") {
        item.tenantImport = {
          ...(item.tenantImport ?? {}),
          parentTenantId: value,
        };
      } else if (header === "parent_tenant_slug") {
        item.tenantImport = {
          ...(item.tenantImport ?? {}),
          parentTenantSlug: value,
        };
      } else if (header === "parent_tenant_name") {
        item.tenantImport = {
          ...(item.tenantImport ?? {}),
          parentTenantName: value,
        };
      } else if (header === "tenant_memo") {
        item.tenantImport = {
          ...(item.tenantImport ?? {}),
          memo: value,
        };
      } else if (header === "email_domain" || header === "tenant_domain") {
        item.emailDomain = value;
        item.tenantImport = {
          ...(item.tenantImport ?? {}),
          emailDomain: value,
        };
      } else if (header === "department") {
        item.department = value;
      } else if (header === "grade") {
        item.grade = value;
      } else if (header === "position") {
        item.position = value;
      } else if (header === "jobtitle") {
        item.jobTitle = value;
      } else if (header === "employee_id") {
        item.metadata.employee_id = value;
      } else if (header === "secondary_emails") {
        applySecondaryEmailMetadata(item, value);
      } else if (header === "tenant_slug1") {
        additionalAppointment.tenantSlug = value;
      } else if (header === "department1") {
        additionalAppointment.department = value;
      } else if (header === "grade1") {
        additionalAppointment.grade = value;
      } else if (header === "position1") {
        additionalAppointment.position = value;
      } else if (header === "jobtitle1") {
        additionalAppointment.jobTitle = value;
      } else if (header === "employee_id1") {
        additionalAppointment.metadata.employee_id = value;
      } else if (header === "lastname") {
        item.metadata.naverworks_last_name = value;
      } else if (header === "firstname") {
        item.metadata.naverworks_first_name = value;
      } else if (header === "id") {
        item.loginId = value;
        item.metadata.naverworks_id = value;
      } else if (header === "personalemail") {
        item.metadata.personal_email = value;
      } else if (header === "subemail") {
        item.metadata.naverworks_sub_email = value;
        addWorksmobileAliasEmails(item, splitEmailTokens(value).slice(1));
        item.email = firstEmailToken(value) || item.email;
      } else if (header === "nickname") {
        item.metadata.naverworks_nickname = value;
      } else if (header === "usertype") {
        item.metadata.naverworks_user_type = value;
      } else if (header === "level") {
        item.grade = value;
        item.metadata.naverworks_level = value;
      } else if (header === "organization") {
        item.metadata.naverworks_organization_path = value;
        const parts = splitOrganizationPath(value);
        const leaf = parts.at(-1) ?? "";
        const parent = parts.at(-2) ?? "";
        if (leaf) {
          item.department = leaf;
          item.tenantImport = {
            ...(item.tenantImport ?? {}),
            name: leaf,
            parentTenantName: parent,
          };
        }
      } else if (header === "companymainphone") {
        item.metadata.naverworks_company_main_phone = value;
      } else if (header === "mobilecountrycode") {
        item.metadata.naverworks_mobile_country_code = value;
      } else if (header === "mobilenumbers") {
        item.metadata.naverworks_mobile_numbers = value;
      } else if (header === "language") {
        item.metadata.naverworks_language = value;
      } else if (header === "responsibilities") {
        item.jobTitle = value;
      } else if (header === "workplace") {
        item.metadata.naverworks_workplace = value;
      } else if (header === "sns") {
        item.metadata.naverworks_sns = value;
      } else if (header === "snsid") {
        item.metadata.naverworks_sns_id = value;
      } else if (header === "birthdaysolarlunar") {
        item.metadata.naverworks_birthday_calendar = value;
      } else if (header === "birthday") {
        item.metadata.naverworks_birthday = value;
      } else if (header === "entrydate") {
        item.metadata.naverworks_entry_date = value;
      } else if (header === "employeenumber") {
        item.metadata.employee_id = value;
      } else if (header === "accountactivationtime") {
        item.metadata.naverworks_account_activation_time = value;
      } else {
        item.metadata[header] = value;
      }
    }

    applyNaverWorksFallbacks(item);
    if (additionalAppointment.tenantSlug) {
      item.additionalAppointments = [
        cleanAdditionalAppointment(additionalAppointment),
      ];
    }

    if (item.email && item.name) {
      data.push(item as BulkUserItem);
    }
  }

  return markBulkEmailDuplicateErrors(data);
}

function cleanAdditionalAppointment(
  appointment: BulkUserAppointment & { metadata: Record<string, unknown> },
) {
  const metadata =
    Object.keys(appointment.metadata).length > 0
      ? appointment.metadata
      : undefined;
  return {
    ...(appointment.tenantId ? { tenantId: appointment.tenantId } : {}),
    ...(appointment.tenantSlug ? { tenantSlug: appointment.tenantSlug } : {}),
    ...(appointment.tenantName ? { tenantName: appointment.tenantName } : {}),
    ...(appointment.isPrimary !== undefined
      ? { isPrimary: appointment.isPrimary }
      : {}),
    ...(appointment.isOwner !== undefined
      ? { isOwner: appointment.isOwner }
      : {}),
    ...(appointment.isAdmin !== undefined
      ? { isAdmin: appointment.isAdmin }
      : {}),
    ...(appointment.isManager !== undefined
      ? { isManager: appointment.isManager }
      : {}),
    ...(appointment.department ? { department: appointment.department } : {}),
    ...(appointment.grade ? { grade: appointment.grade } : {}),
    ...(appointment.position ? { position: appointment.position } : {}),
    ...(appointment.jobTitle ? { jobTitle: appointment.jobTitle } : {}),
    ...(metadata ? { metadata } : {}),
  };
}

function normalizeHeader(header: string) {
  const raw = header.trim().replace(/^\uFEFF/, "");
  const lower = raw.toLowerCase();
  const separatorNormalized = lower.replace(/-+/g, "_").replace(/_+/g, "_");
  const compactKorean = raw.replace(/\s+/g, "");

  if (
    [
      "sub_email",
      "secondary_email",
      "secondary_emails",
      "additional_email",
      "additional_emails",
      "alias_email",
      "alias_emails",
      "worksmobile_alias_email",
      "worksmobile_alias_emails",
    ].includes(separatorNormalized) ||
    ["보조이메일", "보조메일", "추가이메일", "추가메일"].includes(compactKorean)
  ) {
    return "secondary_emails";
  }

  return raw
    .trim()
    .toLowerCase()
    .replace(/^\uFEFF/, "")
    .replace(/[^a-z0-9_]/g, "");
}

function parseCSVRecords(text: string) {
  const records: string[][] = [];
  let field = "";
  let row: string[] = [];
  let quoted = false;

  for (let index = 0; index < text.length; index++) {
    const char = text[index];
    const next = text[index + 1];

    if (char === '"') {
      if (quoted && next === '"') {
        field += '"';
        index++;
      } else {
        quoted = !quoted;
      }
      continue;
    }

    if (char === "," && !quoted) {
      row.push(field);
      field = "";
      continue;
    }

    if ((char === "\n" || char === "\r") && !quoted) {
      if (char === "\r" && next === "\n") index++;
      row.push(field);
      records.push(row);
      field = "";
      row = [];
      continue;
    }

    field += char;
  }

  if (field !== "" || row.length > 0) {
    row.push(field);
    records.push(row);
  }

  return records;
}

function firstEmailToken(value: string) {
  return splitEmailTokens(value)[0] ?? "";
}

function splitEmailTokens(value: string) {
  return value
    .split(/[;,\n\r\t]/)
    .map((token) => token.trim())
    .filter((token) => token.includes("@"));
}

function metadataString(value: unknown) {
  return typeof value === "string" ? value : "";
}

function metadataEmailList(value: unknown) {
  if (Array.isArray(value)) {
    return value
      .map((item) => (typeof item === "string" ? item.trim() : ""))
      .filter(Boolean);
  }
  if (typeof value === "string") {
    return splitEmailTokens(value);
  }
  return [];
}

function uniqueEmails(values: string[]) {
  const seen = new Set<string>();
  const result: string[] = [];
  for (const value of values) {
    const normalized = value.trim().toLowerCase();
    if (!normalized || seen.has(normalized)) continue;
    seen.add(normalized);
    result.push(normalized);
  }
  return result;
}

function bulkUserImportErrorList(user: BulkUserItem) {
  return Array.isArray(user.importErrors) ? user.importErrors : [];
}

function withBulkUserImportError(user: BulkUserItem, error: string) {
  const errors = Array.from(new Set([...bulkUserImportErrorList(user), error]));
  return { ...user, importErrors: errors };
}

function bulkUserAliasEmails(user: BulkUserItem) {
  return uniqueEmails([
    ...metadataEmailList(user.metadata.sub_email),
    ...metadataEmailList(user.metadata.aliasEmails),
    ...metadataEmailList(user.metadata.secondary_emails),
    ...metadataEmailList(user.metadata.worksmobileAliasEmails),
  ]);
}

function markBulkEmailDuplicateErrors(users: BulkUserItem[]) {
  const duplicateIndexes = new Set<number>();
  const owners = new Map<string, Set<number>>();

  users.forEach((user, index) => {
    const primaryEmail = user.email.trim().toLowerCase();
    const aliases = bulkUserAliasEmails(user);
    const rowEmails = new Set<string>();

    if (primaryEmail) {
      rowEmails.add(primaryEmail);
    }
    for (const alias of aliases) {
      if (primaryEmail && alias === primaryEmail) {
        duplicateIndexes.add(index);
      }
      rowEmails.add(alias);
    }

    for (const email of rowEmails) {
      const existing = owners.get(email) ?? new Set<number>();
      existing.add(index);
      owners.set(email, existing);
    }
  });

  for (const indexes of owners.values()) {
    if (indexes.size < 2) {
      continue;
    }
    for (const index of indexes) {
      duplicateIndexes.add(index);
    }
  }

  return users.map((user, index) =>
    duplicateIndexes.has(index)
      ? withBulkUserImportError(user, "duplicateEmail")
      : user,
  );
}

function addWorksmobileAliasEmails(
  item: Partial<BulkUserItem> & { metadata: Record<string, unknown> },
  emails: string[],
) {
  const aliases = uniqueEmails([
    ...metadataEmailList(item.metadata.aliasEmails),
    ...emails,
  ]);
  if (aliases.length > 0) {
    item.metadata.aliasEmails = aliases;
    item.metadata.worksmobileAliasEmails = aliases;
  }
}

function applySecondaryEmailMetadata(
  item: Partial<BulkUserItem> & { metadata: Record<string, unknown> },
  value: string,
) {
  const emails = splitEmailTokens(value);
  const uniqueSecondaryEmails = uniqueEmails([
    ...metadataEmailList(item.metadata.secondary_emails),
    ...emails,
  ]);
  item.metadata.sub_email = emails;
  item.metadata.secondary_emails = uniqueSecondaryEmails;
  addWorksmobileAliasEmails(item, emails);
}

function splitOrganizationPath(value: string) {
  return value
    .split("|")
    .map((part) => part.trim())
    .filter(Boolean);
}

function applyNaverWorksFallbacks(
  item: Partial<BulkUserItem> & { metadata: Record<string, unknown> },
) {
  if (!item.name) {
    const firstName = metadataString(item.metadata.naverworks_first_name);
    const lastName = metadataString(item.metadata.naverworks_last_name);
    item.name = [firstName, lastName].filter(Boolean).join(" ").trim();
    const nickname = metadataString(item.metadata.naverworks_nickname);
    if (!item.name && nickname) {
      item.name = nickname;
    }
  }

  if (!item.email) {
    item.email = metadataString(item.metadata.personal_email);
  }

  if (!item.phone) {
    const countryCode = metadataString(
      item.metadata.naverworks_mobile_country_code,
    );
    const number = metadataString(item.metadata.naverworks_mobile_numbers);
    item.phone = `${countryCode}${number}`.replace(/\s/g, "");
  }

  const level = metadataString(item.metadata.naverworks_level);
  if (!item.grade && level) {
    item.grade = level;
  }
}
