"use client";

import { useEffect, useMemo, useState } from "react";
import { Exercise } from "@prisma/client";
import { Loader2 } from "lucide-react";
import {
  deriveEquipmentOptions,
  deriveMuscleGroupOptions,
  deriveTrackingFieldOptions,
  displayLabel,
  normalizeValue,
  Option,
} from "@/lib/exerciseOptions";

interface AddExerciseFormProps {
  onExerciseAdded: (exercise: Exercise) => void;
}

export default function AddExerciseForm({ onExerciseAdded }: AddExerciseFormProps) {
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [libraryExercises, setLibraryExercises] = useState<Exercise[]>([]);

  const [formData, setFormData] = useState({
    name: "",
    type: "barbell",
    muscleGroups: [] as string[],
    inputFields: ["sets", "reps", "weight"] as string[],
    description: "",
  });

  const [addingType, setAddingType] = useState(false);
  const [newTypeText, setNewTypeText] = useState("");
  const [sessionTypes, setSessionTypes] = useState<Option[]>([]);

  const [addingMuscle, setAddingMuscle] = useState(false);
  const [newMuscleText, setNewMuscleText] = useState("");
  const [sessionMuscles, setSessionMuscles] = useState<string[]>([]);

  const [addingField, setAddingField] = useState(false);
  const [newFieldText, setNewFieldText] = useState("");
  const [sessionFields, setSessionFields] = useState<Option[]>([]);

  useEffect(() => {
    const fetchExercises = async () => {
      try {
        const response = await fetch("/api/exercises");
        if (!response.ok) return;
        const data = await response.json();
        setLibraryExercises(data);
      } catch (err) {
        console.error("Failed to fetch exercise library:", err);
      }
    };
    fetchExercises();
  }, []);

  const equipmentOptions = useMemo(() => {
    const base = deriveEquipmentOptions(libraryExercises);
    const merged = [...base];
    for (const option of sessionTypes) {
      if (!merged.some((item) => item.value === option.value)) {
        merged.push(option);
      }
    }
    return merged;
  }, [libraryExercises, sessionTypes]);

  const muscleOptions = useMemo(() => {
    const base = deriveMuscleGroupOptions(libraryExercises);
    const merged = [...base];
    for (const muscle of sessionMuscles) {
      if (!merged.includes(muscle)) {
        merged.push(muscle);
      }
    }
    return merged;
  }, [libraryExercises, sessionMuscles]);

  const trackingOptions = useMemo(() => {
    const base = deriveTrackingFieldOptions(libraryExercises);
    const merged = [...base];
    for (const option of sessionFields) {
      if (!merged.some((item) => item.value === option.value)) {
        merged.push(option);
      }
    }
    return merged;
  }, [libraryExercises, sessionFields]);

  const getDefaultFieldsForType = (type: string): string[] => {
    if (type === "cardio") return ["sets", "duration", "distance", "calories", "notes"];
    if (type === "bodyweight") return ["sets", "reps", "notes"];
    return ["sets", "reps", "weight", "notes"];
  };

  const handleTypeChange = (type: string) => {
    setFormData((prev) => ({
      ...prev,
      type,
      inputFields: getDefaultFieldsForType(type),
    }));
  };

  const handleMuscleGroupToggle = (group: string) => {
    setFormData((prev) => ({
      ...prev,
      muscleGroups: prev.muscleGroups.includes(group)
        ? prev.muscleGroups.filter((item) => item !== group)
        : [...prev.muscleGroups, group],
    }));
  };

  const handleInputFieldToggle = (field: string) => {
    if (field === "sets") return;
    setFormData((prev) => ({
      ...prev,
      inputFields: prev.inputFields.includes(field)
        ? prev.inputFields.filter((item) => item !== field)
        : [...prev.inputFields, field],
    }));
  };

  const commitNewType = () => {
    const value = normalizeValue(newTypeText);
    if (!value) {
      setAddingType(false);
      setNewTypeText("");
      return;
    }
    if (!equipmentOptions.some((option) => option.value === value)) {
      setSessionTypes((prev) => [...prev, { value, label: displayLabel(value) }]);
    }
    handleTypeChange(value);
    setAddingType(false);
    setNewTypeText("");
  };

  const commitNewMuscle = () => {
    const value = normalizeValue(newMuscleText);
    if (!value) {
      setAddingMuscle(false);
      setNewMuscleText("");
      return;
    }
    if (!muscleOptions.includes(value)) {
      setSessionMuscles((prev) => [...prev, value]);
    }
    if (!formData.muscleGroups.includes(value)) {
      setFormData((prev) => ({ ...prev, muscleGroups: [...prev.muscleGroups, value] }));
    }
    setAddingMuscle(false);
    setNewMuscleText("");
  };

  const commitNewField = () => {
    const value = normalizeValue(newFieldText);
    if (!value || value === "sets") {
      setAddingField(false);
      setNewFieldText("");
      return;
    }
    if (!trackingOptions.some((option) => option.value === value)) {
      setSessionFields((prev) => [...prev, { value, label: displayLabel(value) }]);
    }
    if (!formData.inputFields.includes(value)) {
      setFormData((prev) => ({ ...prev, inputFields: [...prev.inputFields, value] }));
    }
    setAddingField(false);
    setNewFieldText("");
  };

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    setError(null);
    setLoading(true);

    try {
      const response = await fetch("/api/exercises", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          name: formData.name,
          type: formData.type,
          muscleGroups: formData.muscleGroups,
          inputFields: formData.inputFields,
          description: formData.description || undefined,
        }),
      });

      if (!response.ok) {
        const data = await response.json();
        throw new Error(data.error || "Failed to add exercise");
      }

      const exercise = await response.json();
      onExerciseAdded(exercise);
      setLibraryExercises((prev) => [...prev, exercise]);

      setFormData({
        name: "",
        type: "barbell",
        muscleGroups: [],
        inputFields: ["sets", "reps", "weight"],
        description: "",
      });
      setSessionTypes([]);
      setSessionMuscles([]);
      setSessionFields([]);
    } catch (err) {
      setError(err instanceof Error ? err.message : "An error occurred");
    } finally {
      setLoading(false);
    }
  };

  return (
    <form onSubmit={handleSubmit} className="space-y-5">
      {error && (
        <div className="bg-red-900/50 border border-red-800 rounded-lg p-3 text-red-400 text-sm">
          {error}
        </div>
      )}

      <div>
        <label className="block text-xs font-medium text-zinc-400 uppercase tracking-wider mb-2">
          Exercise Name
        </label>
        <input
          type="text"
          required
          value={formData.name}
          onChange={(e) => setFormData((prev) => ({ ...prev, name: e.target.value }))}
          className="w-full px-4 py-3 bg-zinc-800 border border-zinc-700 rounded-lg text-white placeholder:text-zinc-500 focus:outline-none focus:ring-2 focus:ring-white/20"
          placeholder="e.g., Barbell Bench Press"
        />
      </div>

      <div>
        <label className="block text-xs font-medium text-zinc-400 uppercase tracking-wider mb-2">
          Equipment
        </label>
        <div className="flex flex-wrap gap-2">
          {equipmentOptions.map((option) => (
            <button
              key={option.value}
              type="button"
              onClick={() => handleTypeChange(option.value)}
              className={`px-3 py-1.5 rounded-lg text-sm font-medium transition ${
                formData.type === option.value
                  ? "bg-white text-black"
                  : "bg-zinc-800 text-zinc-400 hover:text-white"
              }`}
            >
              {option.label}
            </button>
          ))}
          {addingType ? (
            <input
              autoFocus
              value={newTypeText}
              onChange={(e) => setNewTypeText(e.target.value)}
              onBlur={commitNewType}
              onKeyDown={(e) => {
                if (e.key === "Enter") {
                  e.preventDefault();
                  commitNewType();
                }
              }}
              placeholder="New"
              className="w-20 px-2 py-1.5 rounded-lg text-sm bg-zinc-800 border border-zinc-600 text-white"
            />
          ) : (
            <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>

      <div>
        <label className="block text-xs font-medium text-zinc-400 uppercase tracking-wider mb-1">
          Tracked Fields
        </label>
        <p className="text-xs text-zinc-600 mb-2">What data do you log for this exercise?</p>
        <div className="flex flex-wrap gap-2">
          {trackingOptions.map((field) => (
            <button
              key={field.value}
              type="button"
              onClick={() => handleInputFieldToggle(field.value)}
              className={`px-3 py-1.5 rounded-lg text-sm font-medium transition ${
                formData.inputFields.includes(field.value)
                  ? "bg-white text-black"
                  : "bg-zinc-800 text-zinc-400 hover:text-white"
              }`}
            >
              {field.label}
            </button>
          ))}
          {addingField ? (
            <input
              autoFocus
              value={newFieldText}
              onChange={(e) => setNewFieldText(e.target.value)}
              onBlur={commitNewField}
              onKeyDown={(e) => {
                if (e.key === "Enter") {
                  e.preventDefault();
                  commitNewField();
                }
              }}
              placeholder="New"
              className="w-20 px-2 py-1.5 rounded-lg text-sm bg-zinc-800 border border-zinc-600 text-white"
            />
          ) : (
            <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>

      <div>
        <label className="block text-xs font-medium text-zinc-400 uppercase tracking-wider mb-2">
          Muscle Groups
        </label>
        <div className="flex flex-wrap gap-2">
          {muscleOptions.map((group) => (
            <button
              key={group}
              type="button"
              onClick={() => handleMuscleGroupToggle(group)}
              className={`px-3 py-1.5 rounded-lg text-sm font-medium transition ${
                formData.muscleGroups.includes(group)
                  ? "bg-white text-black"
                  : "bg-zinc-800 text-zinc-400 hover:text-white"
              }`}
            >
              {displayLabel(group)}
            </button>
          ))}
          {addingMuscle ? (
            <input
              autoFocus
              value={newMuscleText}
              onChange={(e) => setNewMuscleText(e.target.value)}
              onBlur={commitNewMuscle}
              onKeyDown={(e) => {
                if (e.key === "Enter") {
                  e.preventDefault();
                  commitNewMuscle();
                }
              }}
              placeholder="New"
              className="w-20 px-2 py-1.5 rounded-lg text-sm bg-zinc-800 border border-zinc-600 text-white"
            />
          ) : (
            <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>

      <div>
        <label className="block text-xs font-medium text-zinc-400 uppercase tracking-wider mb-2">
          Description (optional)
        </label>
        <textarea
          value={formData.description}
          onChange={(e) => setFormData((prev) => ({ ...prev, description: e.target.value }))}
          className="w-full px-4 py-3 bg-zinc-800 border border-zinc-700 rounded-lg text-white placeholder:text-zinc-500 focus:outline-none focus:ring-2 focus:ring-white/20 resize-none"
          placeholder="Notes about form, tips, or variations..."
          rows={2}
        />
      </div>

      <button
        type="submit"
        disabled={loading || !formData.name}
        className="w-full bg-white hover:bg-zinc-200 disabled:bg-zinc-700 disabled:text-zinc-500 text-black font-bold py-3 px-4 rounded-lg transition flex items-center justify-center gap-2"
      >
        {loading && <Loader2 className="w-4 h-4 animate-spin" />}
        {loading ? "Adding..." : "Add Exercise"}
      </button>
    </form>
  );
}
