"use client";
/**
 * Estado en memoria para la maquetación (con respaldo en localStorage del navegador).
 * En producción, cada `mutate` se reemplaza por una llamada a la API y el estado
 * se hidrata desde el servidor.
 */
import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState, type ReactNode } from "react";
import * as M from "./mock";
import type {
  Appointment, Claim, Clinic, Doctor, FeedItem, Insurer, Lab, MembershipPlan, Patient, Plan, Referral, Role, Service, Sponsor,
} from "./types";
import { budgetSplit, patientBalance, membershipDiscount, type SplitContext } from "./logic";

export interface AppState {
  today: string;
  role: Role;
  doctorId: string;
  folio: number;
  clinic: Clinic;
  doctors: Doctor[];
  plans: Plan[];
  services: Service[];
  meds: string[];
  patients: Patient[];
  appointments: Appointment[];
  membershipPlans: MembershipPlan[];
  insurers: Insurer[];
  claims: Claim[];
  labs: Lab[];
  referrals: Referral[];
  sponsors: Sponsor[];
  feed: FeedItem[];
}

const initial = (): AppState =>
  structuredClone({
    today: M.TODAY, role: "recepcion" as Role, doctorId: "d1", folio: 1043,
    clinic: M.clinic, doctors: M.doctors, plans: M.plans, services: M.services, meds: M.meds,
    patients: M.patients, appointments: M.appointments, membershipPlans: M.membershipPlans,
    insurers: M.insurers, claims: M.claims, labs: M.labs, referrals: M.referrals, sponsors: M.sponsors, feed: M.feed,
  });

const KEY = "kada-dental-demo-v1";

interface Store {
  s: AppState;
  /** Clona el estado, aplica cambios y guarda. */
  mutate: (fn: (draft: AppState) => void) => void;
  reset: () => void;
  ctx: SplitContext;
}

const StoreCtx = createContext<Store | null>(null);

export function StoreProvider({ children }: { children: ReactNode }) {
  const [s, setS] = useState<AppState>(initial);
  const loaded = useRef(false);

  useEffect(() => {
    try {
      const raw = localStorage.getItem(KEY);
      if (raw) setS(JSON.parse(raw));
    } catch {}
    loaded.current = true;
  }, []);

  useEffect(() => {
    if (!loaded.current) return;
    try { localStorage.setItem(KEY, JSON.stringify(s)); } catch {}
  }, [s]);

  const mutate = useCallback((fn: (d: AppState) => void) => {
    setS((prev) => { const d = structuredClone(prev); fn(d); return d; });
  }, []);
  const reset = useCallback(() => {
    try { localStorage.removeItem(KEY); } catch {}
    setS(initial());
  }, []);

  const ctx = useMemo<SplitContext>(
    () => ({ plans: s.membershipPlans, insurers: s.insurers, insurersOn: s.clinic.insurersAddon, today: s.today }),
    [s.membershipPlans, s.insurers, s.clinic.insurersAddon, s.today],
  );

  return <StoreCtx.Provider value={{ s, mutate, reset, ctx }}>{children}</StoreCtx.Provider>;
}

export function useStore() {
  const v = useContext(StoreCtx);
  if (!v) throw new Error("useStore fuera de StoreProvider");
  return v;
}

/* ---------- selectores y acciones comunes ---------- */

export const nowHHMM = () => new Date().toTimeString().slice(0, 5);

export function pushFeed(d: AppState, text: string, kind: FeedItem["kind"] = "info") {
  d.feed.unshift({ at: nowHHMM(), text, kind });
}

export function findPatient(s: AppState, id: string) {
  return s.patients.find((p) => p.id === id);
}

export function currentDoctor(s: AppState) {
  return s.doctors.find((d) => d.id === s.doctorId) ?? s.doctors[0];
}

export function nextFolio(d: AppState) {
  d.folio += 1;
  return d.folio;
}

export function sponsorFor(s: AppState, slot: "wa" | "rec" | "portal") {
  return s.sponsors.find((x) => x.active && x.slots[slot]) ?? null;
}

export function insurerDue(s: AppState, ctx: SplitContext) {
  return s.claims
    .filter((c) => c.step < 5)
    .reduce((sum, c) => {
      const p = findPatient(s, c.patientId);
      const b = p?.budgets.find((x) => x.id === c.budgetId);
      return sum + (p && b ? budgetSplit(p, b, ctx).insPay : 0);
    }, 0);
}

export { patientBalance, budgetSplit, membershipDiscount };

export const uid = () => Math.random().toString(36).slice(2, 9);
