import type { Server } from "bun";
import type {
  ProviderHostSshErrorMessage,
} from "../../shared/src/index";
import { ctx, sql, config, logger } from "./context";
import type { ProviderSocket, WsData } from "./types";
import { jsonResponse, wsSendJson } from "./http";

function safeSessionId(): string {
  return `ssh_${Date.now()}_${Math.random().toString(16).slice(2)}`;
}

function sshClientFor(sessionId: string): ProviderSocket | null {
  return ctx.activeSshClients.get(sessionId) ?? null;
}

function providerForSsh(providerId: string): ProviderSocket | null {
  return ctx.activeProviders.get(providerId) ?? null;
}

export function closeSshClient(sessionId: string, code = 1000, reason = "ssh session closed"): void {
  const client = sshClientFor(sessionId);
  ctx.activeSshClients.delete(sessionId);
  if (client !== null && client.readyState === WebSocket.OPEN) client.close(code, reason);
}

export function forwardSshProviderMessage(
  message: ProviderHostSshErrorMessage,
): void {
  const client = sshClientFor(message.sessionId);
  if (client === null) {
    logger("warn", "ssh_client_missing", { providerId: message.providerId, sessionId: message.sessionId, type: message.type });
    return;
  }
  wsSendJson(client, { type: "ssh.error", message: message.message });
  setTimeout(() => closeSshClient(message.sessionId, 1011, "ssh session error"), 50);
}

function numberFromUnknown(value: unknown, fallback: number, min: number, max: number): number {
  const parsed = typeof value === "number" ? value : typeof value === "string" ? Number(value) : fallback;
  if (!Number.isFinite(parsed)) return fallback;
  return Math.max(min, Math.min(max, Math.floor(parsed)));
}

async function providerSupports(providerId: string, capability: string): Promise<boolean> {
  if (!ctx.dbReady) return false;
  const rows = await sql()<Array<{ labels: unknown }>>`
    SELECT labels
    FROM unidesk_nodes
    WHERE provider_id = ${providerId}
    LIMIT 1
  `;
  const labels = rows[0]?.labels;
  if (typeof labels !== "object" || labels === null || Array.isArray(labels)) return false;
  const capabilities = (labels as Record<string, unknown>).unideskCapabilities;
  return Array.isArray(capabilities) ? capabilities.filter((item): item is string => typeof item === "string").includes(capability) : false;
}

export async function handleSshClientMessage(ws: ProviderSocket, raw: string | Buffer): Promise<void> {
  const text = typeof raw === "string" ? raw : raw.toString("utf8");
  const message = JSON.parse(text) as { type?: unknown; providerId?: unknown; cwd?: unknown; command?: unknown; tty?: unknown; data?: unknown; encoding?: unknown; cols?: unknown; rows?: unknown };
  if (message.type === "ssh.open") {
    const providerId = typeof message.providerId === "string" ? message.providerId : "";
    if (providerId.length === 0) {
      wsSendJson(ws, { type: "ssh.error", message: "providerId is required" });
      return;
    }
    const provider = providerForSsh(providerId);
    if (provider === null) {
      wsSendJson(ws, { type: "ssh.error", message: `provider is not online: ${providerId}` });
      return;
    }
    if (!(await providerSupports(providerId, "host.ssh"))) {
      wsSendJson(ws, { type: "ssh.error", message: `provider does not declare host.ssh capability: ${providerId}` });
      return;
    }
    if (!(await providerSupports(providerId, "host.ssh.tcp-pool"))) {
      wsSendJson(ws, {
        type: "ssh.error",
        message: `provider gateway must be upgraded before host.ssh can run: ${providerId} does not declare host.ssh.tcp-pool`,
        failureKind: "provider-gateway-upgrade-required",
        providerId,
        requiredCapability: "host.ssh.tcp-pool",
      });
      return;
    }
    wsSendJson(ws, {
      type: "ssh.error",
      message: "legacy TypeScript backend-core does not implement host.ssh.tcp-pool data channels; use the Rust backend-core",
      failureKind: "backend-core-upgrade-required",
      providerId,
      requiredCapability: "host.ssh.tcp-pool",
    });
    return;
  }

  wsSendJson(ws, { type: "ssh.error", message: `unsupported ssh client message: ${String(message.type)}` });
}

export async function sshRoute(req: Request, server: Server<WsData>): Promise<Response | undefined> {
  const url = new URL(req.url);
  const token = url.searchParams.get("token") ?? req.headers.get("x-provider-token");
  if (token !== config().providerToken) return jsonResponse({ ok: false, error: "invalid ssh bridge token" }, 401);
  const upgraded = server.upgrade(req, { data: { channel: "ssh" } satisfies WsData });
  return upgraded ? undefined : jsonResponse({ ok: false, error: "websocket upgrade failed" }, 400);
}
