import type { SerializedInventoryPolicy } from "@/lib/inventoryRl/types";

const LATEST_POLICY_KEY = "inventory_rl_latest_policy_v1";
const POLICY_HISTORY_KEY = "inventory_rl_policy_history_v1";
const MAX_POLICY_HISTORY = 20;

export type StoredInventoryPolicy = {
  policy: SerializedInventoryPolicy;
  savedAt: string;
  source: "advanced" | "poc";
  samples?: number;
  note?: string;
};

function hasWindow(): boolean {
  return typeof window !== "undefined" && !!window.localStorage;
}

function normalizeStoredPolicy(parsed: unknown): StoredInventoryPolicy | null {
  if (!parsed || typeof parsed !== "object") return null;
  const record = parsed as Partial<StoredInventoryPolicy>;
  const policy = record.policy;
  if (!policy || typeof policy !== "object") return null;
  if (!Array.isArray(policy.skuIds)) return null;
  if (typeof policy.stateDim !== "number" || typeof policy.actionDim !== "number") return null;
  if (policy.modelType === "mlp_tfjs") {
    if (!Array.isArray(policy.weights)) return null;
  } else if (policy.modelType === "bcq_tfjs") {
    if (!Array.isArray(policy.actionBank)) return null;
    if (!Array.isArray(policy.qWeights)) return null;
    if (!Array.isArray(policy.behaviorWeights)) return null;
  } else if (policy.modelType === "ddpg_tfjs") {
    if (!Array.isArray(policy.actorHidden)) return null;
    if (!Array.isArray(policy.actorWeights)) return null;
  } else {
    return null;
  }
  return {
    policy: policy as SerializedInventoryPolicy,
    savedAt: typeof record.savedAt === "string" ? record.savedAt : new Date(0).toISOString(),
    source: record.source === "poc" ? "poc" : "advanced",
    samples: typeof record.samples === "number" ? record.samples : undefined,
    note: typeof record.note === "string" ? record.note : undefined,
  };
}

function dedupeHistory(records: StoredInventoryPolicy[]): StoredInventoryPolicy[] {
  const seen = new Set<string>();
  const out: StoredInventoryPolicy[] = [];
  for (const record of records) {
    const policy = record.policy;
    const key = [
      record.savedAt,
      record.source,
      policy.modelType,
      policy.createdAt,
      policy.stateDim,
      policy.actionDim,
      policy.skuIds.join(","),
    ].join("|");
    if (seen.has(key)) continue;
    seen.add(key);
    out.push(record);
    if (out.length >= MAX_POLICY_HISTORY) break;
  }
  return out;
}

export function saveLatestInventoryPolicy(record: Omit<StoredInventoryPolicy, "savedAt">): void {
  if (!hasWindow()) return;
  const payload: StoredInventoryPolicy = {
    ...record,
    savedAt: new Date().toISOString(),
  };
  try {
    window.localStorage.setItem(LATEST_POLICY_KEY, JSON.stringify(payload));
    const existing = loadInventoryPolicyHistory();
    const merged = dedupeHistory([payload, ...existing]).sort(
      (a, b) => new Date(b.savedAt).getTime() - new Date(a.savedAt).getTime()
    );
    window.localStorage.setItem(POLICY_HISTORY_KEY, JSON.stringify(merged));
  } catch {
    // Ignore storage failures and keep UI functional.
  }
}

export function loadLatestInventoryPolicy(): StoredInventoryPolicy | null {
  if (!hasWindow()) return null;
  try {
    const raw = window.localStorage.getItem(LATEST_POLICY_KEY);
    if (!raw) return null;
    return normalizeStoredPolicy(JSON.parse(raw));
  } catch {
    return null;
  }
}

export function loadInventoryPolicyHistory(): StoredInventoryPolicy[] {
  if (!hasWindow()) return [];
  try {
    const raw = window.localStorage.getItem(POLICY_HISTORY_KEY);
    if (!raw) return [];
    const parsed = JSON.parse(raw);
    if (!Array.isArray(parsed)) return [];
    return dedupeHistory(parsed.map((entry) => normalizeStoredPolicy(entry)).filter((x): x is StoredInventoryPolicy => !!x));
  } catch {
    return [];
  }
}
