import type { ExtensionAPI } from "@jaeswift/jae-coding-agent";
import { existsSync, readFileSync } from "node:fs";
import { join, basename } from "node:path";
import { Type } from "@sinclair/typebox";

export default function (pi: ExtensionAPI) {
  async function dockerExec(args: string[], cwd: string): Promise<{ ok: boolean; output: string }> {
    try {
      const result = await pi.exec("docker", args, { cwd });
      return {
        ok: result.code === 0,
        output: (result.stdout || "").trim() || (result.stderr || "").trim() || "(no output)",
      };
    } catch (err: any) {
      return { ok: false, output: `Docker error: ${err.message}` };
    }
  }

  async function getContainerStatus(cwd: string): Promise<string> {
    const result = await dockerExec(
      ["ps", "--format", "table {{.ID}}\t{{.Names}}\t{{.Image}}\t{{.Status}}\t{{.Ports}}"],
      cwd,
    );
    if (!result.ok) return `\u274C Docker not available: ${result.output}`;
    if (!result.output.trim() || result.output.split("\n").length <= 1) {
      return "\u{1F4AD} No running containers.";
    }
    return `\u{1F433} Running Containers:\n\n${result.output}`;
  }

  async function getContainerLogs(container: string, cwd: string, tail: number = 50): Promise<string> {
    const result = await dockerExec(["logs", "--tail", String(tail), container], cwd);
    if (!result.ok) return `\u274C Failed to get logs for '${container}': ${result.output}`;
    return `\u{1F4DC} Logs for ${container} (last ${tail} lines):\n\n${result.output}`;
  }

  async function buildImage(cwd: string, tag?: string, dockerfile?: string): Promise<string> {
    const imageTag = tag || basename(cwd).toLowerCase().replace(/[^a-z0-9_.-]/g, "-");
    const args = ["build", "-t", imageTag];
    if (dockerfile) args.push("-f", dockerfile);
    args.push(".");

    const result = await dockerExec(args, cwd);
    if (!result.ok) return `\u274C Build failed:\n${result.output.substring(0, 1000)}`;

    // Get image info
    const info = await dockerExec(["images", imageTag, "--format", "{{.Repository}}:{{.Tag}}  {{.Size}}  {{.CreatedAt}}"], cwd);
    return `\u2705 Image built successfully: ${imageTag}\n${info.output}\n\nRun: docker run -d -p 3000:3000 ${imageTag}`;
  }

  async function analyzeProjectForDockerfile(cwd: string): Promise<string> {
    const analysis: string[] = [];

    // Detect project type
    if (existsSync(join(cwd, "package.json"))) {
      try {
        const pkg = JSON.parse(readFileSync(join(cwd, "package.json"), "utf-8"));
        const deps = { ...pkg.dependencies, ...pkg.devDependencies };
        if (deps["next"]) {
          analysis.push("Detected: Next.js application");
          analysis.push("Recommended: Multi-stage build with Node.js Alpine");
          analysis.push(generateNodeDockerfile("next", pkg));
        } else if (deps["vite"] || deps["react-scripts"]) {
          analysis.push("Detected: SPA (React/Vite)");
          analysis.push("Recommended: Multi-stage build with nginx");
          analysis.push(generateSPADockerfile(pkg));
        } else {
          analysis.push("Detected: Node.js application");
          analysis.push(generateNodeDockerfile("node", pkg));
        }
      } catch {
        analysis.push("Could not parse package.json");
      }
    } else if (existsSync(join(cwd, "requirements.txt")) || existsSync(join(cwd, "pyproject.toml"))) {
      analysis.push("Detected: Python application");
      analysis.push(generatePythonDockerfile(cwd));
    } else if (existsSync(join(cwd, "go.mod"))) {
      analysis.push("Detected: Go application");
      analysis.push(generateGoDockerfile());
    } else if (existsSync(join(cwd, "Cargo.toml"))) {
      analysis.push("Detected: Rust application");
      analysis.push("Recommended: Multi-stage build with rust:alpine");
    } else {
      analysis.push("Could not detect project type. Provide a Dockerfile manually.");
    }

    return analysis.join("\n\n");
  }

  function generateNodeDockerfile(type: string, pkg: any): string {
    const startCmd = pkg.scripts?.start ? "npm start" : "node index.js";
    if (type === "next") {
      return `# Suggested Dockerfile for Next.js
FROM node:20-alpine AS deps
WORKDIR /app
COPY package*.json ./
RUN npm ci

FROM node:20-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build

FROM node:20-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static
COPY --from=builder /app/public ./public
EXPOSE 3000
CMD ["node", "server.js"]`;
    }
    return `# Suggested Dockerfile for Node.js
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY . .
EXPOSE 3000
CMD ["${startCmd.split(" ")[0]}", ${startCmd.split(" ").slice(1).map((s: string) => `"${s}"`).join(", ")}]`;
  }

  function generateSPADockerfile(pkg: any): string {
    const buildDir = pkg.scripts?.build?.includes("vite") ? "dist" : "build";
    return `# Suggested Dockerfile for SPA
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM nginx:alpine
COPY --from=builder /app/${buildDir} /usr/share/nginx/html
COPY <<EOF /etc/nginx/conf.d/default.conf
server {
    listen 80;
    root /usr/share/nginx/html;
    location / {
        try_files \$uri \$uri/ /index.html;
    }
}
EOF
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]`;
  }

  function generatePythonDockerfile(cwd: string): string {
    const hasRequirements = existsSync(join(cwd, "requirements.txt"));
    const hasPyproject = existsSync(join(cwd, "pyproject.toml"));
    const installCmd = hasRequirements
      ? "COPY requirements.txt .\nRUN pip install --no-cache-dir -r requirements.txt"
      : hasPyproject
        ? "COPY pyproject.toml .\nRUN pip install --no-cache-dir ."
        : "# Add your dependency installation here";
    return `# Suggested Dockerfile for Python
FROM python:3.12-slim
WORKDIR /app
${installCmd}
COPY . .
EXPOSE 8000
CMD ["python", "main.py"]`;
  }

  function generateGoDockerfile(): string {
    return `# Suggested Dockerfile for Go
FROM golang:1.22-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -o /app/server .

FROM alpine:latest
WORKDIR /app
COPY --from=builder /app/server .
EXPOSE 8080
CMD ["./server"]`;
  }

  pi.registerTool({
    name: "docker_manage",
    label: "Docker Manager",
    description: "Manage Docker containers: list running containers, build images, view logs, or generate Dockerfiles from project analysis.",
    parameters: Type.Object({
      action: Type.String({ description: "Action: 'status', 'build', 'logs', 'generate', 'run', 'stop'" }),
      container: Type.Optional(Type.String({ description: "Container name or ID (for logs/stop)" })),
      tag: Type.Optional(Type.String({ description: "Image tag for build" })),
      port: Type.Optional(Type.String({ description: "Port mapping for run (e.g., '3000:3000')" })),
    }),
    execute: async (args, ctx) => {
      const action = args.action.toLowerCase();

      switch (action) {
        case "status":
        case "ps":
        case "list": {
          const status = await getContainerStatus(ctx.cwd);
          return { output: status };
        }
        case "build": {
          if (!existsSync(join(ctx.cwd, "Dockerfile"))) {
            return { error: "No Dockerfile found. Use action 'generate' to create one." };
          }
          const result = await buildImage(ctx.cwd, args.tag);
          return { output: result };
        }
        case "logs": {
          if (!args.container) return { error: "Specify a container name or ID." };
          const logs = await getContainerLogs(args.container, ctx.cwd);
          return { output: logs };
        }
        case "generate": {
          const analysis = await analyzeProjectForDockerfile(ctx.cwd);
          return { output: `\u{1F433} Dockerfile Generation:\n\n${analysis}` };
        }
        case "run": {
          const tag = args.tag || basename(ctx.cwd).toLowerCase().replace(/[^a-z0-9_.-]/g, "-");
          const runArgs = ["run", "-d"];
          if (args.port) runArgs.push("-p", args.port);
          runArgs.push(tag);
          const result = await dockerExec(runArgs, ctx.cwd);
          return { output: result.ok ? `\u2705 Container started: ${result.output.substring(0, 12)}` : `\u274C ${result.output}` };
        }
        case "stop": {
          if (!args.container) return { error: "Specify a container name or ID." };
          const result = await dockerExec(["stop", args.container], ctx.cwd);
          return { output: result.ok ? `\u2705 Stopped: ${args.container}` : `\u274C ${result.output}` };
        }
        default:
          return { error: `Unknown action '${action}'. Use: status, build, logs, generate, run, stop` };
      }
    },
  });

  pi.registerCommand("docker", {
    description: "Docker manager: /docker [build|logs <container>|generate|status]",
    handler: async (args, ctx) => {
      const parts = args.trim().split(/\s+/);
      const subcommand = (parts[0] || "status").toLowerCase();

      switch (subcommand) {
        case "status":
        case "ps":
        case "": {
          const status = await getContainerStatus(ctx.cwd);
          ctx.ui.notify(status, "info");
          break;
        }
        case "build": {
          if (!existsSync(join(ctx.cwd, "Dockerfile"))) {
            ctx.ui.notify("\u274C No Dockerfile found. Use /docker generate first.", "warning");
            return;
          }
          ctx.ui.notify("\u{1F528} Building Docker image...", "info");
          const tag = parts[1] || undefined;
          const result = await buildImage(ctx.cwd, tag);
          ctx.ui.notify(result, "info");
          break;
        }
        case "logs": {
          const container = parts[1];
          if (!container) {
            ctx.ui.notify("Usage: /docker logs <container-name-or-id>", "warning");
            return;
          }
          const tail = parseInt(parts[2] || "50", 10);
          const logs = await getContainerLogs(container, ctx.cwd, tail);
          ctx.ui.notify(logs, "info");
          break;
        }
        case "generate": {
          ctx.ui.notify("\u{1F50D} Analyzing project for Dockerfile generation...", "info");
          const analysis = await analyzeProjectForDockerfile(ctx.cwd);
          ctx.ui.notify(`\u{1F433} Dockerfile Suggestion:\n\n${analysis}\n\n\u{1F4A1} Tip: Ask JAE to create the Dockerfile based on this analysis.`, "info");
          break;
        }
        case "stop": {
          const container = parts[1];
          if (!container) {
            ctx.ui.notify("Usage: /docker stop <container-name-or-id>", "warning");
            return;
          }
          const result = await dockerExec(["stop", container], ctx.cwd);
          ctx.ui.notify(result.ok ? `\u2705 Stopped: ${container}` : `\u274C ${result.output}`, "info");
          break;
        }
        case "run": {
          const tag = parts[1];
          if (!tag) {
            ctx.ui.notify("Usage: /docker run <image> [port-mapping]", "warning");
            return;
          }
          const port = parts[2] || undefined;
          const runArgs = ["run", "-d"];
          if (port) runArgs.push("-p", port);
          runArgs.push(tag);
          const result = await dockerExec(runArgs, ctx.cwd);
          ctx.ui.notify(result.ok ? `\u2705 Container started: ${result.output.substring(0, 12)}` : `\u274C ${result.output}`, "info");
          break;
        }
        default:
          ctx.ui.notify(
            `\u{1F433} Docker Manager\n${'\u2500'.repeat(30)}\n\n` +
              "Commands:\n" +
              "  /docker          - Show running containers\n" +
              "  /docker build     - Build image from Dockerfile\n" +
              "  /docker logs <id> - Show container logs\n" +
              "  /docker generate  - Generate Dockerfile for project\n" +
              "  /docker run <img> - Run a container\n" +
              "  /docker stop <id> - Stop a container",
            "info",
          );
      }
    },
  });
}
