import React, { useEffect, useState } from "react";
import { useParams, useNavigate, Link } from "react-router-dom";
import { api } from "../services/api";
import { toast } from "react-toastify";
import { ArrowLeft, X, Plus } from "lucide-react";
import { DEFAULT_INSTANCE_TYPE, INSTANCE_TYPES, isPresetInstanceType, normalizeInstanceType } from "../lib/instanceTypes";
import { usePageTitle } from "../hooks/usePageTitle";

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

function normalizeConfig(raw: any) {
  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<any>(defaultConfig());
  const [aptPackagesInput, setAptPackagesInput] = useState("");
  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) {
        // No config saved yet — start from defaults.
        setConfig(defaultConfig());
        setAptPackagesInput("");
      } else {
        toast.error(res.message || "Failed to load config");
      }
      setLoading(false);
    })();
    return () => { active = false; };
  }, [owner, repo]);

  const update = (field: string, value: any) => {
    setConfig((prev: any) => ({ ...prev, [field]: value }));
  };

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

  const setDockerCompose = (checked: boolean) => {
    setConfig((prev: any) => {
      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 res = await api.repos.saveConfig({
      owner,
      repo,
      ...config,
      aptPackages: parseAptPackages(aptPackagesInput),
    });
    setSaving(false);
    if (res.ok) {
      toast.success("Config saved");
    } else {
      toast.error(res.message || "Failed to save config");
    }
  };

  if (loading) {
    return (
      <div className="max-w-3xl space-y-3">
        <div className="h-8 w-64 bg-gray-100 dark:bg-slate-800 rounded animate-pulse" />
        {[...Array(4)].map((_, i) => <div key={i} className="h-16 bg-gray-100 dark:bg-slate-800 rounded-xl animate-pulse" />)}
      </div>
    );
  }

  return (
    <div className="max-w-3xl space-y-4">
      <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} /> Back to Repos</Link>
      </div>

      <div className="flex items-center justify-between">
        <div>
          <h1 className="text-2xl font-bold">Configure Repo</h1>
          <p className="text-sm text-gray-500 dark:text-slate-400 font-mono">{owner}/{repo}</p>
        </div>
      </div>

      <div className="bg-white dark:bg-slate-800 border border-gray-200 dark:border-slate-700 rounded-xl p-4 space-y-4">
        <div className="grid grid-cols-2 gap-4">
          <div>
            <label className={labelCls}>Instance Type</label>
            <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-1`}
                onChange={e => update("instanceType", normalizeInstanceType(e.target.value, ""))} />
            )}
          </div>
          <div>
            <label className={labelCls}>App Port (default: 3000)</label>
            <input type="number" value={config.port} onChange={e => update("port", Number(e.target.value))} className={inputCls} min={1} max={65535} />
          </div>
        </div>

        <div>
          <label className={labelCls}>Inactivity Kill Timer: {config.inactivityHours}h</label>
          <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 mt-1" />
          <div className="flex justify-between text-xs text-gray-400 mt-1">
            <span>0.5h</span><span>12h</span><span>72h</span>
          </div>
        </div>

        <div>
          <label className={labelCls}>Deny List (comma-separated usernames)</label>
          <input type="text"
            value={config.denyList.join(", ")}
            onChange={e => update("denyList", e.target.value.split(",").map((s: string) => s.trim()).filter(Boolean))}
            className={inputCls}
            placeholder="dependabot, renovate-bot"
          />
        </div>

        <div>
          <label className={labelCls}>Preinstall Options</label>
          <div className="grid grid-cols-2 gap-2 sm:grid-cols-3">
            {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 items-center gap-2 rounded-lg border border-gray-200 dark:border-slate-700 px-3 py-2 text-sm">
                  <input
                    type="checkbox"
                    checked={checked}
                    disabled={locked}
                    onChange={e => togglePreinstall(option.value, e.target.checked)}
                    className="rounded"
                  />
                  <span>{option.label}</span>
                </label>
              );
            })}
          </div>
          {(config.preinstallTools || []).includes("node") && (
            <div className="mt-3">
              <label className={labelCls}>Node Version</label>
              <input type="text"
                value={config.nodeVersion || "lts/*"}
                onChange={e => update("nodeVersion", e.target.value)}
                className={inputCls}
                placeholder="lts/*, 22, 20.11.1"
              />
            </div>
          )}
        </div>

        <div>
          <label className={labelCls}>Additional Apt Packages (space-separated)</label>
          <input type="text"
            value={aptPackagesInput}
            onChange={e => {
              setAptPackagesInput(e.target.value);
              update("aptPackages", parseAptPackages(e.target.value));
            }}
            className={inputCls}
            placeholder="ffmpeg libpq-dev"
          />
        </div>

        <div>
          <div className="flex items-center gap-2 mb-2">
            <input type="checkbox" id="compose" checked={config.useDockerCompose}
              onChange={e => setDockerCompose(e.target.checked)} className="rounded" />
            <label htmlFor="compose" className="text-sm font-medium">Use Docker Compose</label>
          </div>

          {config.useDockerCompose ? (
            <div>
              <label className={labelCls}>Compose File Path</label>
              <input type="text" value={config.composeFilePath || "docker-compose.yml"}
                onChange={e => update("composeFilePath", e.target.value)}
                className={inputCls} placeholder="docker-compose.yml" />
            </div>
          ) : (
            <div className="space-y-3">
              <CommandList label="Build Commands" value={config.buildCommands}
                onChange={v => update("buildCommands", v)} />
              <CommandList label="Post-Build Commands (optional)" value={config.postBuildCommands}
                onChange={v => update("postBuildCommands", v)} />
              <div>
                <label className={labelCls}>Run Command</label>
                <input type="text" value={config.runCommand || ""}
                  onChange={e => update("runCommand", e.target.value)}
                  className={inputCls} placeholder="python app.py, ./server, pnpm start" />
              </div>
            </div>
          )}
        </div>

        <CommandList label="Setup Commands (run once on first provision)"
          value={config.setupCommands}
          onChange={v => update("setupCommands", v)} />

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

        <CommandToggles value={config.disabledCommands || []}
          onChange={v => update("disabledCommands", v)} />

        <div className="flex justify-end gap-2">
          <button
            onClick={() => navigate("/repos")}
            className="px-5 py-2 border border-gray-300 dark:border-slate-600 rounded-lg text-sm font-medium hover:bg-gray-50 dark:hover:bg-slate-700 transition-colors"
          >
            Cancel
          </button>
          <button
            onClick={handleSave}
            disabled={saving}
            className="px-5 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-lg text-sm font-medium transition-colors disabled:opacity-50"
          >
            {saving ? "Saving..." : "Save Config"}
          </button>
        </div>
      </div>
    </div>
  );
}

function CommandList({ label, value, onChange }: { label: string; value: string[]; onChange: (v: string[]) => void }) {
  return (
    <div>
      <label className={labelCls}>{label}</label>
      <div className="space-y-1">
        {value.map((cmd, i) => (
          <div key={i} className="flex gap-2">
            <input type="text" value={cmd}
              onChange={e => { const n = [...value]; n[i] = e.target.value; onChange(n); }}
              className={inputCls} placeholder="make build" />
            <button onClick={() => onChange(value.filter((_, j) => j !== i))} className="text-red-500 hover:text-red-700 px-2"><X size={16} /></button>
          </div>
        ))}
        <button onClick={() => onChange([...value, ""])} className="inline-flex items-center gap-1 text-sm text-blue-600 dark:text-blue-400 hover:underline">
          <Plus size={14} /> Add command
        </button>
      </div>
    </div>
  );
}

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" },
];

// Configurable `/pp` commands. `help` is intentionally omitted — it can never be
// disabled so reviewers always have a way to discover command state.
const CONFIGURABLE_COMMANDS: { name: string; description: string }[] = [
  { name: "rebuild", description: "Rebuild the preview (reuse instance, or re-provision if stopped)." },
  { name: "stop", description: "Stop and terminate the preview instance." },
  { name: "start", description: "Start a stopped/ignored preview, or create one." },
  { name: "logs", description: "Post the last 50 lines of logs as a comment." },
  { name: "ignore", description: "Ignore this PR — skip future pushes and commands." },
];

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>
      <label className={labelCls}>PR Comment Commands</label>
      <p className="text-xs text-gray-400 dark:text-slate-500 mb-2">
        Control which <code>/pp</code> commands reviewers can run from PR comments. <code>/pp help</code> is always available.
      </p>
      <div className="space-y-1">
        {CONFIGURABLE_COMMANDS.map(cmd => {
          const enabled = !value.includes(cmd.name);
          return (
            <label key={cmd.name} className="flex items-start gap-2 py-1 cursor-pointer">
              <input type="checkbox" checked={enabled}
                onChange={e => toggle(cmd.name, e.target.checked)}
                className="rounded mt-0.5" />
              <span className="text-sm">
                <code className="font-mono">/pp {cmd.name}</code>
                <span className="text-gray-500 dark:text-slate-400"> — {cmd.description}</span>
              </span>
            </label>
          );
        })}
      </div>
    </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 = (k: string) => {
    const next = { ...value };
    delete next[k];
    onChange(next);
  };

  return (
    <div>
      <label className={labelCls}>Environment Variables</label>
      <div className="space-y-1">
        {entries.map(([k, v], i) => (
          <div key={i} className="flex gap-2">
            <input type="text" value={k} placeholder="KEY"
              onChange={e => updateEntry(k, e.target.value, v)}
              className={`${inputCls} flex-1 min-w-0 font-mono text-xs`} />
            <input type="password" value={v} placeholder="value"
              onChange={e => updateEntry(k, k, e.target.value)}
              className={`${inputCls} flex-1 min-w-0 font-mono text-xs`} />
            <button onClick={() => removeEntry(k)} className="text-red-500 hover:text-red-700 px-2"><X size={16} /></button>
          </div>
        ))}
        <button onClick={addEntry} className="inline-flex items-center gap-1 text-sm text-blue-600 dark:text-blue-400 hover:underline">
          <Plus size={14} /> Add variable
        </button>
      </div>
    </div>
  );
}

const labelCls = "block text-xs font-medium text-gray-600 dark:text-slate-300 mb-1";
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";
