import React, { useEffect, useMemo, useState } from "react";
import { useParams, useNavigate, Link } from "react-router-dom";
import { api } from "../services/api";
import { toast } from "react-toastify";
import {
  ArrowLeft,
  ChevronRight,
  Container,
  KeyRound,
  MessageSquare,
  Package,
  Plus,
  Save,
  Server,
  Shield,
  Terminal,
  X,
} from "lucide-react";
import { DEFAULT_INSTANCE_TYPE, INSTANCE_TYPES, isPresetInstanceType, normalizeInstanceType } from "../lib/instanceTypes";
import { usePageTitle } from "../hooks/usePageTitle";

type RepoConfigState = {
  instanceType: string;
  inactivityHours: number;
  port: number;
  denyList: string[];
  disabledCommands: string[];
  envVars: Record<string, string>;
  preinstallTools: string[];
  nodeVersion: string;
  useDockerCompose: boolean;
  composeFilePath: string;
  aptPackages: string[];
  setupCommands: string[];
  buildCommands: string[];
  postBuildCommands: string[];
  runCommand: string;
};

type SectionKey = "compute" | "runtime" | "docker" | "commands" | "environment" | "access" | "commentCommands";

function defaultConfig(): RepoConfigState {
  return {
    instanceType: DEFAULT_INSTANCE_TYPE,
    inactivityHours: 12,
    port: 3000,
    denyList: [],
    disabledCommands: [],
    envVars: {},
    preinstallTools: [],
    nodeVersion: "lts/*",
    useDockerCompose: false,
    composeFilePath: "docker-compose.yml",
    aptPackages: [],
    setupCommands: [],
    buildCommands: [],
    postBuildCommands: [],
    runCommand: "",
  };
}

function normalizeConfig(raw: any): RepoConfigState {
  const base = defaultConfig();
  if (!raw) return base;
  return {
    instanceType: normalizeInstanceType(raw.instanceType ?? base.instanceType),
    inactivityHours: raw.inactivityHours ?? base.inactivityHours,
    port: raw.port ?? base.port,
    denyList: Array.isArray(raw.denyList) ? raw.denyList : [],
    disabledCommands: Array.isArray(raw.disabledCommands) ? raw.disabledCommands : [],
    envVars: raw.envVars && typeof raw.envVars === "object" ? raw.envVars : {},
    preinstallTools: Array.isArray(raw.preinstallTools) ? raw.preinstallTools : [],
    nodeVersion: raw.nodeVersion ?? base.nodeVersion,
    useDockerCompose: Boolean(raw.useDockerCompose),
    composeFilePath: raw.composeFilePath ?? base.composeFilePath,
    aptPackages: Array.isArray(raw.aptPackages) ? raw.aptPackages : [],
    setupCommands: Array.isArray(raw.setupCommands) ? raw.setupCommands : [],
    buildCommands: Array.isArray(raw.buildCommands) ? raw.buildCommands : [],
    postBuildCommands: Array.isArray(raw.postBuildCommands) ? raw.postBuildCommands : [],
    runCommand: raw.runCommand ?? "",
  };
}

function parseAptPackages(value: string) {
  return value.trim().split(/\s+/).filter(Boolean);
}

export function RepoConfig() {
  const { owner, repo } = useParams<{ owner: string; repo: string }>();
  const navigate = useNavigate();
  const [config, setConfig] = useState<RepoConfigState>(defaultConfig());
  const [aptPackagesInput, setAptPackagesInput] = useState("");
  const [activeSection, setActiveSection] = useState<SectionKey>("compute");
  const [loading, setLoading] = useState(true);
  const [saving, setSaving] = useState(false);
  usePageTitle(owner && repo ? `Configure ${owner}/${repo}` : "Configure Repo");

  useEffect(() => {
    let active = true;
    (async () => {
      if (!owner || !repo) return;
      setLoading(true);
      const res = await api.repos.getConfig(owner, repo);
      if (!active) return;
      if (res.ok) {
        const nextConfig = normalizeConfig(res.data);
        setConfig(nextConfig);
        setAptPackagesInput(nextConfig.aptPackages.join(" "));
      } else if (res.status === 404) {
        setConfig(defaultConfig());
        setAptPackagesInput("");
      } else {
        toast.error(res.message || "Failed to load config");
      }
      setLoading(false);
    })();
    return () => { active = false; };
  }, [owner, repo]);

  const update = <K extends keyof RepoConfigState>(field: K, value: RepoConfigState[K]) => {
    setConfig(prev => ({ ...prev, [field]: value }));
  };

  const togglePreinstall = (tool: string, checked: boolean) => {
    setConfig(prev => {
      const current = Array.isArray(prev.preinstallTools) ? prev.preinstallTools : [];
      const next = checked
        ? [...new Set([...current, tool])]
        : current.filter(item => item !== tool);
      return { ...prev, preinstallTools: next };
    });
  };

  const setDockerCompose = (checked: boolean) => {
    setConfig(prev => {
      const current = Array.isArray(prev.preinstallTools) ? prev.preinstallTools : [];
      return {
        ...prev,
        useDockerCompose: checked,
        preinstallTools: checked ? [...new Set([...current, "docker"])] : current,
      };
    });
  };

  const handleSave = async () => {
    if (!owner || !repo) return;
    setSaving(true);
    const nextAptPackages = parseAptPackages(aptPackagesInput);
    const res = await api.repos.saveConfig({
      owner,
      repo,
      ...config,
      aptPackages: nextAptPackages,
    });
    setSaving(false);
    if (res.ok) {
      setConfig(prev => ({ ...prev, aptPackages: nextAptPackages }));
      toast.success("Repo settings saved");
    } else {
      toast.error(res.message || "Failed to save settings");
    }
  };

  const sections = useMemo(() => buildSections(config), [config]);
  const currentSection = sections.find(section => section.key === activeSection) ?? sections[0];

  if (loading) {
    return (
      <div className="max-w-6xl space-y-4">
        <div className="h-8 w-64 bg-gray-100 dark:bg-slate-800 rounded animate-pulse" />
        <div className="grid gap-4 lg:grid-cols-[minmax(0,1fr)_minmax(360px,0.85fr)]">
          <div className="space-y-2">
            {[...Array(7)].map((_, i) => <div key={i} className="h-20 bg-gray-100 dark:bg-slate-800 rounded-lg animate-pulse" />)}
          </div>
          <div className="h-96 bg-gray-100 dark:bg-slate-800 rounded-lg animate-pulse" />
        </div>
      </div>
    );
  }

  return (
    <div className="max-w-6xl space-y-5">
      <div>
        <Link to="/repos" className="inline-flex items-center gap-1 text-sm text-blue-600 dark:text-blue-400 hover:underline">
          <ArrowLeft size={14} /> Repositories
        </Link>
      </div>

      <div className="flex flex-col gap-3 sm:flex-row sm:items-end sm:justify-between">
        <div className="min-w-0">
          <h1 className="text-2xl font-bold">Repo Settings</h1>
          <p className="text-sm text-gray-500 dark:text-slate-400 font-mono truncate">{owner}/{repo}</p>
        </div>
        <div className="flex gap-2">
          <button
            onClick={() => navigate("/repos")}
            className="px-4 py-2 border border-gray-300 dark:border-slate-600 rounded-lg text-sm font-medium hover:bg-gray-50 dark:hover:bg-slate-800 transition-colors"
          >
            Cancel
          </button>
          <button
            onClick={handleSave}
            disabled={saving}
            className="inline-flex items-center gap-2 px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-lg text-sm font-medium transition-colors disabled:opacity-50"
          >
            <Save size={16} /> {saving ? "Saving..." : "Save"}
          </button>
        </div>
      </div>

      <div className="grid gap-4 lg:grid-cols-[minmax(0,1fr)_minmax(360px,0.85fr)]">
        <section className="space-y-2">
          {sections.map(section => {
            const selected = section.key === activeSection;
            return (
              <button
                key={section.key}
                type="button"
                onClick={() => setActiveSection(section.key)}
                className={`w-full rounded-lg border p-4 text-left transition-colors ${
                  selected
                    ? "border-blue-500 bg-blue-50 dark:border-blue-400 dark:bg-blue-950/30"
                    : "border-gray-200 bg-white hover:border-gray-300 hover:bg-gray-50 dark:border-slate-700 dark:bg-slate-800 dark:hover:border-slate-600 dark:hover:bg-slate-800/80"
                }`}
              >
                <div className="flex items-start gap-3">
                  <span className={`mt-0.5 rounded-md border p-2 ${
                    selected
                      ? "border-blue-200 bg-white text-blue-600 dark:border-blue-800 dark:bg-slate-900 dark:text-blue-300"
                      : "border-gray-200 bg-gray-50 text-gray-500 dark:border-slate-700 dark:bg-slate-900 dark:text-slate-400"
                  }`}>
                    {section.icon}
                  </span>
                  <span className="min-w-0 flex-1">
                    <span className="flex items-center justify-between gap-3">
                      <span className="font-medium text-sm">{section.title}</span>
                      <ChevronRight size={16} className={selected ? "text-blue-500" : "text-gray-400"} />
                    </span>
                    <span className="mt-1 block text-sm text-gray-500 dark:text-slate-400">{section.summary}</span>
                  </span>
                </div>
              </button>
            );
          })}
        </section>

        <section className="rounded-lg border border-gray-200 bg-white p-5 dark:border-slate-700 dark:bg-slate-800">
          <div className="mb-5 flex items-start gap-3">
            <span className="rounded-md border border-gray-200 bg-gray-50 p-2 text-gray-600 dark:border-slate-700 dark:bg-slate-900 dark:text-slate-300">
              {currentSection.icon}
            </span>
            <div>
              <h2 className="font-semibold">{currentSection.title}</h2>
              <p className="text-sm text-gray-500 dark:text-slate-400">{currentSection.description}</p>
            </div>
          </div>

          {activeSection === "compute" && (
            <div className="space-y-4">
              <Field label="Instance type">
                <select
                  value={isPresetInstanceType(config.instanceType) ? config.instanceType : "custom"}
                  onChange={e => update("instanceType", e.target.value === "custom" ? "" : e.target.value)}
                  className={inputCls}
                >
                  {INSTANCE_TYPES.map(t => <option key={t.value} value={t.value}>{t.label} - {t.cost}</option>)}
                  <option value="custom">Custom...</option>
                </select>
                {!isPresetInstanceType(config.instanceType) && (
                  <input
                    type="text"
                    value={config.instanceType}
                    placeholder="Custom instance type"
                    className={`${inputCls} mt-2`}
                    onChange={e => update("instanceType", normalizeInstanceType(e.target.value, ""))}
                  />
                )}
              </Field>
              <Field label={`Inactivity timer: ${config.inactivityHours}h`}>
                <input
                  type="range"
                  min={0.5}
                  max={72}
                  step={0.5}
                  value={config.inactivityHours}
                  onChange={e => update("inactivityHours", Number(e.target.value))}
                  className="w-full"
                />
                <div className="mt-1 flex justify-between text-xs text-gray-400">
                  <span>0.5h</span><span>12h</span><span>72h</span>
                </div>
              </Field>
              <Field label="Preview port">
                <input
                  type="number"
                  value={config.port}
                  onChange={e => update("port", Number(e.target.value))}
                  className={inputCls}
                  min={1}
                  max={65535}
                />
              </Field>
            </div>
          )}

          {activeSection === "runtime" && (
            <div className="space-y-4">
              <Field label="Preinstall tools">
                <div className="grid grid-cols-1 gap-2 sm:grid-cols-2">
                  {PREINSTALL_OPTIONS.map(option => {
                    const checked = config.preinstallTools.includes(option.value);
                    const locked = option.value === "docker" && config.useDockerCompose;
                    return (
                      <label key={option.value} className="flex min-h-11 items-center gap-2 rounded-lg border border-gray-200 px-3 py-2 text-sm dark:border-slate-700">
                        <input
                          type="checkbox"
                          checked={checked}
                          disabled={locked}
                          onChange={e => togglePreinstall(option.value, e.target.checked)}
                          className="rounded"
                        />
                        <span>{option.label}</span>
                      </label>
                    );
                  })}
                </div>
              </Field>
              {config.preinstallTools.includes("node") && (
                <Field label="Node version">
                  <input
                    type="text"
                    value={config.nodeVersion || "lts/*"}
                    onChange={e => update("nodeVersion", e.target.value)}
                    className={inputCls}
                    placeholder="lts/*, 22, 20.11.1"
                  />
                </Field>
              )}
              <Field label="Additional apt packages">
                <input
                  type="text"
                  value={aptPackagesInput}
                  onChange={e => {
                    setAptPackagesInput(e.target.value);
                    update("aptPackages", parseAptPackages(e.target.value));
                  }}
                  className={inputCls}
                  placeholder="ffmpeg libpq-dev"
                />
              </Field>
            </div>
          )}

          {activeSection === "docker" && (
            <div className="space-y-4">
              <label className="flex items-center justify-between gap-4 rounded-lg border border-gray-200 p-3 dark:border-slate-700">
                <span>
                  <span className="block text-sm font-medium">Use Docker Compose</span>
                  <span className="block text-sm text-gray-500 dark:text-slate-400">Run the preview with compose instead of build and run commands.</span>
                </span>
                <input
                  type="checkbox"
                  checked={config.useDockerCompose}
                  onChange={e => setDockerCompose(e.target.checked)}
                  className="h-5 w-5 rounded"
                />
              </label>
              {config.useDockerCompose && (
                <Field label="Compose file path">
                  <input
                    type="text"
                    value={config.composeFilePath || "docker-compose.yml"}
                    onChange={e => update("composeFilePath", e.target.value)}
                    className={inputCls}
                    placeholder="docker-compose.yml"
                  />
                </Field>
              )}
            </div>
          )}

          {activeSection === "commands" && (
            <div className="space-y-4">
              <CommandList label="Setup commands" value={config.setupCommands} onChange={v => update("setupCommands", v)} placeholder="apt-get update" />
              {!config.useDockerCompose && (
                <>
                  <CommandList label="Build commands" value={config.buildCommands} onChange={v => update("buildCommands", v)} placeholder="pnpm install && pnpm build" />
                  <CommandList label="Post-build commands" value={config.postBuildCommands} onChange={v => update("postBuildCommands", v)} placeholder="prisma migrate deploy" />
                  <Field label="Run command">
                    <input
                      type="text"
                      value={config.runCommand || ""}
                      onChange={e => update("runCommand", e.target.value)}
                      className={inputCls}
                      placeholder="python app.py, ./server, pnpm start"
                    />
                  </Field>
                </>
              )}
              {config.useDockerCompose && (
                <p className="rounded-lg border border-blue-200 bg-blue-50 px-3 py-2 text-sm text-blue-700 dark:border-blue-900 dark:bg-blue-950/30 dark:text-blue-300">
                  Docker Compose mode uses the compose file path from the Docker section.
                </p>
              )}
            </div>
          )}

          {activeSection === "environment" && (
            <EnvVarsEditor value={config.envVars || {}} onChange={v => update("envVars", v)} />
          )}

          {activeSection === "access" && (
            <Field label="Deny list">
              <input
                type="text"
                value={config.denyList.join(", ")}
                onChange={e => update("denyList", e.target.value.split(",").map(s => s.trim()).filter(Boolean))}
                className={inputCls}
                placeholder="dependabot, renovate-bot"
              />
            </Field>
          )}

          {activeSection === "commentCommands" && (
            <CommandToggles value={config.disabledCommands || []} onChange={v => update("disabledCommands", v)} />
          )}
        </section>
      </div>
    </div>
  );
}

function buildSections(config: RepoConfigState) {
  return [
    {
      key: "compute" as const,
      title: "Compute",
      description: "Instance size, exposed port, and automatic idle shutdown.",
      summary: `${config.instanceType || "Custom instance"} on port ${config.port}; stops after ${config.inactivityHours}h idle`,
      icon: <Server size={18} />,
    },
    {
      key: "runtime" as const,
      title: "Runtime Packages",
      description: "Tools installed on the preview instance before app setup.",
      summary: summarizeList([...config.preinstallTools, ...config.aptPackages], "No runtime packages selected"),
      icon: <Package size={18} />,
    },
    {
      key: "docker" as const,
      title: "Docker Compose",
      description: "Choose whether the preview starts from a compose file.",
      summary: config.useDockerCompose ? `Enabled: ${config.composeFilePath || "docker-compose.yml"}` : "Disabled",
      icon: <Container size={18} />,
    },
    {
      key: "commands" as const,
      title: "Deploy Commands",
      description: "Commands used to prepare, build, and start the preview.",
      summary: config.useDockerCompose
        ? "Compose file controls startup"
        : `${config.buildCommands.length} build, ${config.postBuildCommands.length} post-build, ${config.runCommand ? "run set" : "no run command"}`,
      icon: <Terminal size={18} />,
    },
    {
      key: "environment" as const,
      title: "Environment Variables",
      description: "Variables passed to the preview app.",
      summary: `${Object.keys(config.envVars || {}).filter(Boolean).length} variables`,
      icon: <KeyRound size={18} />,
    },
    {
      key: "access" as const,
      title: "Access Controls",
      description: "Users that are blocked from creating previews for this repo.",
      summary: summarizeList(config.denyList, "No users blocked"),
      icon: <Shield size={18} />,
    },
    {
      key: "commentCommands" as const,
      title: "PR Comment Commands",
      description: "Reviewer commands available from pull request comments.",
      summary: `${CONFIGURABLE_COMMANDS.length - config.disabledCommands.length} of ${CONFIGURABLE_COMMANDS.length} commands enabled`,
      icon: <MessageSquare size={18} />,
    },
  ];
}

function summarizeList(values: string[], empty: string) {
  const clean = values.filter(Boolean);
  if (clean.length === 0) return empty;
  if (clean.length <= 3) return clean.join(", ");
  return `${clean.slice(0, 3).join(", ")} +${clean.length - 3} more`;
}

function Field({ label, children }: { label: string; children: React.ReactNode }) {
  return (
    <div>
      <label className={labelCls}>{label}</label>
      {children}
    </div>
  );
}

function CommandList({
  label,
  value,
  onChange,
  placeholder,
}: {
  label: string;
  value: string[];
  onChange: (v: string[]) => void;
  placeholder: string;
}) {
  return (
    <Field label={label}>
      <div className="space-y-2">
        {value.length === 0 && (
          <div className="rounded-lg border border-dashed border-gray-300 px-3 py-3 text-sm text-gray-500 dark:border-slate-600 dark:text-slate-400">
            No commands configured.
          </div>
        )}
        {value.map((cmd, i) => (
          <div key={i} className="flex gap-2">
            <input
              type="text"
              value={cmd}
              onChange={e => {
                const next = [...value];
                next[i] = e.target.value;
                onChange(next);
              }}
              className={inputCls}
              placeholder={placeholder}
            />
            <button
              type="button"
              onClick={() => onChange(value.filter((_, j) => j !== i))}
              className="rounded-lg px-2 text-red-500 hover:bg-red-50 hover:text-red-700 dark:hover:bg-red-950/30"
              title="Remove command"
            >
              <X size={16} />
            </button>
          </div>
        ))}
        <button
          type="button"
          onClick={() => onChange([...value, ""])}
          className="inline-flex items-center gap-1 text-sm text-blue-600 hover:underline dark:text-blue-400"
        >
          <Plus size={14} /> Add command
        </button>
      </div>
    </Field>
  );
}

const PREINSTALL_OPTIONS: { value: string; label: string }[] = [
  { value: "docker", label: "Docker + Compose" },
  { value: "node", label: "Node.js" },
  { value: "python", label: "Python" },
  { value: "go", label: "Go" },
  { value: "lua", label: "Lua" },
  { value: "build-essential", label: "Build tools" },
];

const CONFIGURABLE_COMMANDS: { name: string; description: string }[] = [
  { name: "rebuild", description: "Rebuild the preview." },
  { name: "stop", description: "Stop and terminate the preview instance." },
  { name: "start", description: "Start a stopped or ignored preview." },
  { name: "logs", description: "Post the last 50 log lines." },
  { name: "ignore", description: "Ignore future pushes and commands for this PR." },
];

function CommandToggles({ value, onChange }: { value: string[]; onChange: (v: string[]) => void }) {
  const toggle = (name: string, enabled: boolean) => {
    if (enabled) onChange(value.filter(c => c !== name));
    else if (!value.includes(name)) onChange([...value, name]);
  };
  return (
    <div className="space-y-2">
      {CONFIGURABLE_COMMANDS.map(cmd => {
        const enabled = !value.includes(cmd.name);
        return (
          <label key={cmd.name} className="flex items-start justify-between gap-4 rounded-lg border border-gray-200 p-3 dark:border-slate-700">
            <span className="min-w-0">
              <code className="font-mono text-sm">/pp {cmd.name}</code>
              <span className="mt-1 block text-sm text-gray-500 dark:text-slate-400">{cmd.description}</span>
            </span>
            <input
              type="checkbox"
              checked={enabled}
              onChange={e => toggle(cmd.name, e.target.checked)}
              className="mt-1 h-5 w-5 rounded"
            />
          </label>
        );
      })}
      <p className="text-xs text-gray-500 dark:text-slate-400">
        <code>/pp help</code> is always enabled.
      </p>
    </div>
  );
}

function EnvVarsEditor({ value, onChange }: { value: Record<string, string>; onChange: (v: Record<string, string>) => void }) {
  const entries = Object.entries(value);
  const addEntry = () => onChange({ ...value, "": "" });
  const updateEntry = (oldKey: string, newKey: string, newVal: string) => {
    const next: Record<string, string> = {};
    for (const [k, v] of Object.entries(value)) {
      if (k === oldKey) next[newKey] = newVal;
      else next[k] = v;
    }
    onChange(next);
  };
  const removeEntry = (key: string) => {
    const next = { ...value };
    delete next[key];
    onChange(next);
  };

  return (
    <div className="space-y-2">
      {entries.length === 0 && (
        <div className="rounded-lg border border-dashed border-gray-300 px-3 py-3 text-sm text-gray-500 dark:border-slate-600 dark:text-slate-400">
          No environment variables configured.
        </div>
      )}
      {entries.map(([key, val], i) => (
        <div key={i} className="grid gap-2 sm:grid-cols-[minmax(0,1fr)_minmax(0,1fr)_auto]">
          <input
            type="text"
            value={key}
            placeholder="KEY"
            onChange={e => updateEntry(key, e.target.value, val)}
            className={`${inputCls} font-mono text-xs`}
          />
          <input
            type="password"
            value={val}
            placeholder="value"
            onChange={e => updateEntry(key, key, e.target.value)}
            className={`${inputCls} font-mono text-xs`}
          />
          <button
            type="button"
            onClick={() => removeEntry(key)}
            className="rounded-lg px-2 text-red-500 hover:bg-red-50 hover:text-red-700 dark:hover:bg-red-950/30"
            title="Remove variable"
          >
            <X size={16} />
          </button>
        </div>
      ))}
      <button
        type="button"
        onClick={addEntry}
        className="inline-flex items-center gap-1 text-sm text-blue-600 hover:underline dark:text-blue-400"
      >
        <Plus size={14} /> Add variable
      </button>
    </div>
  );
}

const labelCls = "block text-xs font-medium text-gray-600 dark:text-slate-300 mb-1.5";
const inputCls = "w-full px-3 py-2 text-sm border border-gray-300 dark:border-slate-600 rounded-lg bg-white dark:bg-slate-700 focus:outline-none focus:ring-2 focus:ring-blue-500";
