import { existsSync, mkdirSync, writeFileSync } from "node:fs";
import { dirname, join, resolve } from "node:path";
import { generateDocker } from "./docker.ts";

export const DEPLOY_TARGETS = [
  "docker",
  "kubernetes",
  "systemd",
  "railway",
  "render",
  "fly",
] as const;
export type DeployTarget = (typeof DEPLOY_TARGETS)[number];

const ENVIRONMENT = `# Copy to .env.production and replace every required value.
NODE_ENV=production
PORT=3000
HOST=0.0.0.0
DATABASE_URL=postgres://USER:PASSWORD@HOST:5432/DB
SESSION_SECRET=REPLACE_WITH_AT_LEAST_32_RANDOM_BYTES
# OTEL_EXPORTER_OTLP_ENDPOINT=https://collector.example.com
`;

const OPERATIONS = `# WRNexus deployment operations

- Liveness: \`GET /healthz\`
- Readiness: \`GET /readyz\` (includes registered dependency checks)
- Migrations: run \`bunx wrnexus db migrate --profile=production\` once per release before scaling.
- Shutdown: the Bun production server drains on SIGTERM/SIGINT.
- Assets: \`dist/public\` files are content-addressed and may be cached immutably by a CDN.
- Secrets: provide \`DATABASE_URL\` and \`SESSION_SECRET\` through the platform secret store; never commit production env files.
- Logs: stdout/stderr are structured for platform collection. Configure OTLP for centralized telemetry.
- Scaling: start with 250m CPU/256Mi memory, use readiness probes, and scale horizontally from request latency and CPU.
`;

const KUBERNETES = `apiVersion: v1
kind: Service
metadata:
  name: wrnexus
spec:
  selector: { app: wrnexus }
  ports: [{ name: http, port: 80, targetPort: 3000 }]
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: wrnexus
spec:
  replicas: 2
  selector: { matchLabels: { app: wrnexus } }
  template:
    metadata: { labels: { app: wrnexus } }
    spec:
      containers:
        - name: app
          image: ghcr.io/OWNER/APP:latest
          ports: [{ containerPort: 3000 }]
          envFrom: [{ secretRef: { name: wrnexus-secrets } }]
          livenessProbe: { httpGet: { path: /healthz, port: 3000 }, initialDelaySeconds: 5 }
          readinessProbe: { httpGet: { path: /readyz, port: 3000 }, initialDelaySeconds: 5 }
          resources:
            requests: { cpu: 250m, memory: 256Mi }
            limits: { cpu: "1", memory: 512Mi }
          lifecycle: { preStop: { exec: { command: ["sh", "-c", "sleep 5"] } } }
      terminationGracePeriodSeconds: 30
---
apiVersion: batch/v1
kind: Job
metadata:
  name: wrnexus-migrate
spec:
  template:
    spec:
      restartPolicy: Never
      containers:
        - name: migrate
          image: ghcr.io/OWNER/APP:latest
          command: ["bunx", "wrnexus", "db", "migrate", "--profile=production"]
          envFrom: [{ secretRef: { name: wrnexus-secrets } }]
`;

const SYSTEMD = `[Unit]
Description=WRNexus application
After=network-online.target

[Service]
Type=simple
WorkingDirectory=/srv/wrnexus
EnvironmentFile=/etc/wrnexus/wrnexus.env
ExecStartPre=/usr/bin/bunx wrnexus db migrate --profile=production
ExecStart=/usr/bin/bun dist/server.js
Restart=on-failure
RestartSec=5
TimeoutStopSec=30
User=wrnexus
Group=wrnexus
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ReadWritePaths=/srv/wrnexus

[Install]
WantedBy=multi-user.target
`;

const NGINX = `server {
  listen 80;
  server_name example.com;
  location /assets/ { root /srv/wrnexus/dist/public; expires 1y; add_header Cache-Control "public, immutable"; }
  location / { proxy_pass http://127.0.0.1:3000; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Request-ID $request_id; }
}
`;

const RAILWAY = `[build]
builder = "DOCKERFILE"

[deploy]
startCommand = "bun dist/server.js"
healthcheckPath = "/readyz"
restartPolicyType = "ON_FAILURE"
preDeployCommand = ["bunx wrnexus db migrate --profile=production"]
`;

const RENDER = `services:
  - type: web
    name: wrnexus
    runtime: docker
    healthCheckPath: /readyz
    preDeployCommand: bunx wrnexus db migrate --profile=production
    envVars:
      - key: DATABASE_URL
        sync: false
      - key: SESSION_SECRET
        sync: false
`;

const FLY = `app = "wrnexus-app"
primary_region = "bom"

[build]
  dockerfile = "Dockerfile"
[env]
  PORT = "3000"
[http_service]
  internal_port = 3000
  force_https = true
  auto_stop_machines = "stop"
  auto_start_machines = true
  min_machines_running = 1
  [[http_service.checks]]
    path = "/readyz"
    interval = "15s"
    timeout = "2s"
[deploy]
  release_command = "bunx wrnexus db migrate --profile=production"
`;

function write(root: string, relative: string, content: string, files: string[]): void {
  const path = join(root, relative);
  if (existsSync(path)) return;
  mkdirSync(dirname(path), { recursive: true });
  writeFileSync(path, content, "utf8");
  files.push(relative);
}

export function generateDeployment(appRoot: string, target: string): string[] {
  if (!DEPLOY_TARGETS.includes(target as DeployTarget))
    throw new Error(`WRN-DEPLOY-TARGET: use ${DEPLOY_TARGETS.join(" | ")}.`);
  const root = resolve(appRoot);
  const files: string[] = [];
  if (target === "docker" || ["kubernetes", "railway", "render", "fly"].includes(target))
    generateDocker(root);
  write(root, ".env.production.example", ENVIRONMENT, files);
  write(root, "deploy/README.md", OPERATIONS, files);
  if (target === "kubernetes") write(root, "deploy/kubernetes.yaml", KUBERNETES, files);
  if (target === "systemd") {
    write(root, "deploy/wrnexus.service", SYSTEMD, files);
    write(root, "deploy/nginx.conf", NGINX, files);
  }
  if (target === "railway") write(root, "railway.toml", RAILWAY, files);
  if (target === "render") write(root, "render.yaml", RENDER, files);
  if (target === "fly") write(root, "fly.toml", FLY, files);
  return files;
}
