import { access, realpath, stat } from "node:fs/promises";
import { constants } from "node:fs";
import { isAbsolute, relative, resolve } from "node:path";
import { z } from "zod";
import type { IncidentRunnerRequest } from "./incident-runner";

const SAFE_ID = /^[a-zA-Z0-9][a-zA-Z0-9-]{0,127}$/;
const TEARDOWN_GRACE_SECONDS = 30;

export interface IncidentAgentRequest extends IncidentRunnerRequest {
  priority: "P0" | "P1" | "P2" | "P3";
}

export interface IncidentLaunchReceipt {
  dispatchId: string;
  unit: string;
  acceptedAt: string;
}

export interface IncidentDispatchLauncher {
  launch(request: IncidentAgentRequest): Promise<IncidentLaunchReceipt>;
  isActive?(request: { incidentId: string; dispatchId: string }): Promise<boolean>;
  stop?(request: { incidentId: string; dispatchId: string }): Promise<void>;
}

export class IncidentLaunchError extends Error {
  constructor(public readonly stage: "provision" | "start", message: string) {
    super(message);
    this.name = "IncidentLaunchError";
  }
}

export interface IncidentLauncherDeps {
  workspaceRoot: string;
  sourceRepo: string;
  runnerEntry: string;
  bunExecutable?: string;
  now?: () => Date;
  exec?: (argv: string[]) => Promise<{ exitCode: number; stdout: string; stderr: string }>;
}

async function exec(argv: string[]): Promise<{ exitCode: number; stdout: string; stderr: string }> {
  const child = Bun.spawn(argv, { stdout: "pipe", stderr: "pipe" });
  const [exitCode, stdout, stderr] = await Promise.all([
    child.exited,
    new Response(child.stdout).text(),
    new Response(child.stderr).text(),
  ]);
  return { exitCode, stdout, stderr };
}

function assertId(value: string, label: string): void {
  if (!SAFE_ID.test(value)) throw new IncidentLaunchError("provision", `invalid ${label}`);
}

async function existingDirectory(path: string, label: string): Promise<string> {
  if (!isAbsolute(path)) throw new IncidentLaunchError("provision", `${label} must be absolute`);
  let canonical: string;
  try { canonical = await realpath(path); }
  catch { throw new IncidentLaunchError("provision", `${label} is unavailable`); }
  if (!(await stat(canonical)).isDirectory()) throw new IncidentLaunchError("provision", `${label} is not a directory`);
  return canonical;
}

async function validateReusableWorktree(
  execute: NonNullable<IncidentLauncherDeps["exec"]>,
  sourceRepo: string,
  workspace: string,
  dispatchId: string,
): Promise<boolean> {
  const [expected, listed, repository, status, identity] = await Promise.all([
    execute(["/usr/bin/git", "-C", sourceRepo, "rev-parse", "HEAD"]),
    execute(["/usr/bin/git", "-C", sourceRepo, "worktree", "list", "--porcelain"]),
    execute(["/usr/bin/git", "-C", workspace, "rev-parse", "--show-toplevel"]),
    execute(["/usr/bin/git", "-C", workspace, "status", "--porcelain=v1", "--untracked-files=all"]),
    execute(["/usr/bin/git", "-C", workspace, "config", "--worktree", "--get", "overdeck.dispatchId"]),
  ]);
  if ([expected, listed, repository, status, identity].some((result) => result.exitCode !== 0)) return false;
  if (await realpath(repository.stdout.trim()).catch(() => "") !== workspace) return false;
  if (status.stdout.length !== 0 || identity.stdout.trim() !== dispatchId) return false;
  const expectedHead = expected.stdout.trim();
  return listed.stdout.trim().split(/\n\n+/).some((record) => {
    const lines = record.split("\n");
    return lines.includes(`worktree ${workspace}`) && lines.includes(`HEAD ${expectedHead}`) && lines.includes("detached");
  });
}

async function validateActiveService(
  execute: NonNullable<IncidentLauncherDeps["exec"]>,
  unit: string,
  dispatchId: string,
  workspace: string,
  bun: string,
  runnerEntry: string,
  encodedRequest: string,
): Promise<boolean> {
  const shown = await execute(["/usr/bin/systemctl", "--user", "show", unit, "--property=Environment", "--property=ExecStart", "--property=WorkingDirectory"]);
  if (shown.exitCode !== 0) return false;
  const output = shown.stdout;
  return output.includes(`OVERDECK_DISPATCH_ID=${dispatchId}`)
    && output.includes(`WorkingDirectory=${workspace}`)
    && output.includes(bun)
    && output.includes(runnerEntry)
    && output.includes(encodedRequest);
}

export function createIncidentDispatchLauncher(deps: IncidentLauncherDeps): IncidentDispatchLauncher {
  const execute = deps.exec ?? exec;
  const now = deps.now ?? (() => new Date());
  const bun = deps.bunExecutable ?? process.execPath;

  return {
    async isActive(request): Promise<boolean> {
      assertId(request.incidentId, "incident id");
      assertId(request.dispatchId, "dispatch id");
      const unit = `overdeck-incident-${request.incidentId}.service`;
      const shown = await execute(["/usr/bin/systemctl", "--user", "show", unit, "--property=Environment", "--property=ActiveState"]);
      if (shown.exitCode !== 0) throw new IncidentLaunchError("start", shown.stderr.trim() || "service inspection failed");
      const activeState = /^ActiveState=(\S+)$/m.exec(shown.stdout)?.[1];
      if (!["active", "inactive", "failed"].includes(activeState ?? "")) throw new IncidentLaunchError("start", "service active state is indeterminate");
      const environment = /^Environment=(.*)$/m.exec(shown.stdout)?.[1] ?? "";
      const dispatchIds = environment.match(/(?:[^\s"=]+=[^\s"]*|"[^"]*")/g)?.map((entry) => entry.replace(/^"|"$/g, "")).filter((entry) => entry.startsWith("OVERDECK_DISPATCH_ID=")).map((entry) => entry.slice("OVERDECK_DISPATCH_ID=".length)) ?? [];
      if (dispatchIds.length !== 1 || dispatchIds[0] !== request.dispatchId) {
        throw new IncidentLaunchError("start", "service identity mismatch");
      }
      return activeState === "active";
    },
    async stop(request): Promise<void> {
      assertId(request.incidentId, "incident id");
      assertId(request.dispatchId, "dispatch id");
      const unit = `overdeck-incident-${request.incidentId}.service`;
      const shown = await execute(["/usr/bin/systemctl", "--user", "show", unit, "--property=Environment", "--property=ActiveState"]);
      if (shown.exitCode !== 0) throw new IncidentLaunchError("start", shown.stderr.trim() || "service inspection failed");
      const activeState = /^ActiveState=(\S+)$/m.exec(shown.stdout)?.[1];
      if (!["active", "inactive", "failed"].includes(activeState ?? "")) throw new IncidentLaunchError("start", "service active state is indeterminate");
      const environment = /^Environment=(.*)$/m.exec(shown.stdout)?.[1] ?? "";
      const dispatchIds = environment.match(/(?:[^\s"=]+=[^\s"]*|"[^"]*")/g)?.map((entry) => entry.replace(/^"|"$/g, "")).filter((entry) => entry.startsWith("OVERDECK_DISPATCH_ID=")).map((entry) => entry.slice("OVERDECK_DISPATCH_ID=".length)) ?? [];
      if (dispatchIds.length !== 1 || dispatchIds[0] !== request.dispatchId) {
        throw new IncidentLaunchError("start", "service identity mismatch");
      }
      if (activeState !== "active") return;
      const stopped = await execute(["/usr/bin/systemctl", "--user", "stop", unit]);
      if (stopped.exitCode !== 0) throw new IncidentLaunchError("start", stopped.stderr.trim() || `systemctl exited ${stopped.exitCode}`);
      const verified = await execute(["/usr/bin/systemctl", "--user", "is-active", unit]);
      if (verified.exitCode === 0 || !["inactive", "failed", "unknown"].includes(verified.stdout.trim())) {
        throw new IncidentLaunchError("start", "service remained active after stop");
      }
    },
    async launch(request): Promise<IncidentLaunchReceipt> {
      if (request.permissionMode !== "safe") throw new IncidentLaunchError("provision", "unsafe incident permission mode refused");
      assertId(request.incidentId, "incident id");
      assertId(request.dispatchId, "dispatch id");
      const root = await existingDirectory(deps.workspaceRoot, "incident workspace root");
      const sourceRepo = await existingDirectory(deps.sourceRepo, "incident source repository");
      const runnerEntry = await realpath(deps.runnerEntry).catch(() => "");
      if (!runnerEntry || !isAbsolute(runnerEntry) || relative(sourceRepo, runnerEntry).startsWith("..") || relative(sourceRepo, runnerEntry) === "") {
        throw new IncidentLaunchError("provision", "incident runner entry escaped deployed source repository");
      }
      if (!isAbsolute(request.wrapper)) throw new IncidentLaunchError("provision", "wrapper must be absolute");
      const wrapper = await realpath(request.wrapper).catch(() => "");
      if (!wrapper || relative(sourceRepo, wrapper).startsWith("..") || relative(sourceRepo, wrapper) === "") {
        throw new IncidentLaunchError("provision", "wrapper escaped deployed source repository");
      }
      try { await access(wrapper, constants.X_OK); }
      catch { throw new IncidentLaunchError("provision", "wrapper is not executable"); }

      const workspace = resolve(request.workspace);
      if (workspace !== resolve(root, request.incidentId) || relative(root, workspace).startsWith("..") || relative(root, workspace) === "") {
        throw new IncidentLaunchError("provision", "workspace escaped configured root");
      }
      const unit = `overdeck-incident-${request.incidentId}.service`;
      const encoded = Buffer.from(JSON.stringify({ ...request, workspace, wrapper }), "utf8").toString("base64url");
      const workspaceExists = await stat(workspace).then((value) => value.isDirectory()).catch(() => false);
      let reuseWorkspace = false;
      if (workspaceExists) {
        const active = await execute(["/usr/bin/systemctl", "--user", "is-active", unit])
          .catch(() => ({ exitCode: -1, stdout: "", stderr: "" }));
        if (active.exitCode === 0 && active.stdout.trim() === "active") {
          if (!await validateActiveService(execute, unit, request.dispatchId, workspace, bun, runnerEntry, encoded)) {
            throw new IncidentLaunchError("provision", "active service identity mismatch");
          }
          return { dispatchId: request.dispatchId, unit, acceptedAt: now().toISOString() };
        }
        reuseWorkspace = await validateReusableWorktree(execute, sourceRepo, workspace, request.dispatchId).catch(() => false);
        if (!reuseWorkspace) {
          throw new IncidentLaunchError("provision", `existing workspace mismatch; recover or remove ${workspace}`);
        }
      }
      if (!reuseWorkspace) try {
        const provisioned = await execute(["/usr/bin/git", "-C", sourceRepo, "worktree", "add", "--detach", workspace, "HEAD"]);
        if (provisioned.exitCode !== 0) throw new Error(provisioned.stderr.trim() || `git exited ${provisioned.exitCode}`);
        const identified = await execute(["/usr/bin/git", "-C", workspace, "config", "--worktree", "overdeck.dispatchId", request.dispatchId]);
        if (identified.exitCode !== 0) throw new Error(identified.stderr.trim() || "dispatch identity persistence refused");
      } catch (error) {
        throw new IncidentLaunchError("provision", `workspace provisioning refused: ${String(error)}`);
      }

      const runtime = request.timeoutSeconds + TEARDOWN_GRACE_SECONDS;
      const started = await execute([
        "/usr/bin/systemd-run", "--user", `--unit=${unit}`, "--service-type=exec", "--collect",
        `--setenv=OVERDECK_DISPATCH_ID=${request.dispatchId}`, `--working-directory=${workspace}`,
        "--property=Restart=no", `--property=RuntimeMaxSec=${runtime}s`, `--property=TimeoutStopSec=${TEARDOWN_GRACE_SECONDS}s`,
        "--property=MemoryMax=2G", "--property=TasksMax=512", "--property=LimitFSIZE=16M",
        "--quiet", bun, "run", runnerEntry, encoded,
      ]).catch((error) => ({ exitCode: -1, stdout: "", stderr: String(error) }));
      if (started.exitCode !== 0) {
        const startFailure = started.stderr.trim() || `systemd-run exited ${started.exitCode}`;
        const cleanup = await execute([
          "/usr/bin/timeout", "--signal=TERM", "--kill-after=2s", "10s",
          "/usr/bin/git", "-C", sourceRepo, "worktree", "remove", workspace,
        ]).catch((error) => ({ exitCode: -1, stdout: "", stderr: String(error) }));
        if (cleanup.exitCode !== 0) {
          const cleanupFailure = cleanup.stderr.trim() || `cleanup exited ${cleanup.exitCode}`;
          throw new IncidentLaunchError("start", `${startFailure}; workspace cleanup refused: ${cleanupFailure}; recover at ${workspace}`);
        }
        throw new IncidentLaunchError("start", startFailure);
      }
      return { dispatchId: request.dispatchId, unit, acceptedAt: now().toISOString() };
    },
  };
}

const RunnerRequestSchema = z.object({
  incidentId: z.string().regex(SAFE_ID), taskId: z.number().int().positive(), dispatchId: z.string().regex(SAFE_ID),
  brief: z.string().min(1), workspace: z.string(), wrapper: z.string(), wrapperModel: z.string(),
  account: z.string(), accountMode: z.enum(["profile", "fixed"]), permissionMode: z.literal("safe"),
  timeoutSeconds: z.number().int().positive(), initialRevision: z.number().int().positive().optional(),
  priority: z.enum(["P0", "P1", "P2", "P3"]),
}).strict();

export function decodeIncidentRunnerRequest(encoded: string): IncidentAgentRequest {
  return RunnerRequestSchema.parse(JSON.parse(Buffer.from(encoded, "base64url").toString("utf8")));
}
