/**
 * The KCGM account-deletion mails, by region.
 *
 * Two letters per deletion and five regions, so ten templates. The split is a data
 * protection one, not a marketing one: what a UK or European member must be told
 * about erasure of their personal data differs from what an Indian or Indonesian
 * member is told, and sending the wrong region's letter is a compliance problem
 * rather than a cosmetic one.
 *
 * Hardcoded, like the deletion status ids, and for the same reason: these are not an
 * environment's preference, they are what "deleting a KCGM account" means. An
 * environment that pointed them somewhere else would be performing a different
 * action under the same name. An operator can still override either mail per
 * deletion from the console when a specific case calls for it.
 */

export type DeletionRegion =
  | "uk"
  | "europe"
  | "india"
  | "indonesia"
  | "others";

export interface RegionTemplates {
  region: DeletionRegion;
  label: string;
  /** Sent when the account is retired. */
  acknowledgement: { id: string; name: string };
  /** Sent 30 days later, unless the account is reactivated first. */
  confirmation: { id: string; name: string };
}

export const DELETION_TEMPLATES: Record<DeletionRegion, RegionTemplates> = {
  uk: {
    region: "uk",
    label: "United Kingdom",
    acknowledgement: {
      id: "d-78e3ef4c753e49c49dc7aafee0761e87",
      name: "KCGM_Membership_Deletion_UK_Acknowledgement",
    },
    confirmation: {
      id: "d-5b3d29acc0f34f35a40656b292f20fba",
      name: "Confirmation_Of_Personal_Data_Deletion_UK",
    },
  },
  europe: {
    region: "europe",
    label: "Europe",
    acknowledgement: {
      id: "d-d78757a662a7410fbf9134fa53b27f83",
      name: "KCGM_Membership_Deletion_Europe_Acknowledgement",
    },
    confirmation: {
      id: "d-fda150c5f3da429fba34d6b0d733a5bf",
      name: "Confirmation_Of_Personal_Data_Deletion_Europe",
    },
  },
  india: {
    region: "india",
    label: "India",
    acknowledgement: {
      id: "d-739b02131a85479aba1700ef26188beb",
      name: "KCGM_Membership_Deletion_India_Acknowledgement",
    },
    confirmation: {
      id: "d-2676ef20375840a691a5ac0cc201683e",
      name: "Confirmation_Of_Personal_Data_Deletion_India",
    },
  },
  indonesia: {
    region: "indonesia",
    label: "Indonesia",
    acknowledgement: {
      id: "d-55b9ef532d5c4183a5fbd46b26328479",
      name: "KCGM_Membership_Deletion_Indonesia_Acknowledgement",
    },
    confirmation: {
      id: "d-148066cbfb7c4f6e96cdb3c06494deda",
      name: "Confirmation_Of_Personal_Data_Deletion_Indonesia",
    },
  },
  others: {
    region: "others",
    label: "Rest of world",
    acknowledgement: {
      id: "d-71607285701b41a0a9f975f4d09c48d0",
      name: "KCGM_Membership_Deletion_Others_Acknowledgement",
    },
    confirmation: {
      id: "d-00fc5f9eaaa94ea680a34801ea9a902e",
      name: "Confirmation_Of_Personal_Data_Deletion_Others",
    },
  },
};

export const DELETION_REGIONS = Object.values(DELETION_TEMPLATES);

/*
 * Countries are matched on names as well as codes.
 *
 * Viewpoint and the member database disagree about which they store — one row says
 * "GB", the next says "United Kingdom", a third says "U.K." — and a lookup that
 * handled only one form would silently drop members into "Rest of world", which is
 * the one bucket whose letter says the least. Anything unrecognised still lands
 * there, but the console shows the detected region so an operator can correct it.
 */
const UK = new Set([
  "gb",
  "gbr",
  "uk",
  "unitedkingdom",
  "greatbritain",
  "england",
  "scotland",
  "wales",
  "northernireland",
]);

const INDIA = new Set(["in", "ind", "india"]);

const INDONESIA = new Set(["id", "idn", "indonesia"]);

/*
 * The EEA, which is the population the European letter is written for — the EU plus
 * Iceland, Liechtenstein and Norway, all of which the GDPR reaches. Switzerland is
 * included too: it is outside the EEA but its own law tracks the GDPR closely enough
 * that the European letter is the right one.
 */
const EUROPE = new Set([
  "at", "aut", "austria",
  "be", "bel", "belgium",
  "bg", "bgr", "bulgaria",
  "hr", "hrv", "croatia",
  "cy", "cyp", "cyprus",
  "cz", "cze", "czechia", "czechrepublic",
  "dk", "dnk", "denmark",
  "ee", "est", "estonia",
  "fi", "fin", "finland",
  "fr", "fra", "france",
  "de", "deu", "germany",
  "gr", "grc", "greece",
  "hu", "hun", "hungary",
  "ie", "irl", "ireland",
  "it", "ita", "italy",
  "lv", "lva", "latvia",
  "lt", "ltu", "lithuania",
  "lu", "lux", "luxembourg",
  "mt", "mlt", "malta",
  "nl", "nld", "netherlands", "thenetherlands", "holland",
  "pl", "pol", "poland",
  "pt", "prt", "portugal",
  "ro", "rou", "romania",
  "sk", "svk", "slovakia",
  "si", "svn", "slovenia",
  "es", "esp", "spain",
  "se", "swe", "sweden",
  "is", "isl", "iceland",
  "li", "lie", "liechtenstein",
  "no", "nor", "norway",
  "ch", "che", "switzerland",
]);

const normalise = (value: string) =>
  value.toLowerCase().replace(/[^a-z]/g, "");

/**
 * Which region's letters an account gets.
 *
 * Checked most specific first: the UK is not in the EEA set but shares wording with
 * it closely enough that a mistake between the two is easy to make, so it is decided
 * before Europe is consulted.
 *
 * Falls back to "others" for anything unrecognised — including no country at all,
 * which is common enough on older accounts to be the normal case rather than an
 * error. The console shows what was detected so it can be corrected before sending.
 */
export const resolveDeletionRegion = (
  country: string | null | undefined,
): DeletionRegion => {
  if (!country) return "others";
  const key = normalise(country);
  if (!key) return "others";
  if (UK.has(key)) return "uk";
  if (INDIA.has(key)) return "india";
  if (INDONESIA.has(key)) return "indonesia";
  if (EUROPE.has(key)) return "europe";
  return "others";
};

export const isDeletionRegion = (value: string): value is DeletionRegion =>
  value in DELETION_TEMPLATES;

/*
 * Charge centre names, matched on the region they name.
 *
 * A charge centre is where the membership is billed, which is a firmer statement of
 * which entity the member belongs to than the address on the account — an account
 * can carry a holiday address, or none, and still be billed by Karma Group India.
 * So this is consulted before the country.
 *
 * Substring matching rather than an id list, because charge centres are created in
 * Viewpoint and mirrored here: a new one appears without any deploy, and a rule that
 * reads its name keeps working where a hardcoded id map would silently fall through
 * to "Rest of world".
 *
 * Order matters. "United Kingdom" contains neither "europe" nor "eu", but a centre
 * named "Karma Europe (UK)" contains both, and the UK letter is the right one — so
 * the more specific regions are tested first.
 */
const CHARGE_CENTRE_RULES: Array<{ region: DeletionRegion; tokens: string[] }> = [
  { region: "uk", tokens: ["unitedkingdom", "uk", "britain", "british", "gbp"] },
  { region: "indonesia", tokens: ["indonesia", "indonesian", "idr", "bali"] },
  { region: "india", tokens: ["india", "indian", "inr"] },
  {
    region: "europe",
    tokens: ["europe", "european", "eur", "eea", "germany", "france", "spain"],
  },
];

/**
 * Which region a charge centre bills for.
 *
 * Returns null rather than "others" when nothing matches. The distinction is the
 * point: null means "this charge centre told us nothing", which is what lets the
 * caller fall through to the country instead of settling for the least specific
 * letter on the strength of a name it did not recognise.
 */
export const resolveRegionFromChargeCentre = (
  name: string | null | undefined,
): DeletionRegion | null => {
  if (!name) return null;
  const key = normalise(name);
  if (!key) return null;
  for (const rule of CHARGE_CENTRE_RULES) {
    if (rule.tokens.some((token) => key.includes(token))) {
      return rule.region;
    }
  }
  return null;
};

/** Where a resolved region came from, so the console can say so. */
export type RegionSource = "charge-centre" | "country" | "fallback";
