"use client";

import { useState, useRef, useEffect, useMemo, useCallback } from "react";
import { Search, Plus, X, Dumbbell } from "lucide-react";
import { Exercise } from "@prisma/client";
import { scoreExercise } from "@/lib/exerciseSearch";

const MUSCLE_GROUPS = [
  "Chest",
  "Back",
  "Shoulders",
  "Quads",
  "Hamstrings",
  "Glutes",
  "Biceps",
  "Triceps",
  "Forearms",
  "Core",
  "Calves",
  "Full Body",
  "Cardio",
];

const EXERCISE_TYPES = [
  { value: "barbell", label: "Barbell" },
  { value: "dumbbell", label: "Dumbbell" },
  { value: "machine", label: "Machine" },
  { value: "cable", label: "Cable" },
  { value: "bodyweight", label: "Bodyweight" },
  { value: "cardio", label: "Cardio" },
  { value: "kettlebell", label: "Kettlebell" },
  { value: "other", label: "Other" },
];

interface ExercisePickerProps {
  exercises: Exercise[];
  recentlyUsed?: string[];
  onSelect: (exercise: Exercise) => void;
  onExerciseCreated?: (exercise: Exercise) => void;
}

// Search utilities imported from shared module

export default function ExercisePicker({
  exercises,
  recentlyUsed = [],
  onSelect,
  onExerciseCreated,
}: ExercisePickerProps) {
  const [query, setQuery] = useState("");
  const [isOpen, setIsOpen] = useState(false);
  const [highlightIndex, setHighlightIndex] = useState(0);
  const [showCreateForm, setShowCreateForm] = useState(false);
  const [creating, setCreating] = useState(false);

  const [newName, setNewName] = useState("");
  const [newType, setNewType] = useState("barbell");
  const [newMuscleGroups, setNewMuscleGroups] = useState<string[]>([]);
  const [newInputFields, setNewInputFields] = useState<string[]>(["sets", "reps", "weight"]);

  // Derive custom types/muscles/fields from existing exercises
  const knownTypeValues = EXERCISE_TYPES.map((t) => t.value);
  const knownMuscleValues = MUSCLE_GROUPS.map((g) => g.toLowerCase());
  const knownFieldValues = ["sets", "reps", "weight", "duration", "distance", "calories", "notes"];

  const derivedCustomTypes = useMemo(() => {
    const set = new Set<string>();
    for (const ex of exercises) {
      const t = (ex.type || "").toLowerCase();
      if (t && !knownTypeValues.includes(t)) set.add(t);
    }
    return Array.from(set).map((v) => ({ value: v, label: v.charAt(0).toUpperCase() + v.slice(1) }));
  }, [exercises]);

  const derivedCustomMuscles = useMemo(() => {
    const set = new Set<string>();
    for (const ex of exercises) {
      try {
        const groups = JSON.parse(ex.muscleGroups || "[]") as string[];
        groups.forEach((g) => {
          const gl = g.toLowerCase();
          if (!knownMuscleValues.includes(gl)) set.add(g.charAt(0).toUpperCase() + g.slice(1).toLowerCase());
        });
      } catch {}
    }
    return Array.from(set);
  }, [exercises]);

  const derivedCustomFields = useMemo(() => {
    const set = new Set<string>();
    for (const ex of exercises) {
      try {
        const fields = JSON.parse((ex as any).inputFields || "[]") as string[];
        fields.forEach((f) => { if (!knownFieldValues.includes(f)) set.add(f); });
      } catch {}
    }
    return Array.from(set).map((v) => ({ value: v, label: v.charAt(0).toUpperCase() + v.slice(1) }));
  }, [exercises]);

  // Custom "+" add state (session-only additions on top of derived)
  const [addingType, setAddingType] = useState(false);
  const [newTypeText, setNewTypeText] = useState("");
  const [sessionCustomTypes, setSessionCustomTypes] = useState<{ value: string; label: string }[]>([]);
  const [addingMuscle, setAddingMuscle] = useState(false);
  const [newMuscleText, setNewMuscleText] = useState("");
  const [sessionCustomMuscles, setSessionCustomMuscles] = useState<string[]>([]);
  const [addingField, setAddingField] = useState(false);
  const [newFieldText, setNewFieldText] = useState("");
  const [sessionCustomFields, setSessionCustomFields] = useState<{ value: string; label: string }[]>([]);

  // Merge derived + session-added
  const customTypes = useMemo(() => {
    const all = [...derivedCustomTypes];
    for (const t of sessionCustomTypes) {
      if (!all.some((a) => a.value === t.value)) all.push(t);
    }
    return all;
  }, [derivedCustomTypes, sessionCustomTypes]);

  const customMuscles = useMemo(() => {
    const all = [...derivedCustomMuscles];
    for (const m of sessionCustomMuscles) {
      if (!all.map((a) => a.toLowerCase()).includes(m.toLowerCase())) all.push(m);
    }
    return all;
  }, [derivedCustomMuscles, sessionCustomMuscles]);

  const customFieldOptions = useMemo(() => {
    const all = [...derivedCustomFields];
    for (const f of sessionCustomFields) {
      if (!all.some((a) => a.value === f.value)) all.push(f);
    }
    return all;
  }, [derivedCustomFields, sessionCustomFields]);

  const inputRef = useRef<HTMLInputElement>(null);
  const dropdownRef = useRef<HTMLDivElement>(null);
  const containerRef = useRef<HTMLDivElement>(null);

  const filteredExercises = useMemo(() => {
    if (!query.trim()) {
      const recent = exercises.filter((ex) => recentlyUsed.includes(ex.id));
      const others = exercises
        .filter((ex) => !recentlyUsed.includes(ex.id))
        .sort((a, b) => a.name.localeCompare(b.name));
      return [...recent, ...others].slice(0, 15);
    }

    const scored = exercises
      .map((ex) => ({ exercise: ex, score: scoreExercise(query, ex.name) }))
      .filter((item) => item.score >= 0)
      .sort((a, b) => a.score - b.score);

    return scored.map((s) => s.exercise).slice(0, 10);
  }, [exercises, query, recentlyUsed]);

  const exactMatch = exercises.some(
    (ex) => ex.name.toLowerCase() === query.trim().toLowerCase()
  );
  const showCreateOption = query.trim().length > 0 && !exactMatch;
  const totalItems = filteredExercises.length + (showCreateOption ? 1 : 0);

  useEffect(() => {
    setHighlightIndex(0);
  }, [query]);

  useEffect(() => {
    function handleClickOutside(e: MouseEvent) {
      if (
        containerRef.current &&
        !containerRef.current.contains(e.target as Node)
      ) {
        setIsOpen(false);
      }
    }
    document.addEventListener("mousedown", handleClickOutside);
    return () => document.removeEventListener("mousedown", handleClickOutside);
  }, []);

  useEffect(() => {
    if (dropdownRef.current) {
      const highlighted = dropdownRef.current.querySelector(
        '[data-highlighted="true"]'
      );
      if (highlighted) {
        highlighted.scrollIntoView({ block: "nearest" });
      }
    }
  }, [highlightIndex]);

  const handleKeyDown = useCallback(
    (e: React.KeyboardEvent) => {
      if (!isOpen) {
        if (e.key === "ArrowDown" || e.key === "Enter") {
          setIsOpen(true);
          e.preventDefault();
        }
        return;
      }

      switch (e.key) {
        case "ArrowDown":
          e.preventDefault();
          setHighlightIndex((prev) => Math.min(prev + 1, totalItems - 1));
          break;
        case "ArrowUp":
          e.preventDefault();
          setHighlightIndex((prev) => Math.max(prev - 1, 0));
          break;
        case "Enter":
          e.preventDefault();
          if (highlightIndex < filteredExercises.length) {
            handleSelect(filteredExercises[highlightIndex]);
          } else if (showCreateOption) {
            openCreateForm();
          }
          break;
        case "Escape":
          setIsOpen(false);
          inputRef.current?.blur();
          break;
      }
    },
    [isOpen, highlightIndex, filteredExercises, totalItems, showCreateOption]
  );

  const handleSelect = (exercise: Exercise) => {
    onSelect(exercise);
    setQuery("");
    setIsOpen(false);
    inputRef.current?.blur();
  };

  const openCreateForm = () => {
    setNewName(query.trim());
    setNewType("barbell");
    setNewMuscleGroups([]);
    setNewInputFields(["sets", "reps", "weight"]);
    setShowCreateForm(true);
    setIsOpen(false);
  };

  const handleCreate = async () => {
    if (!newName.trim()) return;

    setCreating(true);
    try {
      const response = await fetch("/api/exercises", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          name: newName.trim(),
          type: newType,
          muscleGroups: newMuscleGroups,
          inputFields: newInputFields,
        }),
      });

      if (!response.ok) {
        const err = await response.json();
        alert(err.error || "Failed to create exercise");
        return;
      }

      const exercise: Exercise = await response.json();
      onExerciseCreated?.(exercise);
      onSelect(exercise);
      setShowCreateForm(false);
      setQuery("");
    } catch (error) {
      console.error("Failed to create exercise:", error);
      alert("Failed to create exercise. Please try again.");
    } finally {
      setCreating(false);
    }
  };

  const toggleMuscleGroup = (group: string) => {
    setNewMuscleGroups((prev) =>
      prev.includes(group) ? prev.filter((g) => g !== group) : [...prev, group]
    );
  };

  const toggleInputField = (field: string) => {
    setNewInputFields((prev) => {
      // "sets" is always included
      if (field === "sets") return prev;
      return prev.includes(field)
        ? prev.filter((f) => f !== field)
        : [...prev, field];
    });
  };

  const handleTypeChange = (type: string) => {
    setNewType(type);
    // Auto-set sensible input field defaults based on type
    if (type === "cardio") {
      setNewInputFields(["sets", "duration", "distance", "calories"]);
    } else {
      setNewInputFields(["sets", "reps", "weight"]);
    }
  };

  const highlightMatch = (name: string) => {
    if (!query.trim()) return name;
    const q = query.toLowerCase();
    const idx = name.toLowerCase().indexOf(q);
    if (idx >= 0) {
      return (
        <>
          {name.slice(0, idx)}
          <span className="font-bold text-white">
            {name.slice(idx, idx + q.length)}
          </span>
          {name.slice(idx + q.length)}
        </>
      );
    }
    return name;
  };

  const parseMuscleGroups = (json: string | null): string[] => {
    if (!json) return [];
    try {
      return JSON.parse(json);
    } catch {
      return [];
    }
  };

  // --- Create Form ---
  if (showCreateForm) {
    return (
      <div className="border border-zinc-700 rounded-lg bg-zinc-900 p-4 space-y-4">
        <div className="flex items-center justify-between">
          <h4 className="font-semibold text-white flex items-center gap-2">
            <Plus className="w-4 h-4 text-zinc-400" />
            New Exercise
          </h4>
          <button
            type="button"
            onClick={() => setShowCreateForm(false)}
            className="p-1 hover:bg-zinc-800 rounded"
          >
            <X className="w-4 h-4 text-zinc-500" />
          </button>
        </div>

        {/* Name */}
        <div>
          <label className="block text-sm font-medium text-zinc-400 mb-1">
            Name
          </label>
          <input
            type="text"
            value={newName}
            onChange={(e) => setNewName(e.target.value)}
            className="w-full px-3 py-2 border border-zinc-700 rounded-lg bg-zinc-800 text-white focus:outline-none focus:ring-2 focus:ring-white/20"
            autoFocus
          />
        </div>

        {/* Equipment */}
        <div>
          <label className="block text-sm font-medium text-zinc-400 mb-1">
            Equipment
          </label>
          <div className="flex flex-wrap gap-2">
            {[...EXERCISE_TYPES, ...customTypes].map((t) => (
              <button
                key={t.value}
                type="button"
                onClick={() => handleTypeChange(t.value)}
                className={`px-3 py-1.5 rounded-lg text-sm font-medium transition ${
                  newType === t.value
                    ? "bg-white text-black"
                    : "bg-zinc-800 text-zinc-400 hover:text-white border border-zinc-700"
                }`}
              >
                {t.label}
              </button>
            ))}
            {addingType ? (
              <form
                onSubmit={(e) => {
                  e.preventDefault();
                  const val = newTypeText.trim().toLowerCase();
                  if (val && !EXERCISE_TYPES.some((t) => t.value === val) && !customTypes.some((t) => t.value === val)) {
                    setSessionCustomTypes((p) => [...p, { value: val, label: val.charAt(0).toUpperCase() + val.slice(1) }]);
                    handleTypeChange(val);
                  }
                  setNewTypeText("");
                  setAddingType(false);
                }}
                className="flex items-center gap-1"
              >
                <input
                  autoFocus
                  value={newTypeText}
                  onChange={(e) => setNewTypeText(e.target.value)}
                  onBlur={() => {
                    const val = newTypeText.trim().toLowerCase();
                    if (val && !EXERCISE_TYPES.some((t) => t.value === val) && !customTypes.some((t) => t.value === val)) {
                      setSessionCustomTypes((p) => [...p, { value: val, label: val.charAt(0).toUpperCase() + val.slice(1) }]);
                      handleTypeChange(val);
                    }
                    setNewTypeText("");
                    setAddingType(false);
                  }}
                  placeholder="New type"
                  className="w-24 px-2 py-1.5 bg-zinc-800 border border-zinc-600 rounded-lg text-sm text-white focus:outline-none focus:ring-1 focus:ring-white/30"
                />
              </form>
            ) : (
              <button
                type="button"
                onClick={() => setAddingType(true)}
                className="px-2.5 py-1.5 rounded-lg text-sm font-medium bg-zinc-800 text-zinc-500 hover:text-white border border-dashed border-zinc-600 transition"
              >
                +
              </button>
            )}
          </div>
        </div>

        {/* Muscle Groups */}
        <div>
          <label className="block text-sm font-medium text-zinc-400 mb-1">
            Muscle Groups
          </label>
          <div className="flex flex-wrap gap-2">
            {[...MUSCLE_GROUPS, ...customMuscles].map((group) => (
              <button
                key={group}
                type="button"
                onClick={() => toggleMuscleGroup(group.toLowerCase())}
                className={`px-3 py-1.5 rounded-lg text-sm font-medium transition ${
                  newMuscleGroups.includes(group.toLowerCase())
                    ? "bg-white text-black"
                    : "bg-zinc-800 text-zinc-400 hover:text-white border border-zinc-700"
                }`}
              >
                {group}
              </button>
            ))}
            {addingMuscle ? (
              <form
                onSubmit={(e) => {
                  e.preventDefault();
                  const val = newMuscleText.trim();
                  const valLower = val.toLowerCase();
                  if (val && !MUSCLE_GROUPS.map((g) => g.toLowerCase()).includes(valLower) && !customMuscles.map((g) => g.toLowerCase()).includes(valLower)) {
                    const display = val.charAt(0).toUpperCase() + val.slice(1);
                    setSessionCustomMuscles((p) => [...p, display]);
                  }
                  if (valLower && !newMuscleGroups.includes(valLower)) {
                    setNewMuscleGroups((p) => [...p, valLower]);
                  }
                  setNewMuscleText("");
                  setAddingMuscle(false);
                }}
                className="flex items-center gap-1"
              >
                <input
                  autoFocus
                  value={newMuscleText}
                  onChange={(e) => setNewMuscleText(e.target.value)}
                  onBlur={() => {
                    const val = newMuscleText.trim();
                    const valLower = val.toLowerCase();
                    if (val && !MUSCLE_GROUPS.map((g) => g.toLowerCase()).includes(valLower) && !customMuscles.map((g) => g.toLowerCase()).includes(valLower)) {
                      const display = val.charAt(0).toUpperCase() + val.slice(1);
                      setSessionCustomMuscles((p) => [...p, display]);
                    }
                    if (valLower && !newMuscleGroups.includes(valLower)) {
                      setNewMuscleGroups((p) => [...p, valLower]);
                    }
                    setNewMuscleText("");
                    setAddingMuscle(false);
                  }}
                  placeholder="New group"
                  className="w-24 px-2 py-1.5 bg-zinc-800 border border-zinc-600 rounded-lg text-sm text-white focus:outline-none focus:ring-1 focus:ring-white/30"
                />
              </form>
            ) : (
              <button
                type="button"
                onClick={() => setAddingMuscle(true)}
                className="px-2.5 py-1.5 rounded-lg text-sm font-medium bg-zinc-800 text-zinc-500 hover:text-white border border-dashed border-zinc-600 transition"
              >
                +
              </button>
            )}
          </div>
        </div>

        {/* Input Fields */}
        <div>
          <label className="block text-sm font-medium text-zinc-400 mb-1">
            Tracking Fields
          </label>
          <div className="flex flex-wrap gap-2">
            {[
              { value: "reps", label: "Reps" },
              { value: "weight", label: "Weight" },
              { value: "duration", label: "Time" },
              { value: "distance", label: "Distance" },
              { value: "calories", label: "Calories" },
              { value: "notes", label: "Notes" },
              ...customFieldOptions,
            ].map((field) => (
              <button
                key={field.value}
                type="button"
                onClick={() => toggleInputField(field.value)}
                className={`px-3 py-1.5 rounded-lg text-sm font-medium transition ${
                  newInputFields.includes(field.value)
                    ? "bg-white text-black"
                    : "bg-zinc-800 text-zinc-400 hover:text-white border border-zinc-700"
                }`}
              >
                {field.label}
              </button>
            ))}
            {addingField ? (
              <form
                onSubmit={(e) => {
                  e.preventDefault();
                  const val = newFieldText.trim().toLowerCase();
                  const knownValues = ["sets", "reps", "weight", "duration", "distance", "calories", "notes"];
                  if (val && !knownValues.includes(val) && !customFieldOptions.some((f) => f.value === val)) {
                    setSessionCustomFields((p) => [...p, { value: val, label: val.charAt(0).toUpperCase() + val.slice(1) }]);
                  }
                  if (val && !newInputFields.includes(val)) {
                    setNewInputFields((p) => [...p, val]);
                  }
                  setNewFieldText("");
                  setAddingField(false);
                }}
                className="flex items-center gap-1"
              >
                <input
                  autoFocus
                  value={newFieldText}
                  onChange={(e) => setNewFieldText(e.target.value)}
                  onBlur={() => {
                    const val = newFieldText.trim().toLowerCase();
                    const knownValues = ["sets", "reps", "weight", "duration", "distance", "calories", "notes"];
                    if (val && !knownValues.includes(val) && !customFieldOptions.some((f) => f.value === val)) {
                      setSessionCustomFields((p) => [...p, { value: val, label: val.charAt(0).toUpperCase() + val.slice(1) }]);
                    }
                    if (val && !newInputFields.includes(val)) {
                      setNewInputFields((p) => [...p, val]);
                    }
                    setNewFieldText("");
                    setAddingField(false);
                  }}
                  placeholder="New field"
                  className="w-24 px-2 py-1.5 bg-zinc-800 border border-zinc-600 rounded-lg text-sm text-white focus:outline-none focus:ring-1 focus:ring-white/30"
                />
              </form>
            ) : (
              <button
                type="button"
                onClick={() => setAddingField(true)}
                className="px-2.5 py-1.5 rounded-lg text-sm font-medium bg-zinc-800 text-zinc-500 hover:text-white border border-dashed border-zinc-600 transition"
              >
                +
              </button>
            )}
          </div>
        </div>

        {/* Actions */}
        <div className="flex gap-3 pt-2">
          <button
            type="button"
            onClick={handleCreate}
            disabled={!newName.trim() || creating}
            className="flex-1 py-2.5 bg-white text-black font-semibold rounded-lg hover:bg-zinc-200 disabled:bg-zinc-700 disabled:text-zinc-500 disabled:cursor-not-allowed transition"
          >
            {creating ? "Creating..." : "Create & Add"}
          </button>
          <button
            type="button"
            onClick={() => setShowCreateForm(false)}
            className="px-4 py-2.5 border border-zinc-700 rounded-lg text-zinc-400 hover:text-white hover:border-zinc-600 transition"
          >
            Cancel
          </button>
        </div>
      </div>
    );
  }

  // --- Main Autocomplete Input ---
  return (
    <div ref={containerRef} className="relative">
      <div className="relative">
        <Search className="absolute left-3 top-1/2 -translate-y-1/2 w-5 h-5 text-zinc-500 pointer-events-none" />
        <input
          ref={inputRef}
          type="text"
          value={query}
          onChange={(e) => {
            setQuery(e.target.value);
            setIsOpen(true);
          }}
          onFocus={() => setIsOpen(true)}
          onKeyDown={handleKeyDown}
          placeholder="Type to search or add an exercise..."
          className="w-full pl-10 pr-10 py-3 border border-zinc-700 rounded-lg focus:outline-none focus:ring-2 focus:ring-white/20 text-base bg-zinc-800 text-white placeholder:text-zinc-500"
          autoComplete="off"
        />
        {query && (
          <button
            type="button"
            onClick={() => {
              setQuery("");
              setIsOpen(false);
              inputRef.current?.focus();
            }}
            className="absolute right-3 top-1/2 -translate-y-1/2 p-0.5 rounded text-zinc-500 hover:text-white transition-colors"
            aria-label="Clear search"
          >
            <X className="w-4 h-4" />
          </button>
        )}
      </div>

      {/* Dropdown */}
      {isOpen && (query.trim() || filteredExercises.length > 0) && (
        <div
          ref={dropdownRef}
          className="absolute z-50 w-full mt-1 bg-zinc-900 border border-zinc-700 rounded-lg shadow-2xl max-h-72 overflow-y-auto"
        >
          {/* Recently used label */}
          {!query.trim() &&
            recentlyUsed.length > 0 &&
            filteredExercises.some((ex) =>
              recentlyUsed.includes(ex.id)
            ) && (
              <div className="px-3 py-1.5 text-xs font-semibold text-zinc-500 uppercase tracking-wide bg-zinc-800/50 border-b border-zinc-800">
                Recently Used
              </div>
            )}

          {filteredExercises.map((exercise, index) => {
            const isRecent = recentlyUsed.includes(exercise.id);
            const muscles = parseMuscleGroups(exercise.muscleGroups);

            const isFirstNonRecent =
              !query.trim() &&
              !isRecent &&
              index > 0 &&
              recentlyUsed.includes(filteredExercises[index - 1].id);

            return (
              <div key={exercise.id}>
                {isFirstNonRecent && (
                  <div className="px-3 py-1.5 text-xs font-semibold text-zinc-500 uppercase tracking-wide bg-zinc-800/50 border-t border-b border-zinc-800">
                    All Exercises
                  </div>
                )}
                <button
                  type="button"
                  data-highlighted={highlightIndex === index}
                  onClick={() => handleSelect(exercise)}
                  onMouseEnter={() => setHighlightIndex(index)}
                  className={`w-full text-left px-3 py-2.5 flex items-center gap-3 transition-colors ${
                    highlightIndex === index
                      ? "bg-zinc-800"
                      : "hover:bg-zinc-800/50"
                  }`}
                >
                  <Dumbbell className="w-4 h-4 text-zinc-500 flex-shrink-0" />
                  <div className="flex-1 min-w-0">
                    <div className="text-sm font-medium text-zinc-300">
                      {highlightMatch(exercise.name)}
                    </div>
                    {muscles.length > 0 && (
                      <div className="text-xs text-zinc-600 mt-0.5">
                        {muscles.join(" · ")} · {exercise.type}
                      </div>
                    )}
                  </div>
                </button>
              </div>
            );
          })}

          {/* Create new exercise option */}
          {showCreateOption && (
            <button
              type="button"
              data-highlighted={highlightIndex === filteredExercises.length}
              onClick={openCreateForm}
              onMouseEnter={() =>
                setHighlightIndex(filteredExercises.length)
              }
              className={`w-full text-left px-3 py-3 flex items-center gap-3 border-t border-zinc-800 transition-colors ${
                highlightIndex === filteredExercises.length
                  ? "bg-zinc-800"
                  : "hover:bg-zinc-800/50"
              }`}
            >
              <div className="w-6 h-6 rounded-full bg-zinc-700 flex items-center justify-center flex-shrink-0">
                <Plus className="w-4 h-4 text-white" />
              </div>
              <div>
                <div className="text-sm font-medium text-white">
                  Create &ldquo;{query.trim()}&rdquo;
                </div>
                <div className="text-xs text-zinc-500">
                  Add as a new exercise
                </div>
              </div>
            </button>
          )}

          {/* No results */}
          {filteredExercises.length === 0 && !showCreateOption && (
            <div className="px-3 py-6 text-center text-sm text-zinc-500">
              No exercises found
            </div>
          )}
        </div>
      )}
    </div>
  );
}
