import { z } from "zod";

export const DEFAULT_REMOTE_CONFIG = {
  enabled: false,
  hosts: [] as string[],
  port: 22,
  ssh_user: "user",
  remote_root: "/home/user/builds",
  health_ttl_sec: 30,
  connect_timeout_sec: 6,
  max_remote_jobs: 6,
  ssh_probe_timeout_sec: 15,
  ssh_exec_timeout_sec: 1800,
  rsync_io_timeout_sec: 300,
  rsync_timeout_sec: 900,
  dispatch_timeout_sec: 120,
  doctor_host_timeout_sec: 30,
  local_step_timeout_sec: 120,
  grace_window_sec: 600,
  reconnect_interval_sec: 10,
  local_only: [] as string[],
  local_fallback: true,
  remote_wait_sec: 60,
  local_requeue_sec: 900,
  rsync_only: [] as string[],
  push_excludes: [
    "node_modules",
    ".pnpm-store",
    ".turbo",
    ".astro",
    ".cache",
    "dist",
    "build",
    ".next",
    "coverage",
    "playwright-report",
    "test-results",
    "target",
    ".tmpjail-work",
    ".rb-lockhash",
    ".rb-epoch",
    ".rb-origin",
  ],
  pull_excludes: [
    "node_modules",
    ".git",
    ".pnpm-store",
    ".cache",
    "target",
    ".tmpjail-work",
    ".rb-lockhash",
    ".rb-epoch",
    ".rb-origin",
    ".rb-overlay-manifest",
  ],
  ship_ignored: [".dev.vars", ".env", ".env.local"],
  k3s_enabled: false,
  k3s_allowlist: [] as string[],
};

const stringArraySchema = z.array(z.string());

const BuildRemoteConfigRawSchema = z
  .object({
    enabled: z.boolean().optional(),
    port: z.number().int().positive().optional(),
    ssh_user: z.string().min(1).optional(),
    remote_root: z.string().min(1).optional(),
    health_ttl_sec: z.number().int().positive().optional(),
    connect_timeout_sec: z.number().int().positive().optional(),
    max_remote_jobs: z.number().int().positive().optional(),
    ssh_probe_timeout_sec: z.number().int().positive().optional(),
    ssh_exec_timeout_sec: z.number().int().positive().optional(),
    rsync_io_timeout_sec: z.number().int().positive().optional(),
    rsync_timeout_sec: z.number().int().positive().optional(),
    dispatch_timeout_sec: z.number().int().positive().optional(),
    doctor_host_timeout_sec: z.number().int().positive().optional(),
    local_step_timeout_sec: z.number().int().positive().optional(),
    grace_window_sec: z.number().int().positive().optional(),
    reconnect_interval_sec: z.number().int().positive().optional(),
    local_only: stringArraySchema.optional(),
    local_fallback: z.boolean().optional(),
    dispatch_hosts: stringArraySchema.optional(),
    remote_wait_sec: z.number().int().positive().optional(),
    local_requeue_sec: z.number().int().positive().optional(),
    rsync_only: stringArraySchema.optional(),
    push_excludes: stringArraySchema.optional(),
    pull_excludes: stringArraySchema.optional(),
    ship_ignored: stringArraySchema.optional(),
    identity_file: z.string().optional(),
    remote_job_timeout_sec: z.number().int().positive().optional(),
    k3s_enabled: z.boolean().optional(),
    k3s_allowlist: stringArraySchema.optional(),
    k3s_image: z.string().min(1).optional(),
    k3s_namespace: z.string().regex(/^[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?$/).optional(),
    k3s_service_account: z.string().regex(/^[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?$/).optional(),
    k3s_kubeconfig: z.string().min(1).optional(),
    k3s_api_server: z.string().url().optional(),
    k3s_ca_sha256: z.string().regex(/^[a-f0-9]{64}$/i).optional(),
  })
  .strict();

type BuildRemoteConfigRaw = z.infer<typeof BuildRemoteConfigRawSchema>;

export type NormalizedBuildRemoteConfig = {
  enabled: boolean;
  // Injected by the caller from the fleet declaration.
  hosts: string[];
  port: number;
  ssh_user: string;
  remote_root: string;
  health_ttl_sec: number;
  connect_timeout_sec: number;
  max_remote_jobs: number;
  ssh_probe_timeout_sec: number;
  ssh_exec_timeout_sec: number;
  rsync_io_timeout_sec: number;
  rsync_timeout_sec: number;
  dispatch_timeout_sec: number;
  doctor_host_timeout_sec: number;
  local_step_timeout_sec: number;
  grace_window_sec: number;
  reconnect_interval_sec: number;
  local_only: string[];
  local_fallback: boolean;
  dispatch_hosts?: string[];
  remote_wait_sec: number;
  local_requeue_sec: number;
  rsync_only: string[];
  push_excludes: string[];
  pull_excludes: string[];
  ship_ignored: string[];
  host?: string;
  identity_file?: string;
  remote_job_timeout_sec?: number;
  k3s_enabled: boolean;
  k3s_allowlist: string[];
  k3s_image?: string;
  k3s_namespace?: string;
  k3s_service_account?: string;
  k3s_kubeconfig?: string;
  k3s_api_server?: string;
  k3s_ca_sha256?: string;
};

export function normalizeBuildRemoteConfig(validated: BuildRemoteConfigRaw): NormalizedBuildRemoteConfig {
  return { ...DEFAULT_REMOTE_CONFIG, ...validated };
}

export function isBuildRemoteDisabled(config: NormalizedBuildRemoteConfig): boolean {
  return config.enabled === false || config.hosts.length === 0;
}

export function safeParseBuildRemoteConfig(
  raw: unknown,
):
  | { success: true; data: NormalizedBuildRemoteConfig }
  | { success: false; error: z.ZodError } {
  const parsed = BuildRemoteConfigRawSchema.safeParse(raw);
  if (!parsed.success) {
    return { success: false, error: parsed.error };
  }
  return { success: true, data: normalizeBuildRemoteConfig(parsed.data) };
}

export function parseBuildRemoteConfig(raw: unknown): NormalizedBuildRemoteConfig {
  const parsed = safeParseBuildRemoteConfig(raw);
  if (!parsed.success) {
    throw parsed.error;
  }
  return parsed.data;
}
