/**
 * @file AddLaneModal.tsx
 * @description The "+ Add lane" flow: pick a SOURCE repo (not a folder to
 * adopt), pick which of its branches to fork from, name the feature, and the
 * dashboard provisions a managed git worktree via `POST /api/lanes/worktree`
 * — the dashboard invents the lane's own directory and branch name, the same
 * way Shipyard's "+ Add lane" never asks a human to name a folder. The lane
 * returned is `status: "provisioning"`; the existing `lane_update` WebSocket
 * subscription in the Workspace page flips it to idle when the worktree is
 * actually ready, so this component does not poll.
 * @author Nguyễn Ngọc Trí Vĩ <vinnt@smartgift.vn>
 */

import { useCallback, useEffect, useRef, useState } from "react";
import { useTranslation } from "react-i18next";
import { ConfirmModal } from "../ConfirmModal";
import { CwdAutocomplete } from "../run/RunSetup";
import { api } from "../../lib/api";
import type { CwdSuggestion } from "../../lib/api";
import type { Lane } from "../../lib/types";

export function AddLaneModal({
  open,
  onClose,
  onAdded,
  cwdSuggestions,
}: {
  open: boolean;
  onClose: () => void;
  /** Called with the newly provisioned (still-provisioning) lane. */
  onAdded: (lane: Lane) => void;
  /** The same suggestion list the Run form already fetched (dashboard cwd,
   *  home, recently-used paths) — reused rather than fetched a second time. */
  cwdSuggestions: CwdSuggestion[];
}) {
  const { t } = useTranslation(["lanes"]);
  const [sourceRepo, setSourceRepo] = useState("");
  const [title, setTitle] = useState("");
  const [branches, setBranches] = useState<string[] | null>(null);
  const [base, setBase] = useState("");
  const [branchesError, setBranchesError] = useState<string | null>(null);
  const [busy, setBusy] = useState(false);
  const [error, setError] = useState<string | null>(null);

  const reset = () => {
    setSourceRepo("");
    setTitle("");
    setBranches(null);
    setBase("");
    setBranchesError(null);
    setError(null);
    setBusy(false);
  };

  // Look up the repo's branches once the path settles - debounced so every
  // keystroke while typing a path doesn't fire a request against a path that
  // isn't finished yet.
  const lookedUpFor = useRef<string>("");
  useEffect(() => {
    const path = sourceRepo.trim();
    if (!path) {
      setBranches(null);
      setBase("");
      setBranchesError(null);
      return;
    }
    const timer = window.setTimeout(async () => {
      lookedUpFor.current = path;
      try {
        const r = await api.lanes.branches(path);
        if (lookedUpFor.current !== path) return; // a newer path superseded this one
        setBranches(r.branches);
        setBase(r.current || r.branches[0] || "");
        setBranchesError(null);
      } catch {
        if (lookedUpFor.current !== path) return;
        // Not yet a valid repo path (still being typed, or genuinely wrong) -
        // quiet by design, the same way CwdAutocomplete never errors either.
        setBranches(null);
        setBase("");
        setBranchesError(t("addLaneNotARepo"));
      }
    }, 300);
    return () => window.clearTimeout(timer);
  }, [sourceRepo, t]);

  const submit = async () => {
    const repo = sourceRepo.trim();
    const name = title.trim();
    if (!repo || !branches || !name) return;
    setBusy(true);
    setError(null);
    try {
      const result = await api.lanes.worktree({
        sourceRepo: repo,
        title: name,
        base: base || undefined,
      });
      reset();
      onAdded(result.lane);
      onClose();
    } catch (err) {
      setError(err instanceof Error ? err.message : String(err));
      setBusy(false);
    }
  };

  // ConfirmModal re-focuses its Cancel button in an effect keyed on `onCancel`'s
  // identity. Every keystroke in the fields below re-renders this component; an
  // inline `() => {...}` handed to `onCancel` would get a new identity each
  // time, re-running that effect and yanking focus off the field being typed
  // into after the very first character. useCallback keeps the identity stable
  // across renders so only mount/unmount (and a real onClose change) refocuses.
  const handleCancel = useCallback(() => {
    reset();
    onClose();
  }, [onClose]);

  return (
    <ConfirmModal
      open={open}
      title={t("addLane")}
      confirmLabel={t("add")}
      cancelLabel={t("destructive.cancel")}
      destructive={false}
      busy={busy}
      disabled={!sourceRepo.trim() || !title.trim() || !branches}
      onConfirm={submit}
      onCancel={handleCancel}
    >
      <div className="space-y-3">
        <div>
          <label className="mb-1 block text-xs text-fg-secondary" htmlFor="add-lane-repo">
            {t("addLaneRepoLabel")}
          </label>
          <CwdAutocomplete
            inputId="add-lane-repo"
            value={sourceRepo}
            onChange={setSourceRepo}
            suggestions={cwdSuggestions}
          />
          <p className="mt-1 text-[10px] text-fg-muted">{t("addLaneRepoHint")}</p>
        </div>

        <div>
          <label className="mb-1 block text-xs text-fg-secondary" htmlFor="add-lane-title">
            {t("addLaneTitleLabel")}
          </label>
          <input
            id="add-lane-title"
            value={title}
            onChange={(e) => setTitle(e.target.value)}
            placeholder={t("addLaneTitlePlaceholder")}
            className="w-full rounded-md border border-border-light bg-surface-0 px-3 py-1.5 text-xs text-fg-primary placeholder:text-fg-muted focus:border-blue-500 focus:outline-none"
          />
        </div>

        {branches && (
          <div>
            <label className="mb-1 block text-xs text-fg-secondary" htmlFor="add-lane-base">
              {t("addLaneBaseLabel")}
            </label>
            {branches.length === 0 ? (
              <p className="text-[10px] text-fg-muted">{t("addLaneNoBranches")}</p>
            ) : (
              <select
                id="add-lane-base"
                value={base}
                onChange={(e) => setBase(e.target.value)}
                className="w-full rounded-md border border-border-light bg-surface-0 px-3 py-1.5 text-xs text-fg-primary focus:border-blue-500 focus:outline-none"
              >
                {branches.map((b) => (
                  <option key={b} value={b}>
                    {b}
                  </option>
                ))}
              </select>
            )}
          </div>
        )}
        {branchesError && !branches && (
          <p className="text-[10px] text-status-warning">{branchesError}</p>
        )}

        {error && (
          <p role="alert" className="text-xs text-status-danger">
            {error}
          </p>
        )}
      </div>
    </ConfirmModal>
  );
}
