"use client";

import { useEffect, useRef, useState } from "react";
import { ChevronDown, ChevronUp } from "lucide-react";
import { InfoBubble } from "@/components/InfoBubble";
import { formatChf, parseChfInput } from "@/lib/format";

const baseInputClass =
  "w-full rounded-lg border border-border bg-input px-2.5 py-1.5 text-sm text-fg shadow-sm transition-colors focus:border-accent focus:outline-none focus:ring-2 focus:ring-accent/25";

export function FieldLabel({ label, help }: { label: string; help?: string }) {
  return (
    <label className="mb-1 flex items-center text-xs font-medium text-muted">
      {label}
      {help && <InfoBubble text={help} />}
    </label>
  );
}

export function NumberField({
  label,
  help,
  value,
  onChange,
  step,
  min,
  max,
}: {
  label: string;
  help?: string;
  value: number;
  onChange: (value: number) => void;
  step?: number;
  min?: number;
  max?: number;
}) {
  return (
    <div>
      <FieldLabel label={label} help={help} />
      <input
        type="number"
        className={baseInputClass}
        value={Number.isFinite(value) ? value : 0}
        step={step ?? "any"}
        min={min}
        max={max}
        onFocus={(e) => e.currentTarget.select()}
        onChange={(e) => onChange(e.target.valueAsNumber || 0)}
      />
    </div>
  );
}

// Pflicht-Zahlenfeld, das wirklich LEER sein kann (NumberField erzwingt eine Zahl und hätte
// damit immer einen Default -- genau das soll bei Annahmen vermieden werden, siehe
// SPEZIFIKATION 9.15/9.18: ein stiller Default wird nicht hinterfragt). Der Wert wird als
// String geführt; die Validierung liegt beim Aufrufer.
export function RequiredNumberField({
  label,
  help,
  value,
  onChange,
  step = 0.1,
  suffix,
  placeholder = "Pflicht",
}: {
  label: string;
  help?: string;
  value: string;
  onChange: (value: string) => void;
  step?: number;
  suffix?: string;
  placeholder?: string;
}) {
  const empty = value.trim() === "";
  return (
    <div>
      <FieldLabel label={label} help={help} />
      <div className="relative">
        <input
          type="number"
          step={step}
          value={value}
          placeholder={placeholder}
          onChange={(e) => onChange(e.target.value)}
          className={`${baseInputClass} ${suffix ? "pr-8" : ""} ${
            empty ? "border-danger focus:border-danger" : ""
          }`}
        />
        {suffix && (
          <span className="pointer-events-none absolute inset-y-0 right-2.5 flex items-center text-xs text-faint">
            {suffix}
          </span>
        )}
      </div>
      {empty && <p className="mt-1 text-[11px] text-danger">Pflichtfeld – bitte ausfüllen.</p>}
    </div>
  );
}

// Ganzzahliges Betragsfeld. Zeigt den Wert unfokussiert mit 1'000er-Trennzeichen an,
// akzeptiert fokussiert beliebige ganze Zahlen (keine Nachkommastellen) und bietet
// Pfeil-Buttons mit Klick-und-Halten-BESCHLEUNIGUNG (1 -> 10 -> 100 -> 1'000 -> ...).
// Optionales `max` (und `min`) klammern die Eingabe hart (Live-Cap).
export function MoneyInput({
  value,
  onChange,
  className,
  min = 0,
  max,
}: {
  value: number;
  onChange: (value: number) => void;
  className?: string;
  min?: number;
  max?: number;
}) {
  const [focused, setFocused] = useState(false);
  const [text, setText] = useState(() => String(Math.round(value || 0)));
  const valueRef = useRef(value);
  const inputRef = useRef<HTMLInputElement | null>(null);
  useEffect(() => {
    valueRef.current = value;
  }, [value]);
  const holdTimeout = useRef<ReturnType<typeof setTimeout> | null>(null);
  const holdInterval = useRef<ReturnType<typeof setInterval> | null>(null);

  function clamp(v: number): number {
    let result = Math.round(v);
    if (min != null) result = Math.max(min, result);
    if (max != null) result = Math.min(result, Math.round(max));
    return result;
  }

  function stepBy(delta: number) {
    onChange(clamp(Math.round(valueRef.current) + delta));
  }

  function stopHold() {
    if (holdTimeout.current) {
      clearTimeout(holdTimeout.current);
      holdTimeout.current = null;
    }
    if (holdInterval.current) {
      clearInterval(holdInterval.current);
      holdInterval.current = null;
    }
  }

  // Klick = 1 Schritt. Halten: nach 400 ms Wiederholung im 70-ms-Takt, wobei die
  // Schrittweite mit der Haltedauer wächst (immer schneller).
  function startHold(sign: number) {
    stepBy(sign);
    const start = Date.now();
    holdTimeout.current = setTimeout(() => {
      holdInterval.current = setInterval(() => {
        const s = (Date.now() - start) / 1000;
        const mag = s < 1.5 ? 1 : s < 3 ? 10 : s < 4.5 ? 100 : s < 6 ? 1000 : 10000;
        stepBy(sign * mag);
      }, 70);
    }, 400);
  }

  useEffect(() => stopHold, []);

  const arrowBtn =
    "flex flex-1 items-center justify-center text-faint hover:bg-accent-soft hover:text-accent-soft-fg";

  return (
    <div className={`relative ${className ?? "w-full"}`}>
      <input
        ref={inputRef}
        type="text"
        inputMode="numeric"
        className={`${baseInputClass} w-full pr-6`}
        value={focused ? text : formatChf(value)}
        onFocus={() => {
          setFocused(true);
          const current = Math.round(value || 0);
          // Default-0 sofort leeren; sonst Wert markieren, damit man ihn überschreiben kann.
          setText(current === 0 ? "" : String(current));
          requestAnimationFrame(() => inputRef.current?.select());
        }}
        onChange={(e) => setText(e.target.value.replace(min < 0 ? /[^0-9-]/g : /[^0-9]/g, ""))}
        onKeyDown={(e) => {
          if (e.key === "ArrowUp") {
            e.preventDefault();
            stepBy(e.shiftKey ? 100 : 1);
          } else if (e.key === "ArrowDown") {
            e.preventDefault();
            stepBy(e.shiftKey ? -100 : -1);
          }
        }}
        onBlur={() => {
          setFocused(false);
          onChange(clamp(parseChfInput(text)));
        }}
      />
      <div className="absolute inset-y-0 right-0 flex w-6 flex-col overflow-hidden rounded-r-lg border-l border-border">
        <button
          type="button"
          tabIndex={-1}
          aria-label="Erhöhen"
          onMouseDown={(e) => {
            e.preventDefault();
            startHold(1);
          }}
          onMouseUp={stopHold}
          onMouseLeave={stopHold}
          onTouchStart={(e) => {
            e.preventDefault();
            startHold(1);
          }}
          onTouchEnd={stopHold}
          className={arrowBtn}
        >
          <ChevronUp className="h-3 w-3" />
        </button>
        <button
          type="button"
          tabIndex={-1}
          aria-label="Verringern"
          onMouseDown={(e) => {
            e.preventDefault();
            startHold(-1);
          }}
          onMouseUp={stopHold}
          onMouseLeave={stopHold}
          onTouchStart={(e) => {
            e.preventDefault();
            startHold(-1);
          }}
          onTouchEnd={stopHold}
          className={`${arrowBtn} border-t border-border`}
        >
          <ChevronDown className="h-3 w-3" />
        </button>
      </div>
    </div>
  );
}

export function MoneyField({
  label,
  help,
  value,
  onChange,
  min,
  max,
}: {
  label: string;
  help?: string;
  value: number;
  onChange: (value: number) => void;
  min?: number;
  max?: number;
}) {
  return (
    <div>
      <FieldLabel label={label} help={help} />
      <MoneyInput value={value} onChange={onChange} min={min} max={max} />
    </div>
  );
}

export function TextField({
  label,
  help,
  value,
  onChange,
  placeholder,
}: {
  label: string;
  help?: string;
  value: string;
  onChange: (value: string) => void;
  placeholder?: string;
}) {
  return (
    <div>
      <FieldLabel label={label} help={help} />
      <input
        type="text"
        className={baseInputClass}
        value={value}
        placeholder={placeholder}
        onChange={(e) => onChange(e.target.value)}
      />
    </div>
  );
}

export function SelectField<T extends string>({
  label,
  help,
  value,
  onChange,
  options,
}: {
  label: string;
  help?: string;
  value: T;
  onChange: (value: T) => void;
  options: { value: T; label: string }[];
}) {
  return (
    <div>
      <FieldLabel label={label} help={help} />
      <select
        className={baseInputClass}
        value={value}
        onChange={(e) => onChange(e.target.value as T)}
      >
        {options.map((o) => (
          <option key={o.value} value={o.value}>
            {o.label}
          </option>
        ))}
      </select>
    </div>
  );
}

// --- "Aus Vorphase uebernehmen" (Roadmap Nr. 44, Punkt A) --------------------------------
//
// Wiederkehr-Parameter (Raten, Beitraege, Amortisation) gelten weiter, bis man sie bewusst
// aendert. Bisher war das unsichtbar: Beim Anlegen einer Phase wurde der Wert KOPIERT, und
// spaetere Aenderungen an der Vorphase kamen deshalb nie an. Jetzt entscheidet ein sichtbares
// Haekchen: angehakt = Feld leer lassen und live erben; abgehakt = eigener Wert fuer diese
// Phase. In der ersten Phase gibt es nichts zu erben -- dort erscheint das Haekchen nicht.
export function InheritableField({
  label,
  help,
  canInherit,
  isInheriting,
  inheritedDisplay,
  onToggle,
  children,
}: {
  label: string;
  help?: string;
  canInherit: boolean;
  isInheriting: boolean;
  inheritedDisplay: string;
  onToggle: (inherit: boolean) => void;
  children: React.ReactNode;
}) {
  return (
    <div>
      {isInheriting ? (
        <>
          <FieldLabel label={label} help={help} />
          <div className="w-full rounded-lg border border-dashed border-border bg-surface-2 px-2.5 py-1.5 text-sm text-muted">
            {inheritedDisplay} <span className="text-xs text-faint">(aus der Vorphase)</span>
          </div>
        </>
      ) : (
        children
      )}
      {canInherit && (
        <label className="mt-1 flex cursor-pointer items-center gap-1.5 text-xs text-muted">
          <input
            type="checkbox"
            checked={isInheriting}
            onChange={(e) => onToggle(e.target.checked)}
            className="h-3.5 w-3.5 accent-accent"
          />
          Aus Vorphase übernehmen
        </label>
      )}
    </div>
  );
}
