export type ReleaseBadge =
  | "recommended"
  | "previous"
  | "experimental"
  | "deprecated-baseline";

export interface NexusRelease {
  build: number;
  version: string;
  publishedAt: string;
  packageUrl: string;
  sha256Url: string;
  sha256: string;
  sizeBytes: number;
  installerUrl: string;
  installerSha256: string;
  installerSizeBytes: number;
  notes: string[];
  releaseNotes: string[];
  manifestPath: string;
  badge: ReleaseBadge;
}

export interface LatestManifest {
  product: string;
  channel: string;
  version: string;
  build: number;
  publishedAt: string;
  sha256: string;
  sizeBytes: number;
  packageUrl: string;
  installerUrl: string;
  installerSha256: string;
  installerSizeBytes: number;
  notes: string[];
}

export interface ReleasesCatalog {
  product: string;
  channel: string;
  generatedAt: string;
  latestJson: string;
  releases: NexusRelease[];
}

const BASE = "https://nexus.ninjakernen.info";

/** Static fallback — merged with live releases.json; artifact paths preserved for update client. */
export const FALLBACK_RELEASES: NexusRelease[] = [
  {
    build: 91,
    version: "0.1.0-installer3",
    publishedAt: "2026-06-06T06:51:29Z",
    packageUrl: `${BASE}/downloads/releases/0.1.0-installer3/nexus-shell-poc.zip`,
    sha256Url: `${BASE}/downloads/releases/0.1.0-installer3/sha256.txt`,
    sha256: "74cd86501094674eef80dd46deb23f41c671f44bb27cd33438ebe15d77c9d19e",
    sizeBytes: 15352684,
    installerUrl: `${BASE}/downloads/NexusSetup.exe`,
    installerSha256: "3a8ce20d67918be4181d5082f35e2c53277928cdcf238d2d00ea5804f366bdb7",
    installerSizeBytes: 90170532,
    notes: [
      "Fix Identity API startup, SQLite data path, PC name, role loading and first-run enrollment persistence.",
      "Admin elevation, repair/fresh cleanup, 19-step install timeline, 67 unit tests.",
    ],
    releaseNotes: [
      "Fix Identity API startup, SQLite data path, PC name, role loading and first-run enrollment persistence.",
    ],
    manifestPath: "/downloads/releases/0.1.0-installer3/manifest.json",
    badge: "recommended",
  },
  {
    build: 90,
    version: "0.1.0-installer2",
    publishedAt: "2026-06-06T06:17:13Z",
    packageUrl: `${BASE}/downloads/releases/0.1.0-installer2/nexus-shell-poc.zip`,
    sha256Url: `${BASE}/downloads/releases/0.1.0-installer2/sha256.txt`,
    sha256: "397c465c71b730a335ade52137b4567deb647ad29a7d1eb1e305d030baca94d6",
    sizeBytes: 15351967,
    installerUrl: `${BASE}/downloads/NexusSetup.exe`,
    installerSha256: "77126e939eaf741b3e883ae7cb0343eb50f9ddc1e0f29fa6e30b755b31f761c7",
    installerSizeBytes: 90121892,
    notes: [
      "Fix first-run setup input and organization selection in installer/onboarding.",
      "Ikke valid baseline — brug build 91.",
    ],
    releaseNotes: [
      "Fix first-run setup input and organization selection in installer/onboarding.",
    ],
    manifestPath: "/downloads/releases/0.1.0-installer2/manifest.json",
    badge: "deprecated-baseline",
  },
  {
    build: 89,
    version: "0.1.0-installer1",
    publishedAt: "2026-06-05T22:10:16Z",
    packageUrl: `${BASE}/downloads/releases/0.1.0-installer1/nexus-shell-poc.zip`,
    sha256Url: `${BASE}/downloads/releases/0.1.0-installer1/sha256.txt`,
    sha256: "eb2b1eb363e1299191ec0413e805e4c57900951c3e756a0aae462b6b6ff99601",
    sizeBytes: 15350602,
    installerUrl: `${BASE}/downloads/NexusSetup.exe`,
    installerSha256: "c9f1ddc25b3ca2e75811bfd9c075ab3af8f3fd4202cef4de751b49488cd1a31a",
    installerSizeBytes: 90102436,
    notes: [
      "Installer/update hardening: fil-lås preflight, rollback, queue timeout, data/ separation.",
    ],
    releaseNotes: [
      "Installer/update hardening build 89: fil-lås preflight, rollback, queue timeout.",
    ],
    manifestPath: "/downloads/releases/0.1.0-installer1/manifest.json",
    badge: "previous",
  },
  {
    build: 88,
    version: "0.1.0-identity3",
    publishedAt: "2026-06-05T18:00:00Z",
    packageUrl: `${BASE}/downloads/releases/0.1.0-identity3/nexus-shell-poc.zip`,
    sha256Url: `${BASE}/downloads/releases/0.1.0-identity3/sha256.txt`,
    sha256: "233ab047ac03775d0ba9932d733516fee25148af220022c74d1f8b029a286dff",
    sizeBytes: 15350000,
    installerUrl: `${BASE}/downloads/NexusSetup.exe`,
    installerSha256: "",
    installerSizeBytes: 0,
    notes: ["Auto-update readiness: manifest schema, UpdateService flow, CDN smoke."],
    releaseNotes: ["Auto-update readiness build 88."],
    manifestPath: "/downloads/releases/0.1.0-identity3/manifest.json",
    badge: "previous",
  },
  {
    build: 87,
    version: "0.1.0-identity2",
    publishedAt: "2026-06-05T12:00:00Z",
    packageUrl: `${BASE}/downloads/releases/0.1.0-identity2/nexus-shell-poc.zip`,
    sha256Url: `${BASE}/downloads/releases/0.1.0-identity2/sha256.txt`,
    sha256: "",
    sizeBytes: 0,
    installerUrl: `${BASE}/downloads/NexusSetup.exe`,
    installerSha256: "",
    installerSizeBytes: 0,
    notes: [
      "Platform wave 2 release-lock: Identity, Store, policy, remote foundation POC, installer v2.",
    ],
    releaseNotes: ["Platform foundation build 87."],
    manifestPath: "/downloads/releases/0.1.0-identity2/manifest.json",
    badge: "previous",
  },
];

function badgeForBuild(build: number): ReleaseBadge {
  if (build === 91) return "recommended";
  if (build === 90) return "deprecated-baseline";
  if (build >= 87) return "previous";
  return "experimental";
}

function mergeRelease(raw: Partial<NexusRelease> & { build: number; version: string }): NexusRelease {
  const fallback = FALLBACK_RELEASES.find((r) => r.build === raw.build);
  return {
    build: raw.build,
    version: raw.version,
    publishedAt: raw.publishedAt ?? fallback?.publishedAt ?? "",
    packageUrl: raw.packageUrl ?? fallback?.packageUrl ?? "",
    sha256Url: raw.sha256Url ?? fallback?.sha256Url ?? "",
    sha256: raw.sha256 ?? fallback?.sha256 ?? "",
    sizeBytes: raw.sizeBytes ?? fallback?.sizeBytes ?? 0,
    installerUrl: raw.installerUrl ?? fallback?.installerUrl ?? `${BASE}/downloads/NexusSetup.exe`,
    installerSha256: raw.installerSha256 ?? fallback?.installerSha256 ?? "",
    installerSizeBytes: raw.installerSizeBytes ?? fallback?.installerSizeBytes ?? 0,
    notes: raw.notes?.length ? raw.notes : (fallback?.notes ?? []),
    releaseNotes: raw.releaseNotes?.length
      ? raw.releaseNotes
      : (fallback?.releaseNotes ?? []),
    manifestPath: raw.manifestPath ?? fallback?.manifestPath ?? "",
    badge: fallback?.badge ?? badgeForBuild(raw.build),
  };
}

async function fetchJson<T>(url: string): Promise<T | null> {
  try {
    const res = await fetch(url, { cache: "force-cache" });
    if (!res.ok) return null;
    return (await res.json()) as T;
  } catch {
    return null;
  }
}

export async function getLatestManifest(): Promise<LatestManifest | null> {
  const data = await fetchJson<LatestManifest>(`${BASE}/downloads/latest.json`);
  return data;
}

export async function getReleasesCatalog(): Promise<ReleasesCatalog> {
  const remote = await fetchJson<{
    product?: string;
    channel?: string;
    generatedAt?: string;
    latestJson?: string;
    releases?: Array<Partial<NexusRelease> & { build: number; version: string }>;
  }>(`${BASE}/downloads/releases.json`);

  const byBuild = new Map<number, NexusRelease>();
  for (const fb of FALLBACK_RELEASES) {
    byBuild.set(fb.build, fb);
  }
  if (remote?.releases) {
    for (const r of remote.releases) {
      byBuild.set(r.build, mergeRelease(r));
    }
  }

  const releases = [...byBuild.values()].sort((a, b) => b.build - a.build);

  return {
    product: remote?.product ?? "Ninja Nexus",
    channel: remote?.channel ?? "poc",
    generatedAt: remote?.generatedAt ?? new Date().toISOString(),
    latestJson: remote?.latestJson ?? "/downloads/latest.json",
    releases,
  };
}

export function formatBytes(bytes: number): string {
  if (!bytes) return "—";
  return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
}

export function formatDate(iso: string): string {
  if (!iso) return "—";
  try {
    return new Date(iso).toLocaleString("da-DK", {
      dateStyle: "medium",
      timeStyle: "short",
    });
  } catch {
    return iso;
  }
}

export function truncateHash(hash: string): string {
  if (!hash || hash.length < 16) return hash || "—";
  return `${hash.slice(0, 12)}…${hash.slice(-8)}`;
}

export function toRelativePath(url: string): string {
  try {
    const u = new URL(url);
    return u.pathname;
  } catch {
    return url;
  }
}

export const BADGE_LABELS: Record<ReleaseBadge, string> = {
  recommended: "Anbefalet",
  previous: "Tidligere",
  experimental: "Eksperimentel",
  "deprecated-baseline": "Ikke baseline",
};
