import { jsx, jsxs } from "react/jsx-runtime";
import { useEffect, useRef, useState } from "react";
import { Box, Text, useInput } from "ink";
import os from "node:os";
import { semantic } from "../theme/palette.js";
import { reducedMotion } from "../theme/motion-guard.js";
const SAVED_CHECK_TTL = 1500;
function displayPath(v) {
  if (typeof v !== "string" || v.length === 0) return "";
  const home = os.homedir();
  if (v === home) return "~";
  if (v.startsWith(home + "/")) return "~/" + v.slice(home.length + 1);
  return v;
}
function valuesEqual(a, b) {
  if (a === b) return true;
  return JSON.stringify(a) === JSON.stringify(b);
}
function maskedSummary(value) {
  if (typeof value !== "string" || value.length === 0) return "";
  const tail = value.slice(-4);
  return `****${tail}`;
}
function renderValue(field, value) {
  switch (field.kind) {
    case "toggle":
      return value ? "on" : "off";
    case "path":
      return displayPath(value);
    case "number":
      return value === void 0 || value === null ? "" : String(value);
    case "select": {
      return value === void 0 || value === null ? "" : String(value);
    }
    case "masked":
      return maskedSummary(value);
    case "readonly":
    case "text":
    default:
      return value === void 0 || value === null ? "" : String(value);
  }
}
function FieldRenderer(props) {
  const {
    field,
    value,
    current,
    focused,
    editing,
    onChange,
    onEditStart,
    onEditDone,
    onEditCancel,
    savedAt = null
  } = props;
  const [showCheck, setShowCheck] = useState(false);
  const checkTimerRef = useRef(null);
  useEffect(() => {
    if (savedAt === null || reducedMotion()) return;
    setShowCheck(true);
    if (checkTimerRef.current !== null) clearTimeout(checkTimerRef.current);
    checkTimerRef.current = setTimeout(() => {
      setShowCheck(false);
      checkTimerRef.current = null;
    }, SAVED_CHECK_TTL);
    return () => {
      if (checkTimerRef.current !== null) {
        clearTimeout(checkTimerRef.current);
        checkTimerRef.current = null;
      }
    };
  }, [savedAt]);
  const [buffer, setBuffer] = useState(() => {
    if (field.kind === "path") return displayPath(value);
    if (field.kind === "masked") return "";
    return value === void 0 || value === null ? "" : String(value);
  });
  const [multiBuffer, setMultiBuffer] = useState(
    () => new Set(Array.isArray(value) ? value : [])
  );
  const [multiCursor, setMultiCursor] = useState(0);
  useEffect(() => {
    if (editing && (field.kind === "text" || field.kind === "number" || field.kind === "path")) {
      if (field.kind === "path") setBuffer(displayPath(value));
      else setBuffer(value === void 0 || value === null ? "" : String(value));
    }
    if (editing && field.kind === "masked") {
      setBuffer("");
    }
    if (editing && field.kind === "multiselect") {
      setMultiBuffer(new Set(Array.isArray(value) ? value : []));
      setMultiCursor(0);
    }
  }, [editing, field.kind, value]);
  const isPending = current !== void 0 && !valuesEqual(value, current);
  useInput(
    (input, key) => {
      if (field.kind === "readonly") return;
      if (!focused) return;
      if (field.kind === "select") {
        const opts = field.options ?? [];
        if (opts.length === 0) return;
        const idx = opts.findIndex((o) => o.value === value);
        const safeIdx = idx >= 0 ? idx : 0;
        if (key.rightArrow || key.return && !editing) {
          const next = opts[(safeIdx + 1) % opts.length];
          if (next && next.value !== value) {
            onChange(next.value);
          }
          if (key.return) onEditDone();
          return;
        }
        if (key.leftArrow) {
          const prev = opts[(safeIdx - 1 + opts.length) % opts.length];
          if (prev && prev.value !== value) {
            onChange(prev.value);
          }
          return;
        }
        return;
      }
      if (field.kind === "toggle") {
        if (key.return) {
          onChange(!value);
          onEditDone();
        }
        return;
      }
      if (field.kind === "multiselect") {
        const opts = field.options ?? [];
        if (!editing) {
          if (key.return) {
            onEditStart();
          }
          return;
        }
        if (opts.length === 0) {
          if (key.return || key.escape) onEditCancel();
          return;
        }
        if (key.escape) {
          onEditCancel();
          return;
        }
        if (key.return) {
          const next = opts.map((o) => o.value).filter((v) => multiBuffer.has(v));
          onChange(next);
          onEditDone();
          return;
        }
        if (key.upArrow) {
          setMultiCursor((c) => c > 0 ? c - 1 : opts.length - 1);
          return;
        }
        if (key.downArrow) {
          setMultiCursor((c) => c < opts.length - 1 ? c + 1 : 0);
          return;
        }
        if (input === " ") {
          const cur = opts[multiCursor];
          if (!cur) return;
          setMultiBuffer((prev) => {
            const nextSet = new Set(prev);
            if (nextSet.has(cur.value)) nextSet.delete(cur.value);
            else nextSet.add(cur.value);
            return nextSet;
          });
          return;
        }
        return;
      }
      if (field.kind === "masked") {
        if (!editing) {
          if (key.return) {
            onEditStart();
            return;
          }
          const hasValue = typeof value === "string" && value.length > 0;
          if (!hasValue) return;
          if (input === "r" || input === "R") {
            onEditStart();
            return;
          }
          if (input === "x" || input === "X") {
            onChange(null);
            onEditDone();
            return;
          }
          return;
        }
        if (key.escape) {
          onEditCancel();
          return;
        }
        if (key.return) {
          if (buffer.length === 0) {
            onEditCancel();
            return;
          }
          onChange(buffer);
          onEditDone();
          return;
        }
        if (key.backspace || key.delete) {
          setBuffer((b) => b.slice(0, -1));
          return;
        }
        if (input && !key.ctrl && !key.meta) {
          setBuffer((b) => b + input);
          return;
        }
        return;
      }
      if (field.kind === "text" || field.kind === "number" || field.kind === "path") {
        if (!editing) {
          if (key.return) {
            onEditStart();
          }
          return;
        }
        if (key.escape) {
          onEditCancel();
          return;
        }
        if (key.return) {
          if (field.kind === "number") {
            const trimmed = buffer.trim();
            if (trimmed === "") {
              onEditCancel();
              return;
            }
            const parsed = Number(trimmed);
            if (!Number.isFinite(parsed)) {
              onEditCancel();
              return;
            }
            const min = field.min ?? -Infinity;
            const max = field.max ?? Infinity;
            if (parsed < min || parsed > max) {
              onEditCancel();
              return;
            }
            onChange(parsed);
            onEditDone();
            return;
          }
          let next = buffer;
          if (field.kind === "path") {
            if (next === "~") next = os.homedir();
            else if (next.startsWith("~/")) next = os.homedir() + next.slice(1);
          }
          onChange(next);
          onEditDone();
          return;
        }
        if (key.backspace || key.delete) {
          setBuffer((b) => b.slice(0, -1));
          return;
        }
        if (input && !key.ctrl && !key.meta) {
          if (field.kind === "number") {
            if (!/^[0-9.\-]$/.test(input)) return;
          }
          setBuffer((b) => b + input);
          return;
        }
      }
    },
    { isActive: focused && field.kind !== "readonly" }
  );
  const isMultiselect = field.kind === "multiselect";
  const multiOptions = isMultiselect ? field.options ?? [] : [];
  const multiSelectedSet = isMultiselect ? editing ? multiBuffer : new Set(Array.isArray(value) ? value : []) : /* @__PURE__ */ new Set();
  const display = (() => {
    if (editing && (field.kind === "text" || field.kind === "number" || field.kind === "path")) {
      return buffer;
    }
    if (editing && field.kind === "masked") {
      return "*".repeat(buffer.length);
    }
    if (field.kind === "masked") {
      const hasValue = typeof value === "string" && value.length > 0;
      if (!hasValue) return "[type to enter]";
      return renderValue(field, value);
    }
    if (isMultiselect) {
      const arr = Array.isArray(value) ? value : [];
      if (arr.length === 0) return "(none)";
      return arr.join(", ");
    }
    return renderValue(field, value);
  })();
  const labelText = field.label;
  const valueColor = isPending ? semantic.warn : void 0;
  const pendingMarker = isPending ? " *" : "";
  const maskedHasValue = field.kind === "masked" && typeof value === "string" && value.length > 0;
  const showMaskedHotkeys = field.kind === "masked" && !editing && maskedHasValue && focused;
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
    /* @__PURE__ */ jsx(Box, { flexDirection: "row", children: /* @__PURE__ */ jsxs(Text, { children: [
      focused ? /* @__PURE__ */ jsx(Text, { color: semantic.accent, children: "\u276F " }) : "  ",
      /* @__PURE__ */ jsx(Text, { bold: focused, inverse: focused && !editing, children: labelText }),
      /* @__PURE__ */ jsx(Text, { children: "  " }),
      editing && (field.kind === "text" || field.kind === "number" || field.kind === "path" || field.kind === "masked") ? /* @__PURE__ */ jsxs(Text, { color: semantic.accent, children: [
        display,
        /* @__PURE__ */ jsx(Text, { color: semantic.accent, inverse: true, children: " " })
      ] }) : /* @__PURE__ */ jsxs(Text, { color: valueColor, children: [
        display,
        pendingMarker
      ] }),
      showMaskedHotkeys && /* @__PURE__ */ jsx(Text, { dimColor: true, children: "   [r] Replace [x] Remove" }),
      showCheck && /* @__PURE__ */ jsx(Text, { color: semantic.accent, children: "  \u2713" })
    ] }) }),
    isMultiselect && /* @__PURE__ */ jsx(Box, { flexDirection: "column", paddingLeft: 4, children: multiOptions.map((opt, idx) => {
      const checked = multiSelectedSet.has(opt.value);
      const rowFocused = editing && idx === multiCursor;
      return /* @__PURE__ */ jsx(Box, { flexDirection: "row", children: /* @__PURE__ */ jsxs(Text, { children: [
        rowFocused ? /* @__PURE__ */ jsx(Text, { color: semantic.accent, children: "\u276F " }) : "  ",
        checked ? /* @__PURE__ */ jsx(Text, { color: semantic.ok, children: "[x] " }) : /* @__PURE__ */ jsx(Text, { dimColor: true, children: "[ ] " }),
        /* @__PURE__ */ jsx(Text, { bold: rowFocused, children: opt.label }),
        opt.hint ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
          "   ",
          opt.hint
        ] }) : null
      ] }) }, opt.value);
    }) }),
    field.help && /* @__PURE__ */ jsx(Box, { paddingLeft: 4, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: field.help }) }),
    field.futureNote && /* @__PURE__ */ jsx(Box, { paddingLeft: 4, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: field.futureNote }) })
  ] });
}
export {
  FieldRenderer
};
//# sourceMappingURL=FieldRenderer.js.map