'use client';

import { useState } from 'react';
import { useRouter } from 'next/navigation';
import { Plus, Trash2, ChevronDown, ChevronRight, Loader2 } from 'lucide-react';

const DAY_LABELS = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];

interface LibraryExercise {
  id: string;
  name: string;
  type: string;
}

export interface DraftExercise {
  exerciseId: string;
  order: number;
  sets?: number | null;
  repsMin?: number | null;
  repsMax?: number | null;
  rpe?: number | null;
  restSeconds?: number | null;
  notes?: string | null;
}
export interface DraftDay {
  dayOfWeek: number;
  name?: string | null;
  description?: string | null;
  exercises: DraftExercise[];
}
export interface DraftWeek {
  weekNumber: number;
  phase?: string | null;
  description?: string | null;
  days: DraftDay[];
}
export interface DraftProgram {
  name: string;
  description?: string | null;
  type: string;
  durationWeeks: number;
  startDate: string; // ISO yyyy-mm-dd
  isActive: boolean;
  weeks: DraftWeek[];
}

const TYPE_OPTIONS = [
  'hypertrophy',
  'strength',
  'power',
  'endurance',
  'recovery',
  'general',
];

export default function ProgramEditor({
  initialProgram,
  programId,
  exercises,
}: {
  initialProgram?: DraftProgram;
  programId?: string; // if present, this is an edit; otherwise create
  exercises: LibraryExercise[];
}) {
  const router = useRouter();
  const [program, setProgram] = useState<DraftProgram>(
    initialProgram ?? {
      name: '',
      description: '',
      type: 'hypertrophy',
      durationWeeks: 8,
      startDate: new Date().toISOString().slice(0, 10),
      isActive: false,
      weeks: [],
    },
  );
  const [saving, setSaving] = useState(false);
  const [error, setError] = useState<string | null>(null);

  // Track expansion state for the tree
  const [openWeeks, setOpenWeeks] = useState<Record<number, boolean>>({});

  const update = (patch: Partial<DraftProgram>) =>
    setProgram((p) => ({ ...p, ...patch }));

  const addWeek = () => {
    const nextNum = Math.max(0, ...program.weeks.map((w) => w.weekNumber)) + 1;
    setProgram((p) => ({
      ...p,
      weeks: [...p.weeks, { weekNumber: nextNum, phase: null, days: [] }].sort(
        (a, b) => a.weekNumber - b.weekNumber,
      ),
    }));
    setOpenWeeks((s) => ({ ...s, [nextNum]: true }));
  };

  const removeWeek = (weekNumber: number) => {
    if (!confirm(`Remove week ${weekNumber}?`)) return;
    setProgram((p) => ({
      ...p,
      weeks: p.weeks.filter((w) => w.weekNumber !== weekNumber),
    }));
  };

  const updateWeek = (weekNumber: number, patch: Partial<DraftWeek>) =>
    setProgram((p) => ({
      ...p,
      weeks: p.weeks.map((w) =>
        w.weekNumber === weekNumber ? { ...w, ...patch } : w,
      ),
    }));

  const addDay = (weekNumber: number, dayOfWeek: number) => {
    setProgram((p) => ({
      ...p,
      weeks: p.weeks.map((w) =>
        w.weekNumber === weekNumber
          ? {
              ...w,
              days: [
                ...w.days,
                { dayOfWeek, name: null, description: null, exercises: [] },
              ].sort((a, b) => a.dayOfWeek - b.dayOfWeek),
            }
          : w,
      ),
    }));
  };

  const removeDay = (weekNumber: number, dayOfWeek: number) =>
    setProgram((p) => ({
      ...p,
      weeks: p.weeks.map((w) =>
        w.weekNumber === weekNumber
          ? { ...w, days: w.days.filter((d) => d.dayOfWeek !== dayOfWeek) }
          : w,
      ),
    }));

  const updateDay = (
    weekNumber: number,
    dayOfWeek: number,
    patch: Partial<DraftDay>,
  ) =>
    setProgram((p) => ({
      ...p,
      weeks: p.weeks.map((w) =>
        w.weekNumber === weekNumber
          ? {
              ...w,
              days: w.days.map((d) =>
                d.dayOfWeek === dayOfWeek ? { ...d, ...patch } : d,
              ),
            }
          : w,
      ),
    }));

  const addExercise = (
    weekNumber: number,
    dayOfWeek: number,
    exerciseId: string,
  ) => {
    setProgram((p) => ({
      ...p,
      weeks: p.weeks.map((w) =>
        w.weekNumber === weekNumber
          ? {
              ...w,
              days: w.days.map((d) =>
                d.dayOfWeek === dayOfWeek
                  ? {
                      ...d,
                      exercises: [
                        ...d.exercises,
                        {
                          exerciseId,
                          order: d.exercises.length,
                          sets: 3,
                          repsMin: 8,
                          repsMax: 12,
                          rpe: null,
                          restSeconds: 90,
                          notes: null,
                        },
                      ],
                    }
                  : d,
              ),
            }
          : w,
      ),
    }));
  };

  const updateExercise = (
    weekNumber: number,
    dayOfWeek: number,
    order: number,
    patch: Partial<DraftExercise>,
  ) =>
    setProgram((p) => ({
      ...p,
      weeks: p.weeks.map((w) =>
        w.weekNumber === weekNumber
          ? {
              ...w,
              days: w.days.map((d) =>
                d.dayOfWeek === dayOfWeek
                  ? {
                      ...d,
                      exercises: d.exercises.map((ex) =>
                        ex.order === order ? { ...ex, ...patch } : ex,
                      ),
                    }
                  : d,
              ),
            }
          : w,
      ),
    }));

  const removeExercise = (
    weekNumber: number,
    dayOfWeek: number,
    order: number,
  ) =>
    setProgram((p) => ({
      ...p,
      weeks: p.weeks.map((w) =>
        w.weekNumber === weekNumber
          ? {
              ...w,
              days: w.days.map((d) =>
                d.dayOfWeek === dayOfWeek
                  ? {
                      ...d,
                      exercises: d.exercises
                        .filter((ex) => ex.order !== order)
                        .map((ex, idx) => ({ ...ex, order: idx })),
                    }
                  : d,
              ),
            }
          : w,
      ),
    }));

  const handleSave = async () => {
    if (!program.name.trim()) {
      setError('Program name is required.');
      return;
    }
    setError(null);
    setSaving(true);
    try {
      const url = programId ? `/api/programs/${programId}` : '/api/programs';
      const method = programId ? 'PATCH' : 'POST';
      const res = await fetch(url, {
        method,
        headers: { 'content-type': 'application/json' },
        body: JSON.stringify(program),
      });
      if (!res.ok) {
        const body = await res.json().catch(() => ({}));
        throw new Error(body.error ?? `HTTP ${res.status}`);
      }
      const saved = await res.json();
      router.push(`/main/programs/${saved.id}`);
      router.refresh();
    } catch (e) {
      setError((e as Error).message);
    } finally {
      setSaving(false);
    }
  };

  const exerciseLookup = new Map(exercises.map((e) => [e.id, e]));

  return (
    <div className="space-y-6">
      {/* Top-level metadata */}
      <section className="bg-zinc-900 border border-zinc-800 rounded p-4 space-y-4">
        <Field label="Name">
          <input
            value={program.name}
            onChange={(e) => update({ name: e.target.value })}
            placeholder="8 Week Hypertrophy"
            className={inputClass}
          />
        </Field>
        <Field label="Description (optional)">
          <textarea
            value={program.description ?? ''}
            onChange={(e) => update({ description: e.target.value || null })}
            rows={2}
            className={inputClass}
          />
        </Field>
        <div className="grid grid-cols-2 sm:grid-cols-4 gap-3">
          <Field label="Type">
            <select
              value={program.type}
              onChange={(e) => update({ type: e.target.value })}
              className={inputClass}
            >
              {TYPE_OPTIONS.map((t) => (
                <option key={t} value={t}>
                  {t}
                </option>
              ))}
            </select>
          </Field>
          <Field label="Duration (weeks)">
            <input
              type="number"
              min={1}
              max={52}
              value={program.durationWeeks}
              onChange={(e) =>
                update({ durationWeeks: parseInt(e.target.value || '1', 10) })
              }
              className={inputClass}
            />
          </Field>
          <Field label="Start date">
            <input
              type="date"
              value={program.startDate}
              onChange={(e) => update({ startDate: e.target.value })}
              className={inputClass}
            />
          </Field>
          <Field label="Active">
            <button
              type="button"
              onClick={() => update({ isActive: !program.isActive })}
              className={`mt-1 inline-flex items-center h-9 px-3 rounded border text-xs uppercase tracking-wider ${
                program.isActive
                  ? 'bg-emerald-900/40 border-emerald-800 text-emerald-300'
                  : 'border-zinc-700 text-zinc-400'
              }`}
            >
              {program.isActive ? 'Active' : 'Inactive'}
            </button>
          </Field>
        </div>
      </section>

      {/* Weeks */}
      <section className="space-y-3">
        <div className="flex items-center justify-between">
          <h2 className="text-sm font-semibold text-white uppercase tracking-wider">
            Weeks ({program.weeks.length})
          </h2>
          <button
            type="button"
            onClick={addWeek}
            className="text-xs px-3 py-1.5 rounded border border-zinc-700 text-white hover:bg-zinc-800"
          >
            <Plus className="inline w-3.5 h-3.5 mr-1" />
            Add week
          </button>
        </div>

        {program.weeks.length === 0 && (
          <p className="text-xs text-zinc-500">
            No weeks yet. Click <strong>Add week</strong> to start the plan.
          </p>
        )}

        {program.weeks.map((w) => (
          <div
            key={w.weekNumber}
            className="bg-zinc-900 border border-zinc-800 rounded"
          >
            <div className="flex items-center justify-between px-4 py-2 border-b border-zinc-800">
              <button
                type="button"
                onClick={() =>
                  setOpenWeeks((s) => ({ ...s, [w.weekNumber]: !s[w.weekNumber] }))
                }
                className="flex items-center gap-2 text-sm text-white"
              >
                {openWeeks[w.weekNumber] ? (
                  <ChevronDown className="w-4 h-4" />
                ) : (
                  <ChevronRight className="w-4 h-4" />
                )}
                Week {w.weekNumber}
                {w.phase && (
                  <span className="text-xs text-zinc-500">· {w.phase}</span>
                )}
                <span className="text-xs text-zinc-600">
                  ({w.days.length} day{w.days.length === 1 ? '' : 's'})
                </span>
              </button>
              <button
                type="button"
                onClick={() => removeWeek(w.weekNumber)}
                className="text-xs text-red-400 hover:text-red-300"
              >
                <Trash2 className="w-3.5 h-3.5" />
              </button>
            </div>

            {openWeeks[w.weekNumber] && (
              <div className="p-4 space-y-3">
                <div className="grid grid-cols-1 sm:grid-cols-2 gap-3">
                  <Field label="Phase (optional)">
                    <input
                      value={w.phase ?? ''}
                      onChange={(e) =>
                        updateWeek(w.weekNumber, {
                          phase: e.target.value || null,
                        })
                      }
                      placeholder="Volume, intensity, deload..."
                      className={inputClass}
                    />
                  </Field>
                  <Field label="Notes (optional)">
                    <input
                      value={w.description ?? ''}
                      onChange={(e) =>
                        updateWeek(w.weekNumber, {
                          description: e.target.value || null,
                        })
                      }
                      className={inputClass}
                    />
                  </Field>
                </div>

                {/* Day picker */}
                <div className="flex items-center gap-2 flex-wrap">
                  <span className="text-xs text-zinc-500 uppercase tracking-wider">
                    Add day:
                  </span>
                  {DAY_LABELS.map((label, idx) => {
                    const exists = w.days.some((d) => d.dayOfWeek === idx);
                    return (
                      <button
                        key={idx}
                        type="button"
                        disabled={exists}
                        onClick={() => addDay(w.weekNumber, idx)}
                        className={`text-xs px-2 py-1 rounded border ${
                          exists
                            ? 'border-zinc-800 text-zinc-700 cursor-not-allowed'
                            : 'border-zinc-700 text-zinc-300 hover:bg-zinc-800'
                        }`}
                      >
                        {label}
                      </button>
                    );
                  })}
                </div>

                {/* Days */}
                <div className="space-y-2">
                  {w.days.map((d) => (
                    <DayRow
                      key={d.dayOfWeek}
                      day={d}
                      weekNumber={w.weekNumber}
                      exercises={exercises}
                      exerciseLookup={exerciseLookup}
                      onUpdateDay={(patch) => updateDay(w.weekNumber, d.dayOfWeek, patch)}
                      onRemoveDay={() => removeDay(w.weekNumber, d.dayOfWeek)}
                      onAddExercise={(exId) => addExercise(w.weekNumber, d.dayOfWeek, exId)}
                      onUpdateExercise={(order, patch) =>
                        updateExercise(w.weekNumber, d.dayOfWeek, order, patch)
                      }
                      onRemoveExercise={(order) =>
                        removeExercise(w.weekNumber, d.dayOfWeek, order)
                      }
                    />
                  ))}
                </div>
              </div>
            )}
          </div>
        ))}
      </section>

      {error && (
        <div className="rounded bg-red-900/50 px-4 py-3 border border-red-800 text-sm text-red-400">
          {error}
        </div>
      )}

      <div className="flex gap-2">
        <button
          type="button"
          onClick={handleSave}
          disabled={saving}
          className="px-5 py-2 rounded bg-white text-black font-bold text-sm uppercase tracking-wider hover:bg-gray-100 disabled:bg-zinc-700 disabled:text-zinc-500"
        >
          {saving ? (
            <>
              <Loader2 className="inline w-4 h-4 animate-spin mr-2" />
              Saving...
            </>
          ) : programId ? (
            'Save changes'
          ) : (
            'Create program'
          )}
        </button>
      </div>
    </div>
  );
}

function DayRow({
  day,
  weekNumber: _weekNumber,
  exercises,
  exerciseLookup,
  onUpdateDay,
  onRemoveDay,
  onAddExercise,
  onUpdateExercise,
  onRemoveExercise,
}: {
  day: DraftDay;
  weekNumber: number;
  exercises: LibraryExercise[];
  exerciseLookup: Map<string, LibraryExercise>;
  onUpdateDay: (patch: Partial<DraftDay>) => void;
  onRemoveDay: () => void;
  onAddExercise: (exerciseId: string) => void;
  onUpdateExercise: (order: number, patch: Partial<DraftExercise>) => void;
  onRemoveExercise: (order: number) => void;
}) {
  const [pickerValue, setPickerValue] = useState('');
  return (
    <div className="bg-zinc-950 border border-zinc-800 rounded p-3 space-y-3">
      <div className="flex items-center justify-between gap-2">
        <span className="text-xs font-semibold text-zinc-300 uppercase tracking-wider">
          {DAY_LABELS[day.dayOfWeek]}
        </span>
        <input
          value={day.name ?? ''}
          onChange={(e) => onUpdateDay({ name: e.target.value || null })}
          placeholder="Day name (Push, Pull, Lower, etc.)"
          className="flex-1 px-2 py-1 text-sm rounded border border-zinc-700 bg-zinc-900 text-white placeholder:text-zinc-600"
        />
        <button
          type="button"
          onClick={onRemoveDay}
          className="text-xs text-red-400 hover:text-red-300 p-1"
        >
          <Trash2 className="w-3.5 h-3.5" />
        </button>
      </div>

      {day.exercises.map((ex) => {
        const lib = exerciseLookup.get(ex.exerciseId);
        return (
          <div
            key={ex.order}
            className="bg-zinc-900 border border-zinc-800 rounded p-2 space-y-2"
          >
            <div className="flex items-center justify-between gap-2">
              <span className="text-sm text-white">
                {lib?.name ?? '(missing exercise)'}
              </span>
              <button
                type="button"
                onClick={() => onRemoveExercise(ex.order)}
                className="text-xs text-red-400 hover:text-red-300"
              >
                <Trash2 className="w-3.5 h-3.5" />
              </button>
            </div>
            <div className="grid grid-cols-3 sm:grid-cols-6 gap-2">
              <NumField
                label="Sets"
                value={ex.sets ?? null}
                onChange={(v) => onUpdateExercise(ex.order, { sets: v })}
              />
              <NumField
                label="Reps min"
                value={ex.repsMin ?? null}
                onChange={(v) => onUpdateExercise(ex.order, { repsMin: v })}
              />
              <NumField
                label="Reps max"
                value={ex.repsMax ?? null}
                onChange={(v) => onUpdateExercise(ex.order, { repsMax: v })}
              />
              <NumField
                label="RPE"
                value={ex.rpe ?? null}
                onChange={(v) => onUpdateExercise(ex.order, { rpe: v })}
              />
              <NumField
                label="Rest (s)"
                value={ex.restSeconds ?? null}
                onChange={(v) => onUpdateExercise(ex.order, { restSeconds: v })}
              />
              <Field label="Notes">
                <input
                  value={ex.notes ?? ''}
                  onChange={(e) =>
                    onUpdateExercise(ex.order, { notes: e.target.value || null })
                  }
                  className="w-full px-2 py-1 text-xs rounded border border-zinc-700 bg-zinc-800 text-white"
                />
              </Field>
            </div>
          </div>
        );
      })}

      <div className="flex items-center gap-2">
        <select
          value={pickerValue}
          onChange={(e) => setPickerValue(e.target.value)}
          className="flex-1 px-2 py-1 text-sm rounded border border-zinc-700 bg-zinc-900 text-white"
        >
          <option value="">Add exercise...</option>
          {exercises.map((e) => (
            <option key={e.id} value={e.id}>
              {e.name} ({e.type})
            </option>
          ))}
        </select>
        <button
          type="button"
          disabled={!pickerValue}
          onClick={() => {
            if (pickerValue) {
              onAddExercise(pickerValue);
              setPickerValue('');
            }
          }}
          className="text-xs px-3 py-1.5 rounded border border-zinc-700 text-white hover:bg-zinc-800 disabled:opacity-40"
        >
          <Plus className="inline w-3.5 h-3.5 mr-1" />
          Add
        </button>
      </div>
    </div>
  );
}

const inputClass =
  'w-full px-3 py-2 text-sm rounded border border-zinc-700 bg-zinc-800 text-white placeholder:text-zinc-500 focus:outline-none focus:ring-2 focus:ring-white/30';

function Field({ label, children }: { label: string; children: React.ReactNode }) {
  return (
    <label className="block">
      <span className="text-[11px] font-semibold text-zinc-400 uppercase tracking-wider block mb-1">
        {label}
      </span>
      {children}
    </label>
  );
}

function NumField({
  label,
  value,
  onChange,
}: {
  label: string;
  value: number | null;
  onChange: (v: number | null) => void;
}) {
  return (
    <Field label={label}>
      <input
        type="number"
        value={value ?? ''}
        onChange={(e) => {
          const v = e.target.value;
          onChange(v === '' ? null : Number(v));
        }}
        className="w-full px-2 py-1 text-xs rounded border border-zinc-700 bg-zinc-800 text-white"
      />
    </Field>
  );
}
