/*
 * SPEC: PJ2026-010405 云端控制台。
 * Implementation reference: draft-2026-07-13-p0-cloud-console。
 * Responsibility: 聚合当前用户可见的项目、HWPOD 与账务事实，输出有界 typed Dashboard read model。
 */
import { discoverHwpodSpecs } from "./hwpod-spec-discovery.ts";
import { buildHwpodTopologyReadModel } from "./hwpod-topology-read-model.ts";
import { getHeader, sendJson } from "./server-http-utils.ts";

export const DASHBOARD_SUMMARY_CONTRACT_VERSION = "cloud-dashboard-summary-v1";

export type DashboardSourceState = "ready" | "partial" | "stale" | "unavailable" | "restricted";

export interface DashboardSourceStatus {
  id: "work" | "hwpod" | "billing";
  label: string;
  authority: string;
  state: DashboardSourceState;
  observedAt: string | null;
  reason: string | null;
  href: string;
}

export interface DashboardIssue {
  id: string;
  domain: DashboardSourceStatus["id"];
  severity: "warning" | "error";
  code: string;
  title: string;
  summary: string;
  count: number | null;
  action: { label: string; href: string };
}

export interface DashboardTaskContinuation {
  taskRef: string;
  taskId: string;
  title: string;
  status: string;
  projectId: string | null;
  sourceId: string;
  fileRef: string;
  updatedAt: string | null;
  href: string;
}

export interface DashboardSummaryResponse {
  ok: true;
  status: "ready" | "partial" | "stale";
  contractVersion: typeof DASHBOARD_SUMMARY_CONTRACT_VERSION;
  route: "/v1/dashboard/summary";
  observedAt: string;
  actor: { id: string; displayName: string; role: string };
  sources: DashboardSourceStatus[];
  work: {
    state: DashboardSourceState;
    authority: "hwlab-project-management";
    observedAt: string | null;
    projectCount: number | null;
    projects: Array<{ projectId: string; title: string; status: string; href: string }>;
    taskCounts: { open: number | null; inProgress: number | null; blocked: number | null };
    continuations: DashboardTaskContinuation[];
  };
  hwpod: {
    state: DashboardSourceState;
    authority: "cloud-api-hwpod-domain";
    observedAt: string | null;
    nodeCount: number | null;
    onlineNodeCount: number | null;
    offlineNodeCount: number | null;
    deviceCount: number | null;
    availableDeviceCount: number | null;
    busyDeviceCount: number | null;
    capabilityMismatchCount: number | null;
    invalidSpecCount: number | null;
  };
  billing: {
    state: DashboardSourceState;
    authority: "hwlab-user-billing";
    observedAt: string | null;
    plan: { id: string | null; displayName: string | null; status: string | null } | null;
    credits: { balance: number | null; reserved: number | null; available: number | null } | null;
    entitlementCount: number | null;
    activeReservationCount: number | null;
  };
  issues: DashboardIssue[];
  valuesRedacted: true;
}

interface DashboardAuth {
  actor?: Record<string, unknown> | null;
  authMethod?: string | null;
  userBilling?: { active?: boolean; token?: string } | null;
  apiKey?: unknown;
  session?: unknown;
}

export async function handleDashboardSummaryHttp(request: any, response: any, options: any = {}) {
  if (request.method !== "GET") {
    sendJson(response, 405, {
      ok: false,
      contractVersion: DASHBOARD_SUMMARY_CONTRACT_VERSION,
      error: { code: "method_not_allowed", message: "Dashboard summary only supports GET" },
      valuesRedacted: true
    });
    return;
  }

  const auth = await options.accessController.authenticate(request, { required: true });
  if (!auth.ok) {
    sendJson(response, auth.status, auth);
    return;
  }

  const observedAt = dashboardNow(options);
  const [work, hwpod, billing] = await Promise.all([
    loadWorkSummary(request, auth, options, observedAt),
    loadHwpodSummary(auth, options, observedAt),
    loadBillingSummary(auth, options, observedAt)
  ]);
  const sources = [sourceStatus("work", "项目与任务", "hwlab-project-management", work, "/projects"), sourceStatus("hwpod", "HWPOD", "cloud-api-hwpod-domain", hwpod, "/hwpods/devices"), sourceStatus("billing", "额度与 Plan", "hwlab-user-billing", billing, "/usage")];
  const payload: DashboardSummaryResponse = {
    ok: true,
    status: aggregateStatus(sources),
    contractVersion: DASHBOARD_SUMMARY_CONTRACT_VERSION,
    route: "/v1/dashboard/summary",
    observedAt,
    actor: publicActor(auth.actor),
    sources,
    work: publicWorkSummary(work),
    hwpod: publicHwpodSummary(hwpod),
    billing: publicBillingSummary(billing),
    issues: dashboardIssues(work, hwpod, billing),
    valuesRedacted: true
  };
  sendJson(response, 200, payload);
}

async function loadWorkSummary(request: any, auth: DashboardAuth, options: any, observedAt: string) {
  if (!navAllowed(options.accessController, auth.actor, "project.mdtodo")) return restrictedSection(observedAt, "当前身份无项目管理访问权限");
  const baseUrl = text(options.env?.HWLAB_PROJECT_MANAGEMENT_URL);
  if (!baseUrl) return unavailableSection(observedAt, "project_management_service_unconfigured");
  const fetchImpl = options.fetchImpl ?? fetch;
  const requests = [
    ["projects", "/v1/project-management/projects"],
    ["open", "/v1/project-management/mdtodo/tasks?status=open&limit=6&offset=0"],
    ["inProgress", "/v1/project-management/mdtodo/tasks?status=in_progress&limit=6&offset=0"],
    ["blocked", "/v1/project-management/mdtodo/tasks?status=blocked&limit=6&offset=0"]
  ] as const;
  const settled = await Promise.all(requests.map(async ([id, pathname]) => {
    try {
      return [id, { ok: true, body: await projectManagementJson(request, auth, fetchImpl, baseUrl, pathname, options) }] as const;
    } catch (error) {
      return [id, { ok: false, reason: safeReason(error) }] as const;
    }
  }));
  const results = Object.fromEntries(settled) as Record<string, { ok: boolean; body?: Record<string, unknown>; reason?: string }>;
  const failures = requests.map(([id]) => results[id]).filter((item) => !item?.ok);
  const projectsPayload = results.projects?.body;
  const projects = array(projectsPayload?.projects).map(projectSummary).filter(Boolean).slice(0, 6);
  const inProgressTasks = array(results.inProgress?.body?.tasks);
  const openTasks = array(results.open?.body?.tasks);
  const state = failures.length > 0 ? "partial" : strongestPayloadState(settled.map(([, result]) => result.body));
  return {
    state,
    observedAt: newestObservedAt(settled.map(([, result]) => result.body), observedAt),
    reason: failures.length ? `${failures.length} 个 Project Management 查询未完成：${failures.map((item) => item.reason).filter(Boolean).join("；")}` : null,
    projectCount: results.projects?.ok ? array(projectsPayload?.projects).length : null,
    projects,
    taskCounts: {
      open: taskTotal(results.open),
      inProgress: taskTotal(results.inProgress),
      blocked: taskTotal(results.blocked)
    },
    continuations: [...inProgressTasks, ...openTasks].map(taskContinuation).filter(Boolean).slice(0, 6)
  };
}

async function projectManagementJson(request: any, auth: DashboardAuth, fetchImpl: typeof fetch, baseUrl: string, pathname: string, options: any) {
  const url = new URL(pathname, baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`);
  const headers = new Headers({ accept: "application/json", "x-hwlab-bridge-service": "hwlab-cloud-api" });
  for (const name of ["x-request-id", "traceparent", "tracestate"]) {
    const value = getHeader(request, name);
    if (value) headers.set(name, value);
  }
  if (auth.actor?.id) headers.set("x-hwlab-actor-id", text(auth.actor.id));
  if (auth.actor?.role) headers.set("x-hwlab-actor-role", text(auth.actor.role));
  headers.set("x-hwlab-auth-method", text(auth.authMethod) || (auth.apiKey ? "api-key" : auth.session ? "web-session" : "unknown"));
  const timeoutMs = positiveInteger(options.env?.HWLAB_PROJECT_MANAGEMENT_PROXY_TIMEOUT_MS, 30000);
  const upstream = await fetchImpl(url, { method: "GET", headers, signal: AbortSignal.timeout(timeoutMs) });
  const body = await upstream.json().catch(() => null);
  if (!upstream.ok || !isRecord(body) || body.ok === false) {
    const error = isRecord(body?.error) ? body.error : {};
    throw new Error(text(error.code) || text(error.message) || `project_management_http_${upstream.status}`);
  }
  return body;
}

async function loadHwpodSummary(auth: DashboardAuth, options: any, observedAt: string) {
  if (!navAllowed(options.accessController, auth.actor, "admin.hwpodGroups")) return restrictedSection(observedAt, "当前身份无 HWPOD topology 访问权限");
  try {
    const discover = options.dashboardDiscoverHwpodSpecs ?? discoverHwpodSpecs;
    const specs = await discover(options);
    const registrySnapshot = options.hwpodNodeWsRegistry?.describe?.() ?? {};
    const topology = buildHwpodTopologyReadModel(specs, registrySnapshot, { observedAt, resource: "node", limit: 1 });
    return {
      state: payloadState(topology.status),
      observedAt: text(topology.observedAt) || observedAt,
      reason: topology.status === "partial" ? `${number(topology.summary?.invalidSpecCount)} 个 HWPOD spec 无法解析` : null,
      ...topology.summary
    };
  } catch (error) {
    return unavailableSection(observedAt, safeReason(error));
  }
}

async function loadBillingSummary(auth: DashboardAuth, options: any, observedAt: string) {
  if (!navAllowed(options.accessController, auth.actor, "user.usage")) return restrictedSection(observedAt, "当前身份无用户账务访问权限");
  const client = options.userBillingClient ?? options.accessController?.userBilling ?? null;
  const token = text(auth.userBilling?.token);
  if (auth.userBilling?.active !== true || !token) return unavailableSection(observedAt, "user_billing_auth_unavailable");
  if (!client?.configured || typeof client.billingSummary !== "function") return unavailableSection(observedAt, "user_billing_not_configured");
  try {
    const result = await client.billingSummary(token, { limit: 5 });
    if (!result?.ok || !isRecord(result.body)) return unavailableSection(observedAt, text(result?.error?.code) || `user_billing_http_${number(result?.status) || 502}`);
    const body = result.body;
    const plan = isRecord(body.plan) ? body.plan : null;
    const credits = isRecord(body.credits) ? body.credits : null;
    const reservations = isRecord(body.reservations) ? body.reservations : null;
    return {
      state: payloadState(body.status),
      observedAt: text(body.observedAt) || observedAt,
      reason: null,
      plan: plan ? { id: nullableText(plan.id ?? body.planId), displayName: nullableText(plan.displayName), status: nullableText(plan.status) } : body.planId ? { id: nullableText(body.planId), displayName: null, status: null } : null,
      credits: credits ? { balance: nullableNumber(credits.balance), reserved: nullableNumber(credits.reserved), available: nullableNumber(credits.available) } : null,
      entitlementCount: Array.isArray(body.entitlements) ? body.entitlements.length : null,
      activeReservationCount: reservations ? nullableNumber(reservations.activeCount) : null
    };
  } catch (error) {
    return unavailableSection(observedAt, safeReason(error));
  }
}

function publicWorkSummary(value: any): DashboardSummaryResponse["work"] {
  return {
    state: value.state,
    authority: "hwlab-project-management",
    observedAt: value.observedAt ?? null,
    projectCount: value.projectCount ?? null,
    projects: value.projects ?? [],
    taskCounts: value.taskCounts ?? { open: null, inProgress: null, blocked: null },
    continuations: value.continuations ?? []
  };
}

function publicHwpodSummary(value: any): DashboardSummaryResponse["hwpod"] {
  return {
    state: value.state,
    authority: "cloud-api-hwpod-domain",
    observedAt: value.observedAt ?? null,
    nodeCount: nullableNumber(value.nodeCount),
    onlineNodeCount: nullableNumber(value.onlineNodeCount),
    offlineNodeCount: nullableNumber(value.offlineNodeCount),
    deviceCount: nullableNumber(value.deviceCount),
    availableDeviceCount: nullableNumber(value.availableDeviceCount),
    busyDeviceCount: nullableNumber(value.busyDeviceCount),
    capabilityMismatchCount: nullableNumber(value.capabilityMismatchCount),
    invalidSpecCount: nullableNumber(value.invalidSpecCount)
  };
}

function publicBillingSummary(value: any): DashboardSummaryResponse["billing"] {
  return {
    state: value.state,
    authority: "hwlab-user-billing",
    observedAt: value.observedAt ?? null,
    plan: value.plan ?? null,
    credits: value.credits ?? null,
    entitlementCount: value.entitlementCount ?? null,
    activeReservationCount: value.activeReservationCount ?? null
  };
}

function dashboardIssues(work: any, hwpod: any, billing: any): DashboardIssue[] {
  const issues: DashboardIssue[] = [];
  dependencyIssue(issues, "work", work, "项目与任务", "/projects");
  dependencyIssue(issues, "hwpod", hwpod, "HWPOD", "/hwpods/devices");
  dependencyIssue(issues, "billing", billing, "额度与 Plan", "/usage");
  if (number(work.taskCounts?.blocked) > 0) issues.push(issue("work-blocked-tasks", "work", "warning", "mdtodo_tasks_blocked", "存在阻塞任务", `${number(work.taskCounts.blocked)} 个 MDTODO 任务由 Project Management 标记为 blocked。`, number(work.taskCounts.blocked), "查看阻塞任务", "/projects/mdtodo?filter=blocked"));
  if (number(hwpod.offlineNodeCount) > 0) issues.push(issue("hwpod-offline-nodes", "hwpod", "error", "hwpod_node_offline", "HWPOD Node 离线", `${number(hwpod.offlineNodeCount)} 个已声明 Node 当前未连接。`, number(hwpod.offlineNodeCount), "查看 Node", "/hwpods/nodes?status=offline"));
  if (number(hwpod.capabilityMismatchCount) > 0) issues.push(issue("hwpod-capability-mismatch", "hwpod", "error", "hwpod_capability_mismatch", "HWPOD 能力不匹配", `${number(hwpod.capabilityMismatchCount)} 个设备缺少声明能力。`, number(hwpod.capabilityMismatchCount), "查看设备", "/hwpods/devices?status=capability-mismatch"));
  if (number(hwpod.invalidSpecCount) > 0) issues.push(issue("hwpod-invalid-specs", "hwpod", "error", "invalid_hwpod_spec", "HWPOD spec 无效", `${number(hwpod.invalidSpecCount)} 个 spec 无法进入 topology。`, number(hwpod.invalidSpecCount), "查看设备", "/hwpods/devices"));
  const planStatus = text(billing.plan?.status).toLowerCase();
  if (["blocked", "disabled", "inactive", "past_due", "suspended"].includes(planStatus)) issues.push(issue("billing-plan-status", "billing", "error", "billing_plan_not_active", "Plan 状态异常", `user-billing 返回 plan status=${planStatus}。`, null, "查看账务", "/billing"));
  return dedupeIssues(issues).slice(0, 10);
}

function dependencyIssue(target: DashboardIssue[], domain: DashboardIssue["domain"], value: any, label: string, href: string) {
  if (value.state === "unavailable") target.push(issue(`${domain}-unavailable`, domain, "error", `${domain}_summary_unavailable`, `${label}摘要不可用`, value.reason || `${label} authority 未返回摘要。`, null, `打开${label}`, href));
  if (value.state === "stale") target.push(issue(`${domain}-stale`, domain, "warning", `${domain}_summary_stale`, `${label}摘要已过期`, value.reason || `${label} authority 明确返回 stale。`, null, `打开${label}`, href));
  if (value.state === "partial" && value.reason) target.push(issue(`${domain}-partial`, domain, "warning", `${domain}_summary_partial`, `${label}摘要不完整`, value.reason, null, `打开${label}`, href));
}

function issue(id: string, domain: DashboardIssue["domain"], severity: DashboardIssue["severity"], code: string, title: string, summary: string, count: number | null, label: string, href: string): DashboardIssue {
  return { id, domain, severity, code, title, summary, count, action: { label, href } };
}

function sourceStatus(id: DashboardSourceStatus["id"], label: string, authority: string, value: any, href: string): DashboardSourceStatus {
  return { id, label, authority, state: value.state, observedAt: value.observedAt ?? null, reason: value.reason ?? null, href };
}

function aggregateStatus(sources: DashboardSourceStatus[]): DashboardSummaryResponse["status"] {
  const states = sources.filter((source) => source.state !== "restricted").map((source) => source.state);
  if (states.some((state) => state === "partial" || state === "unavailable")) return "partial";
  if (states.some((state) => state === "stale")) return "stale";
  return "ready";
}

function strongestPayloadState(values: Array<Record<string, unknown> | undefined>) {
  const states = values.filter(Boolean).map((value) => payloadState(value?.status));
  if (states.includes("partial")) return "partial";
  if (states.includes("stale")) return "stale";
  return "ready";
}

function payloadState(value: unknown): DashboardSourceState {
  const state = text(value).toLowerCase();
  if (state === "stale") return "stale";
  if (["partial", "degraded"].includes(state)) return "partial";
  return "ready";
}

function projectSummary(value: unknown): { projectId: string; title: string; status: string; href: string } | null {
  if (!isRecord(value)) return null;
  const projectId = text(value.projectId);
  if (!projectId) return null;
  return { projectId, title: text(value.name ?? value.title) || projectId, status: text(value.status) || "unknown", href: `/projects/${encodeURIComponent(projectId)}` };
}

function taskContinuation(value: unknown): DashboardTaskContinuation | null {
  if (!isRecord(value)) return null;
  const taskRef = text(value.taskRef);
  const taskId = text(value.taskId);
  const sourceId = text(value.sourceId);
  const fileRef = text(value.fileRef);
  if (!taskRef || !taskId || !sourceId || !fileRef) return null;
  return {
    taskRef,
    taskId,
    title: text(value.title) || taskId,
    status: text(value.status) || "unknown",
    projectId: nullableText(value.projectId),
    sourceId,
    fileRef,
    updatedAt: nullableText(value.updatedAt),
    href: `/projects/mdtodo/sources/${encodeURIComponent(sourceId)}/files/${encodeURIComponent(fileRef)}/tasks/${encodeURIComponent(taskId)}`
  };
}

function taskTotal(result: { ok: boolean; body?: Record<string, unknown> } | undefined): number | null {
  if (!result?.ok || !isRecord(result.body?.page)) return null;
  return nullableNumber(result.body.page.total);
}

function newestObservedAt(values: Array<Record<string, unknown> | undefined>, fallback: string) {
  const timestamps = values.map((value) => text(value?.observedAt)).filter(Boolean).sort();
  return timestamps.at(-1) || fallback;
}

function restrictedSection(observedAt: string, reason: string) {
  return { state: "restricted" as const, observedAt, reason };
}

function unavailableSection(observedAt: string, reason: string) {
  return { state: "unavailable" as const, observedAt, reason };
}

function publicActor(actor: Record<string, unknown> | null | undefined) {
  return { id: text(actor?.id), displayName: text(actor?.displayName ?? actor?.username ?? actor?.name), role: text(actor?.role) || "member" };
}

function navAllowed(accessController: any, actor: unknown, navId: string) {
  return typeof accessController?.navAccessAllowed !== "function" || accessController.navAccessAllowed(actor, navId) === true;
}

function dashboardNow(options: any) {
  const value = typeof options.dashboardNow === "function" ? options.dashboardNow() : new Date().toISOString();
  return text(value) || new Date().toISOString();
}

function safeReason(error: unknown) {
  return text((error as any)?.code ?? (error as any)?.message ?? error)
    .replace(/\b(Bearer|Basic)\s+\S+/giu, "$1 [REDACTED]")
    .replace(/\b(api[_-]?key|token|secret|password|authorization)\s*[:=]\s*\S+/giu, "$1=[REDACTED]")
    .slice(0, 240) || "dependency_request_failed";
}

function dedupeIssues(values: DashboardIssue[]) {
  const seen = new Set<string>();
  return values.filter((value) => !seen.has(value.id) && Boolean(seen.add(value.id)));
}

function nullableText(value: unknown) {
  return text(value) || null;
}

function nullableNumber(value: unknown): number | null {
  if (value === null || value === undefined || value === "") return null;
  const parsed = Number(value);
  return Number.isFinite(parsed) ? parsed : null;
}

function number(value: unknown) {
  return nullableNumber(value) ?? 0;
}

function positiveInteger(value: unknown, fallback: number) {
  const parsed = Number(value);
  return Number.isInteger(parsed) && parsed > 0 ? parsed : fallback;
}

function array(value: unknown): unknown[] {
  return Array.isArray(value) ? value : [];
}

function isRecord(value: unknown): value is Record<string, any> {
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
}

function text(value: unknown) {
  return typeof value === "string" && value.trim() ? value.trim() : "";
}
