"use client";

import { useCallback, useEffect, useMemo, useState } from "react";
import { Alert } from "@/components/ui/Alert";
import { Button } from "@/components/ui/Button";
import { Input } from "@/components/ui/Field";
import { ApiError, apiDelete, apiGet, apiPatch, apiPost, apiPut } from "@/lib/api";
import type { StudyFieldMatrixGrade, StudyFieldMatrixStage, StudyFieldOption } from "@/lib/types";

function idsEqual(a: number[], b: number[]): boolean {
  if (a.length !== b.length) return false;
  const sortedA = [...a].sort((x, y) => x - y);
  const sortedB = [...b].sort((x, y) => x - y);
  return sortedA.every((id, i) => id === sortedB[i]);
}

function stageCatalogFields(stage: StudyFieldMatrixStage): StudyFieldOption[] {
  return stage.catalog_fields ?? stage.grade_levels[0]?.catalog_fields ?? [];
}

function gradeNeedsFieldChoice(grade: StudyFieldMatrixGrade, catalog: StudyFieldOption[]): boolean {
  return catalog.length > 1;
}

export function StudyFieldTreeManager() {
  const [stages, setStages] = useState<StudyFieldMatrixStage[]>([]);
  const [selections, setSelections] = useState<Record<number, number[]>>({});
  const [saved, setSaved] = useState<Record<number, number[]>>({});
  const [expandedStages, setExpandedStages] = useState<Set<number>>(new Set());
  const [addingToStage, setAddingToStage] = useState<number | null>(null);
  const [editingFieldId, setEditingFieldId] = useState<number | null>(null);
  const [newFieldName, setNewFieldName] = useState("");
  const [newFieldCode, setNewFieldCode] = useState("");
  const [editFieldName, setEditFieldName] = useState("");
  const [editFieldCode, setEditFieldCode] = useState("");
  const [loading, setLoading] = useState(true);
  const [savingId, setSavingId] = useState<number | "all" | null>(null);
  const [adding, setAdding] = useState(false);
  const [updating, setUpdating] = useState(false);
  const [deletingId, setDeletingId] = useState<number | null>(null);
  const [error, setError] = useState<string | null>(null);
  const [message, setMessage] = useState<string | null>(null);

  const load = useCallback(async () => {
    setLoading(true);
    try {
      const rows = await apiGet<StudyFieldMatrixStage[]>("/study-fields/matrix");
      setStages(rows);
      const initial: Record<number, number[]> = {};
      for (const stage of rows) {
        for (const grade of stage.grade_levels) {
          if (grade.has_study_fields) {
            initial[grade.id] = [...grade.selected_study_field_ids];
          }
        }
      }
      setSelections(initial);
      setSaved(initial);
      setExpandedStages(new Set(rows.map((s) => s.id)));
      setError(null);
    } catch (err) {
      setError(err instanceof ApiError ? err.message : "خطا در بارگذاری");
    } finally {
      setLoading(false);
    }
  }, []);

  useEffect(() => {
    load();
  }, [load]);

  const dirtyGradeIds = useMemo(() => {
    const dirty: number[] = [];
    for (const [gradeIdStr, ids] of Object.entries(selections)) {
      const gradeId = Number(gradeIdStr);
      if (!idsEqual(ids, saved[gradeId] ?? [])) dirty.push(gradeId);
    }
    return dirty;
  }, [selections, saved]);

  const setGradeFields = (gradeId: number, fieldIds: number[]) => {
    setSelections((prev) => ({ ...prev, [gradeId]: fieldIds }));
    setMessage(null);
  };

  const toggleField = (gradeId: number, fieldId: number) => {
    const current = selections[gradeId] ?? [];
    const next = current.includes(fieldId)
      ? current.filter((id) => id !== fieldId)
      : [...current, fieldId];
    setGradeFields(gradeId, next);
  };

  const toggleGrade = (grade: StudyFieldMatrixGrade, catalog: StudyFieldOption[]) => {
    const orgFieldIds = catalog.map((f) => f.id);
    if (orgFieldIds.length === 0) return;

    const selectedFields = selections[grade.id] ?? [];
    const allSelected = orgFieldIds.every((id) => selectedFields.includes(id));

    if (!allSelected) {
      setGradeFields(grade.id, [...orgFieldIds]);
      return;
    }
    setGradeFields(grade.id, []);
  };

  const toggleStage = (stage: StudyFieldMatrixStage) => {
    const catalog = stageCatalogFields(stage);
    const grades = stage.grade_levels.filter(() => catalog.length > 0);
    if (grades.length === 0) return;

    const allComplete = grades.every((grade) => {
      const ids = selections[grade.id] ?? [];
      return catalog.every((f) => ids.includes(f.id));
    });

    const next = { ...selections };
    grades.forEach((grade) => {
      next[grade.id] = allComplete ? [] : catalog.map((f) => f.id);
    });
    setSelections(next);
    setMessage(null);
  };

  const saveGrade = async (gradeId: number) => {
    setSavingId(gradeId);
    setError(null);
    setMessage(null);
    try {
      const result = await apiPut<{ selected_study_field_ids: number[] }>(
        `/grade-levels/${gradeId}/study-fields`,
        { study_field_ids: selections[gradeId] ?? [] },
      );
      const ids = [...result.selected_study_field_ids];
      setSaved((prev) => ({ ...prev, [gradeId]: ids }));
      setSelections((prev) => ({ ...prev, [gradeId]: ids }));
      setMessage("ذخیره شد.");
    } catch (err) {
      setError(err instanceof ApiError ? err.message : "خطا در ذخیره");
    } finally {
      setSavingId(null);
    }
  };

  const saveAll = async () => {
    if (dirtyGradeIds.length === 0) return;
    setSavingId("all");
    setError(null);
    setMessage(null);
    try {
      const results = await Promise.all(
        dirtyGradeIds.map(async (gradeId) => {
          const result = await apiPut<{ selected_study_field_ids: number[] }>(
            `/grade-levels/${gradeId}/study-fields`,
            { study_field_ids: selections[gradeId] ?? [] },
          );
          return { gradeId, ids: [...result.selected_study_field_ids] };
        }),
      );
      setSaved((prev) => {
        const next = { ...prev };
        results.forEach(({ gradeId, ids }) => {
          next[gradeId] = ids;
        });
        return next;
      });
      setSelections((prev) => {
        const next = { ...prev };
        results.forEach(({ gradeId, ids }) => {
          next[gradeId] = ids;
        });
        return next;
      });
      setMessage("همه تغییرات ذخیره شد.");
    } catch (err) {
      setError(err instanceof ApiError ? err.message : "خطا در ذخیره");
    } finally {
      setSavingId(null);
    }
  };

  const addField = async (stageId: number) => {
    if (!newFieldName.trim()) {
      setError("نام رشته الزامی است.");
      return;
    }
    setAdding(true);
    setError(null);
    setMessage(null);
    try {
      await apiPost("/study-fields", {
        education_stage_id: stageId,
        name: newFieldName.trim(),
        code: newFieldCode.trim() || null,
        link_to_all_grades: true,
      });
      setNewFieldName("");
      setNewFieldCode("");
      setAddingToStage(null);
      setMessage("رشته جدید اضافه شد.");
      await load();
    } catch (err) {
      setError(err instanceof ApiError ? err.message : "خطا در ثبت");
    } finally {
      setAdding(false);
    }
  };

  const startEditField = (field: StudyFieldOption) => {
    setEditingFieldId(field.id);
    setEditFieldName(field.name);
    setEditFieldCode(field.code ?? "");
    setAddingToStage(null);
    setError(null);
    setMessage(null);
  };

  const cancelEditField = () => {
    setEditingFieldId(null);
    setEditFieldName("");
    setEditFieldCode("");
  };

  const updateField = async () => {
    if (editingFieldId === null) return;
    if (!editFieldName.trim()) {
      setError("نام رشته الزامی است.");
      return;
    }
    setUpdating(true);
    setError(null);
    setMessage(null);
    try {
      await apiPatch(`/study-fields/${editingFieldId}`, {
        name: editFieldName.trim(),
        code: editFieldCode.trim() || null,
      });
      cancelEditField();
      setMessage("رشته ویرایش شد.");
      await load();
    } catch (err) {
      setError(err instanceof ApiError ? err.message : "خطا در ویرایش");
    } finally {
      setUpdating(false);
    }
  };

  const removeField = async (fieldId: number, fieldName: string) => {
    if (!window.confirm(`رشته «${fieldName}» از کل سازمان حذف شود؟`)) return;
    setDeletingId(fieldId);
    setError(null);
    setMessage(null);
    try {
      await apiDelete(`/study-fields/${fieldId}`);
      setMessage(`«${fieldName}» حذف شد.`);
      await load();
    } catch (err) {
      setError(err instanceof ApiError ? err.message : "خطا در حذف");
    } finally {
      setDeletingId(null);
    }
  };

  const toggleExpand = (stageId: number) => {
    setExpandedStages((prev) => {
      const next = new Set(prev);
      if (next.has(stageId)) next.delete(stageId);
      else next.add(stageId);
      return next;
    });
  };

  if (loading) {
    return <p className="text-sm text-[var(--muted)]">در حال بارگذاری…</p>;
  }

  if (stages.length === 0) {
    return (
      <p className="text-sm text-[var(--muted)]">هنوز مقطع یا پایه‌ای تعریف نشده است.</p>
    );
  }

  return (
    <div className="space-y-4">
      <div className="flex flex-wrap items-center justify-between gap-3">
        <p className="text-xs leading-relaxed text-[var(--muted)]">
          درخت: مقطع → پایه → رشته. تیک پایه = همه رشته‌های آن پایه. انتخاب رشته برای هر مدرسه در
          ویرایش مدرسه انجام می‌شود.
        </p>
        {dirtyGradeIds.length > 0 ? (
          <Button loading={savingId === "all"} onClick={saveAll}>
            ذخیره همه ({dirtyGradeIds.length})
          </Button>
        ) : null}
      </div>

      {error ? <Alert tone="error">{error}</Alert> : null}
      {message ? <Alert tone="success">{message}</Alert> : null}

      <div className="max-h-[42rem] space-y-3 overflow-y-auto rounded-2xl border border-[var(--border)] bg-slate-50/50 p-3">
        {stages.map((stage) => {
          const catalog = stageCatalogFields(stage);
          const grades = stage.grade_levels;
          const expanded = expandedStages.has(stage.id);
          const gradesWithCatalog = grades.filter(() => catalog.length > 0);
          const stageAllSelected =
            gradesWithCatalog.length > 0 &&
            gradesWithCatalog.every((grade) => {
              const ids = selections[grade.id] ?? [];
              return catalog.every((f) => ids.includes(f.id));
            });
          const stageSomeSelected =
            !stageAllSelected &&
            gradesWithCatalog.some((grade) => (selections[grade.id] ?? []).length > 0);

          return (
            <div
              key={stage.id}
              className="overflow-hidden rounded-xl border border-[var(--border)] bg-white shadow-sm"
            >
              <div className="flex flex-wrap items-center gap-2 border-b border-[var(--border)] bg-slate-50 px-3 py-2.5">
                <button
                  type="button"
                  className="flex min-w-0 flex-1 items-center gap-2 text-right"
                  onClick={() => toggleExpand(stage.id)}
                >
                  <span className="text-xs text-[var(--muted)]">{expanded ? "▼" : "◀"}</span>
                  {gradesWithCatalog.length > 0 ? (
                    <input
                      type="checkbox"
                      checked={stageAllSelected}
                      ref={(el) => {
                        if (el) el.indeterminate = stageSomeSelected;
                      }}
                      onClick={(e) => e.stopPropagation()}
                      onChange={() => toggleStage(stage)}
                    />
                  ) : null}
                  <span className="truncate text-sm font-bold">{stage.name}</span>
                  {catalog.length > 0 ? (
                    <span className="rounded-full bg-teal-100 px-2 py-0.5 text-[10px] font-medium text-teal-800">
                      {catalog.length} رشته
                    </span>
                  ) : null}
                </button>
                <Button
                  variant="ghost"
                  onClick={() => {
                    cancelEditField();
                    setAddingToStage(addingToStage === stage.id ? null : stage.id);
                    setNewFieldName("");
                    setNewFieldCode("");
                  }}
                >
                  + رشته
                </Button>
              </div>

              {addingToStage === stage.id ? (
                <div className="flex flex-wrap items-end gap-2 border-b border-[var(--border)] bg-teal-50/40 px-3 py-3">
                  <label className="min-w-[10rem] flex-1 text-xs">
                    <span className="mb-1 block text-[var(--muted)]">نام رشته</span>
                    <Input
                      value={newFieldName}
                      placeholder="مثلاً علوم تجربی"
                      onChange={(e) => setNewFieldName(e.target.value)}
                    />
                  </label>
                  <label className="min-w-[8rem] flex-1 text-xs">
                    <span className="mb-1 block text-[var(--muted)]">کد (اختیاری)</span>
                    <Input
                      value={newFieldCode}
                      placeholder="experimental"
                      onChange={(e) => setNewFieldCode(e.target.value)}
                    />
                  </label>
                  <Button loading={adding} onClick={() => addField(stage.id)}>
                    افزودن
                  </Button>
                  <Button variant="ghost" onClick={() => setAddingToStage(null)}>
                    انصراف
                  </Button>
                </div>
              ) : null}

              {expanded ? (
                <div className="px-2 py-2">
                  {catalog.length > 0 ? (
                    <div className="mb-2 flex flex-wrap gap-1.5 px-2">
                      {catalog.map((field) =>
                        editingFieldId === field.id ? (
                          <div
                            key={field.id}
                            className="flex w-full flex-wrap items-end gap-2 rounded-lg border border-teal-200 bg-teal-50/40 px-2 py-2"
                          >
                            <label className="min-w-[10rem] flex-1 text-xs">
                              <span className="mb-1 block text-[var(--muted)]">نام رشته</span>
                              <Input
                                value={editFieldName}
                                onChange={(e) => setEditFieldName(e.target.value)}
                              />
                            </label>
                            <label className="min-w-[8rem] flex-1 text-xs">
                              <span className="mb-1 block text-[var(--muted)]">کد (اختیاری)</span>
                              <Input
                                value={editFieldCode}
                                placeholder="experimental"
                                onChange={(e) => setEditFieldCode(e.target.value)}
                              />
                            </label>
                            <Button loading={updating} onClick={updateField}>
                              ذخیره
                            </Button>
                            <Button variant="ghost" onClick={cancelEditField}>
                              انصراف
                            </Button>
                          </div>
                        ) : (
                          <span
                            key={field.id}
                            className="inline-flex items-center gap-1 rounded-lg border border-[var(--border)] bg-white px-2 py-1 text-xs text-[var(--muted)]"
                          >
                            {field.name}
                            <button
                              type="button"
                              className="rounded px-1 text-teal-700 hover:bg-teal-50"
                              title="ویرایش"
                              onClick={() => startEditField(field)}
                            >
                              ✎
                            </button>
                            <button
                              type="button"
                              className="rounded px-1 text-rose-600 hover:bg-rose-50"
                              disabled={deletingId === field.id}
                              title="حذف از کاتالوگ"
                              onClick={() => removeField(field.id, field.name)}
                            >
                              ×
                            </button>
                          </span>
                        ),
                      )}
                    </div>
                  ) : (
                    <p className="px-2 py-2 text-xs text-[var(--muted)]">
                      هنوز رشته‌ای برای این مقطع تعریف نشده — «+ رشته» را بزنید.
                    </p>
                  )}

                  <div className="mr-2 space-y-1 border-r-2 border-teal-100 pr-3">
                    {grades.map((grade) => {
                      const selectedFields = selections[grade.id] ?? [];
                      const hasCatalog = catalog.length > 0;
                      const needsChoice = gradeNeedsFieldChoice(grade, catalog);
                      const allSelected =
                        catalog.length > 0 &&
                        catalog.every((f) => selectedFields.includes(f.id));
                      const gradeDirty = dirtyGradeIds.includes(grade.id);
                      const gradeIndeterminate =
                        needsChoice &&
                        selectedFields.length > 0 &&
                        !allSelected;

                      if (!hasCatalog) {
                        return (
                          <div
                            key={grade.id}
                            className="flex items-center gap-2 rounded-lg px-2 py-1.5 text-sm text-[var(--muted)]"
                          >
                            <span className="w-4" />
                            <span>{grade.name}</span>
                            <span className="text-xs opacity-60">— بدون رشته</span>
                          </div>
                        );
                      }

                      return (
                        <div key={grade.id} className="rounded-lg">
                          <div className="flex flex-wrap items-center gap-2 px-2 py-1.5">
                            <label className="flex min-w-0 flex-1 cursor-pointer items-center gap-2 text-sm font-semibold">
                              <input
                                type="checkbox"
                                checked={allSelected}
                                ref={(el) => {
                                  if (el) el.indeterminate = gradeIndeterminate;
                                }}
                                onChange={() => toggleGrade(grade, catalog)}
                              />
                              {grade.name}
                            </label>
                            {gradeDirty ? (
                              <Button
                                variant="ghost"
                                disabled={savingId === grade.id}
                                onClick={() => saveGrade(grade.id)}
                              >
                                {savingId === grade.id ? "…" : "ذخیره"}
                              </Button>
                            ) : null}
                          </div>

                          <div className="mr-6 space-y-0.5 border-r border-dashed border-slate-200 pr-3 pb-1">
                            {catalog.map((field) => (
                              <label
                                key={field.id}
                                className="flex cursor-pointer items-center gap-2 rounded-md px-2 py-1 text-xs text-[var(--muted)] hover:bg-slate-50"
                              >
                                <input
                                  type="checkbox"
                                  checked={selectedFields.includes(field.id)}
                                  onChange={() => toggleField(grade.id, field.id)}
                                />
                                <span className="flex-1">{field.name}</span>
                              </label>
                            ))}
                          </div>
                        </div>
                      );
                    })}
                  </div>
                </div>
              ) : null}
            </div>
          );
        })}
      </div>
    </div>
  );
}
