/* ========================================================================
   estate-data.jsx — Estate model (Story 1)
   Every SIM belongs to exactly one estate group: pool | individual |
   international | travel. This file adds the two new groups to the shared
   SIM list, plus the country reference data and the monthly usage load.
   Loads immediately after data.jsx.
   ======================================================================== */
const ED = window.MILO_DATA;

/* ---------- Countries we hold international SIMs in ---------- */
const COUNTRIES = {
  IE: { code: "IE", name: "Ireland",     flag: "🇮🇪", network: "Three Ireland" },
  FR: { code: "FR", name: "France",      flag: "🇫🇷", network: "Orange France" },
  ES: { code: "ES", name: "Spain",       flag: "🇪🇸", network: "Movistar" },
  NL: { code: "NL", name: "Netherlands", flag: "🇳🇱", network: "KPN" },
  SG: { code: "SG", name: "Singapore",   flag: "🇸🇬", network: "Singtel" }
};

/* ---------- The monthly usage load ----------
   One load per month, on the 1st. It stamps every international and travel
   surface at once, so the date is computed here and never hard-coded. The
   Tweaks panel can roll the month forward to demonstrate an arrival. */
const ESTATE_NOW = new Date();
const MONTH_OFFSET_KEY = "mp_estate_month_offset";
function monthOffset() {
  try { return parseInt(localStorage.getItem(MONTH_OFFSET_KEY) || "0", 10) || 0; } catch (e) { return 0; }
}
function rollUsageMonth(by) {
  try { localStorage.setItem(MONTH_OFFSET_KEY, String(monthOffset() + (by == null ? 1 : by))); } catch (e) {}
}
const loadDate = () => new Date(ESTATE_NOW.getFullYear(), ESTATE_NOW.getMonth() + monthOffset(), 1);
const usageMonthDate = () => new Date(ESTATE_NOW.getFullYear(), ESTATE_NOW.getMonth() + monthOffset() - 1, 1);
const monthEndDate = () => new Date(ESTATE_NOW.getFullYear(), ESTATE_NOW.getMonth() + monthOffset() + 1, 0);
const fmtDayMonth = (d) => d.toLocaleDateString("en-GB", { day: "numeric", month: "long" });
const fmtLoadFull = (d) => d.toLocaleDateString("en-GB", { day: "numeric", month: "long", year: "numeric" });
const fmtMonthYear = (d) => d.toLocaleDateString("en-GB", { month: "long", year: "numeric" });
const fmtMonth = (d) => d.toLocaleDateString("en-GB", { month: "long" });
const daysFromNow = (n) => new Date(ESTATE_NOW.getFullYear(), ESTATE_NOW.getMonth(), ESTATE_NOW.getDate() + n);
const intlBackDate = (days) => daysFromNow(-days).toISOString().slice(0, 10);

/* ---------- International SIMs ---------- */
const INTL_SPEC = [["IE", 8], ["FR", 7], ["ES", 6], ["NL", 5], ["SG", 4]];
function localNumber(cc, i) {
  if (cc === "IE") return "+353 87 " + (300 + i) + " " + (4100 + i * 7);
  if (cc === "FR") return "+33 6 " + (12 + i) + " " + (34 + i) + " " + (56 + i) + " " + (78 - i);
  if (cc === "ES") return "+34 6" + (10 + i) + " " + (200 + i * 3) + " " + (410 + i * 7);
  if (cc === "NL") return "+31 6 " + (1200 + i * 11) + " " + (3400 + i * 13);
  return "+65 8" + (100 + i) + " " + (2300 + i * 9);
}
/* Deterministic, plausible monthly figures. No live data is implied. */
/* Exactly one SIM exceeds its allowance: index 1, at 112 GB of 100 GB. */
const INTL_USED = [18.4, 112, 6.2, 41.7, 9.8, 27.3, 3.1, 33.9, 14.6, 44.6, 7.7, 21.2, 48.1, 11.5, 2.9,
  36.8, 19.3, 5.4, 44.2, 8.1, 25.6, 13.7, 30.4, 4.6, 17.9, 39.5, 10.2, 22.8, 6.9, 28.7];
const INTL_PREV = [21.1, 96.4, 5.8, 38.2, 12.4, 24.9, 3.6, 30.1, 16.2, 47.8, 6.9, 19.4, 44.6, 13.1, 3.4,
  33.2, 17.8, 6.1, 40.9, 7.4, 23.1, 15.2, 27.6, 5.2, 20.3, 35.7, 9.4, 24.5, 7.8, 26.2];
const INTL_STATUS = { 4: "Suspended", 17: "Suspended", 23: "For Activation" };
/* A modest spread of the international estate is assigned to named people. */
const INTL_ASSIGN = { 0: 3, 2: 5, 5: 1, 8: 4, 11: 7, 13: 2, 16: 8, 19: 9, 22: 12, 26: 13 };

/* Plan inclusions, set by the local network. */
const INTL_CALLS = ["500 minutes", "1000 minutes", "Unlimited minutes"];
const INTL_TEXTS = ["500 texts", "Unlimited texts"];
const EU_MARKETS = ["IE", "FR", "ES", "NL"];

const INTERNATIONAL_SIMS = [];
let ix = 0;
INTL_SPEC.forEach(([cc, count]) => {
  for (let i = 0; i < count; i++) {
    const n = ix;
    INTERNATIONAL_SIMS.push({
      id: 101 + n,
      group: "international",
      serial: "894420191234000" + String(3100 + n),
      msisdn: localNumber(cc, i),
      status: INTL_STATUS[n] || "Active",
      sim_type: n % 3 === 0 ? "eSIM" : "Physical",
      plan: "big",
      country: cc,
      network: COUNTRIES[cc].network,
      /* The 25 GB band used to catch several heavy users, which turned the
         over-allowance flag into wallpaper. One SIM exceeds its allowance. */
      allowance_gb: n === 1 ? 100 : n % 4 === 0 ? 60 : 50,
      /* One international eSIM is still waiting to be set up. */
      install_state: n === 21 ? "ready" : undefined,
      used: INTL_USED[n],
      prev_used: INTL_PREV[n],
      data_active: (INTL_STATUS[n] || "Active") === "Active",
      /* Back-dated from today, like the UK working estate, so no year goes
         stale. Spread across roughly the last eighteen months. */
      activation_date: intlBackDate(120 + n * 17),
      /* One SIM was provisioned this month, so it has no full month yet. */
      provisioned: n === 29 ? new Date(ESTATE_NOW.getFullYear(), ESTATE_NOW.getMonth(), 12) : daysFromNow(-(118 + n * 17)),
      calls: INTL_CALLS[n % 3],
      texts: INTL_TEXTS[n % 2],
      eu_roaming: EU_MARKETS.indexOf(cc) !== -1,
      user_id: INTL_ASSIGN[n] || null
    });
    ix++;
  }
});

/* ---------- Travel eSIMs ---------- */
const COVERAGE = {
  europe: { label: "Europe Zone", countries: 39 },
  apac: { label: "Asia Pacific Zone", countries: 14 }
};
const TRAVEL_SIMS = [
  { id: 201, user_id: 3,  coverage: "europe", allowance_gb: 10, plan_type: "Recurring", used: 4.2,  prev_used: 6.8, renews: 1 },
  { id: 202, user_id: 1,  coverage: "us",     allowance_gb: 5,  plan_type: "One-Off",   used: 3.9,  prev_used: 0,   expires_in: 9 },
  { id: 203, user_id: 4,  coverage: "global90", allowance_gb: 20, plan_type: "Recurring", used: 11.4, prev_used: 9.2, renews: 1 },
  { id: 204, user_id: 5,  coverage: "apac",   allowance_gb: 10, plan_type: "One-Off",   used: 2.1,  prev_used: 0,   expires_in: 52 },
  { id: 205, user_id: 6,  coverage: "europe", allowance_gb: 5,  plan_type: "One-Off",   used: 1.6,  prev_used: 0,   expires_in: 74, install_state: "ready" },
  { id: 206, user_id: 8,  coverage: "global90", allowance_gb: 20, plan_type: "Recurring", used: 8.7,  prev_used: 12.1, renews: 1 }
].map((t, i) => ({
  ...t,
  group: "travel",
  serial: "894420191234000" + String(4200 + i),
  msisdn: "Data only",
  status: "Active",
  sim_type: "eSIM",
  plan: "small",
  data_active: true,
  activation_date: null,
  provisioned: daysFromNow(-(20 + i * 9)),
  expires: t.expires_in ? daysFromNow(t.expires_in) : null,
  renews_on: t.renews ? new Date(ESTATE_NOW.getFullYear(), ESTATE_NOW.getMonth() + 1, 1) : null
}));

/* ---------- Individual SIMs on alternative UK networks ----------
   UK SIMs provisioned on O2 or Vodafone rather than the core network. Usage
   is live, like UK individual SIMs; changes go through the request kit. */
const ALTNET_SPEC = [
  ["O2", "Physical", "big", 11.6, "Active", 6],
  ["O2", "eSIM", "small", 3.2, "Active", 10],
  ["Vodafone", "Physical", "unlimited", 38.4, "Active", 11],
  ["Vodafone", "eSIM", "big", 19.7, "Active", null],
  ["O2", "Physical", "big", 7.9, "Active", 2],
  ["Vodafone", "Physical", "small", 0.8, "Suspended", 8],
  ["O2", "eSIM", "unlimited", 24.1, "Active", null],
  ["Vodafone", "eSIM", "small", 0, "For Activation", null]];
const ALTNET_SIMS = ALTNET_SPEC.map(([network, type, plan, used, status, uid], i) => ({
  id: 301 + i,
  group: "altnet",
  serial: (network === "O2" ? "8944110" : "8944100") + "91234000" + String(5101 + i),
  msisdn: "+44 7700 900" + String(601 + i * 7),
  status, sim_type: type, plan, used, network,
  data_active: status === "Active",
  activation_date: status === "For Activation" ? null : intlBackDate(90 + i * 31),
  user_id: uid
}));

/* ---------- Fold the new groups into the shared estate ---------- */
ED.SIMS.push(...INTERNATIONAL_SIMS, ...ALTNET_SIMS, ...TRAVEL_SIMS);
[...INTERNATIONAL_SIMS, ...ALTNET_SIMS, ...TRAVEL_SIMS].forEach((s) => {
  if (s.user_id == null) return;
  const u = ED.USERS.find((x) => x.id === s.user_id);
  if (u && u.sim_ids.indexOf(s.id) === -1) u.sim_ids.push(s.id);
});

/* ---------- Helpers shared by the estate surfaces ---------- */
const estGb = (n) => (Math.round(n * 10) % 10 === 0 ? String(Math.round(n)) : n.toFixed(1));
const internationalSims = () => ED.SIMS.filter((s) => s.group === "international");
const travelSims = () => ED.SIMS.filter((s) => s.group === "travel");
const altnetSims = () => ED.SIMS.filter((s) => s.group === "altnet");
function countrySummary() {
  const out = [];
  Object.keys(COUNTRIES).forEach((cc) => {
    const rows = internationalSims().filter((s) => s.country === cc);
    if (!rows.length) return;
    out.push({ ...COUNTRIES[cc], count: rows.length, used: rows.reduce((a, s) => a + s.used, 0) });
  });
  return out.sort((a, b) => b.count - a.count);
}
function travelExpiringSoon() {
  return travelSims().filter((s) => s.expires && (s.expires - ESTATE_NOW) / 86400000 <= 30).length;
}
function allowanceState(sim) {
  const over = sim.used - sim.allowance_gb;
  return over > 0 ?
    { over: true, label: "Over allowance: " + estGb(over) + " GB over, additional charges apply" } :
    { over: false, label: "Within allowance" };
}
/* Every date a user reads carries its year. */
function estFmtDate(d) { return d ? fmtLoadFull(d) : null; }
/* True while a SIM has not yet completed its first month. */
function awaitingFirstMonth(sim) {
  return !!sim.provisioned && sim.provisioned >= loadDate();
}

/* ---------- Billing lines for the rest of the estate ----------
   International and travel SIMs are billed too, so they get their own
   subscriptions rather than being invisible on Subscription and Billing.
   Fictional pricing, generated per SIM. */
function seedEstateSubscriptions() {
  if (!ED.SUBSCRIPTIONS) return;
  const nextBill = new Date(ESTATE_NOW.getFullYear(), ESTATE_NOW.getMonth() + 1, 8);
  const ends = new Date(ESTATE_NOW.getFullYear() + 1, ESTATE_NOW.getMonth() + 4, 8);
  const fmt = (x) => x.toLocaleDateString("en-GB", { day: "numeric", month: "long", year: "numeric" });
  /* International plans are priced per SIM by allowance, travel plans by their
     own record, so both read as real lines rather than a single lump. */
  /* Priced per SIM by allowance. This is the SIM's only price: nothing reads
     its UK plan field for money. */
  const INTL_PRICE = { 50: 22, 60: 26, 100: 34 };
  INTERNATIONAL_SIMS.forEach((s) => { s.monthly_price = INTL_PRICE[s.allowance_gb] || 22; });
  ED.SUBSCRIPTIONS.push({
    id: 4903, stripe_status: "active", label: "International SIMs",
    sim_ids: INTERNATIONAL_SIMS.filter((s) => s.status !== "Terminated").map((s) => s.id),
    next_bill: fmt(nextBill), expires: fmt(ends)
  });
  ED.SUBSCRIPTIONS.push({
    id: 4931, stripe_status: "active", label: "Individual SIMs (Alternative Networks)",
    sim_ids: ALTNET_SIMS.filter((s) => s.status !== "Terminated").map((s) => s.id),
    next_bill: fmt(nextBill), expires: fmt(ends)
  });
  ED.SUBSCRIPTIONS.push({
    id: 4917, stripe_status: "active", label: "Travel eSIM plans",
    sim_ids: TRAVEL_SIMS.map((s) => s.id),
    next_bill: fmt(nextBill), expires: "Rolling"
  });
}
seedEstateSubscriptions();

window.MP_ESTATE = {
  COUNTRIES, COVERAGE, internationalSims, travelSims, altnetSims, countrySummary, travelExpiringSoon,
  allowanceState, estGb, fmtDate: estFmtDate, awaitingFirstMonth, rollUsageMonth,
  get loadLabel() { return fmtDayMonth(loadDate()); },
  get loadLabelFull() { return fmtLoadFull(loadDate()); },
  get monthLabel() { return fmtMonth(usageMonthDate()); },
  get monthFull() { return fmtMonthYear(usageMonthDate()); },
  get monthEndLabel() { return fmtDayMonth(monthEndDate()); },
  groupOf: (sim) => sim && sim.group ? sim.group : null
};
