import { useEffect, useState } from "preact/hooks";

type Student = {
  numEtud: number;
  nom: string;
  prenom: string;
  idPromo: string;
};
type UE = { id: number; nom: string };
type UEModule = {
  idModule: string;
  idUE: number;
  idPromo: string;
  coeff: number;
};
type Module = { id: string; nom: string };
type Note = { numEtud: number; idModule: string; note: number };
type Ajustement = { numEtud: number; idUE: number; valeur: number };

type Props = { numEtud: number };

function fmt(n: number): string {
  return `${Math.round(n * 10) / 10}/20`;
}

function noteClass(n: number): string {
  return n >= 10 ? "note-chip note-chip--ok" : "note-chip note-chip--fail";
}

export default function NoteRecap({ numEtud }: Props) {
  const [student, setStudent] = useState<Student | null>(null);
  const [ueList, setUeList] = useState<UE[]>([]);
  const [ueModules, setUeModules] = useState<UEModule[]>([]);
  const [moduleMap, setModuleMap] = useState<Map<string, string>>(new Map());
  const [noteMap, setNoteMap] = useState<Map<string, number>>(new Map());
  const [ajustements, setAjustements] = useState<Ajustement[]>([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);
  const [editingNote, setEditingNote] = useState<
    { idModule: string; value: string } | null
  >(null);
  const [ajustInputs, setAjustInputs] = useState<Record<number, string>>({});

  async function load() {
    try {
      const sRes = await fetch(`/students/api/students/${numEtud}`);
      if (!sRes.ok) throw new Error("Élève introuvable");
      const s: Student = await sRes.json();
      setStudent(s);

      const [uesRes, umRes, mRes, notesRes, ajustRes] = await Promise.all([
        fetch("/notes/api/ues"),
        fetch(
          `/notes/api/ue-modules?idPromo=${encodeURIComponent(s.idPromo)}`,
        ),
        fetch("/admin/api/modules"),
        fetch(`/notes/api/notes?numEtud=${numEtud}`),
        fetch(`/notes/api/ajustements?numEtud=${numEtud}`),
      ]);

      if (uesRes.ok) setUeList(await uesRes.json());
      if (umRes.ok) setUeModules(await umRes.json());
      if (mRes.ok) {
        const mods: Module[] = await mRes.json();
        setModuleMap(new Map(mods.map((m) => [m.id, m.nom])));
      }
      if (notesRes.ok) {
        const ns: Note[] = await notesRes.json();
        setNoteMap(new Map(ns.map((n) => [n.idModule, n.note])));
      }
      if (ajustRes.ok) {
        const aj: Ajustement[] = await ajustRes.json();
        setAjustements(aj);
        const inputs: Record<number, string> = {};
        for (const a of aj) inputs[a.idUE] = String(a.valeur);
        setAjustInputs(inputs);
      }
    } catch (e) {
      setError(e instanceof Error ? e.message : "Erreur");
    } finally {
      setLoading(false);
    }
  }

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

  function calcAvg(ueMods: UEModule[]): number | null {
    let total = 0, coeff = 0;
    for (const um of ueMods) {
      const n = noteMap.get(um.idModule);
      if (n === undefined) return null;
      total += n * um.coeff;
      coeff += um.coeff;
    }
    return coeff > 0 ? total / coeff : null;
  }

  async function saveNote(idModule: string, value: string) {
    const note = parseFloat(value.replace(",", "."));
    if (isNaN(note) || note < 0 || note > 20) {
      setEditingNote(null);
      return;
    }
    const res = await fetch(
      `/notes/api/notes/${numEtud}/${encodeURIComponent(idModule)}`,
      {
        method: "PUT",
        headers: { "content-type": "application/json" },
        body: JSON.stringify({ note }),
      },
    );
    if (res.ok) {
      const updated: Note = await res.json();
      setNoteMap((prev) => new Map(prev).set(idModule, updated.note));
    }
    setEditingNote(null);
  }

  async function applyAjust(idUE: number) {
    const val = parseFloat((ajustInputs[idUE] ?? "").replace(",", "."));
    if (isNaN(val) || val < 0 || val > 20) return;
    const existing = ajustements.find((a) => a.idUE === idUE);
    const res = existing
      ? await fetch(`/notes/api/ajustements/${numEtud}/${idUE}`, {
        method: "PUT",
        headers: { "content-type": "application/json" },
        body: JSON.stringify({ valeur: val }),
      })
      : await fetch("/notes/api/ajustements", {
        method: "POST",
        headers: { "content-type": "application/json" },
        body: JSON.stringify({ numEtud, idUE, valeur: val }),
      });
    if (res.ok) {
      const updated: Ajustement = await res.json();
      setAjustements((prev) =>
        existing
          ? prev.map((a) => a.idUE === idUE ? updated : a)
          : [...prev, updated]
      );
    }
  }

  async function resetAjust(idUE: number) {
    const res = await fetch(`/notes/api/ajustements/${numEtud}/${idUE}`, {
      method: "DELETE",
    });
    if (res.ok) {
      setAjustements((prev) => prev.filter((a) => a.idUE !== idUE));
      setAjustInputs((prev) => {
        const c = { ...prev };
        delete c[idUE];
        return c;
      });
    }
  }

  if (loading) {
    return (
      <div class="page-content">
        <p class="state-loading">Chargement…</p>
      </div>
    );
  }
  if (error && !student) {
    return (
      <div class="page-content">
        <p class="state-error">{error}</p>
      </div>
    );
  }
  if (!student) return null;

  return (
    <div class="page-content">
      <a
        class="back-link"
        href="/notes/courses"
        f-partial="/notes/partials/courses"
      >
        ← Retour à la liste
      </a>

      <h2
        class="page-title"
        style="border-bottom: none; margin-bottom: 0.5rem"
      >
        Récap notes – {student.prenom} {student.nom}
      </h2>

      <div class="info-bar" style="margin-bottom: 1.25rem">
        <span class="numEtud-chip">{student.numEtud}</span>
        <span style="font-weight: 600">{student.prenom} {student.nom}</span>
        <span class="note-chip note-chip--promo">{student.idPromo}</span>
      </div>

      {error && <p class="state-error">{error}</p>}

      {ueList.length === 0
        ? (
          <p class="state-empty">
            Aucune UE configurée pour cette promotion.
          </p>
        )
        : ueList.map((ue) => {
          const ueMods = ueModules.filter((um) => um.idUE === ue.id);
          const avg = calcAvg(ueMods);
          const ajust = ajustements.find((a) => a.idUE === ue.id);

          return (
            <div key={ue.id} class="edit-section">
              {/* UE header */}
              <div style="display: flex; align-items: center; gap: 0.75rem; margin-bottom: 0.75rem; flex-wrap: wrap">
                <p class="edit-section-title" style="margin: 0">{ue.nom}</p>
                {avg !== null && (
                  <span class={noteClass(avg)} style="font-size: 0.78rem">
                    Moy. calculée : {fmt(avg)}
                  </span>
                )}
                {ajust && (
                  <span
                    class="note-chip note-chip--ajust"
                    style="font-size: 0.78rem"
                  >
                    ⚡ Ajust. actif : {fmt(ajust.valeur)}
                  </span>
                )}
              </div>

              {/* Module rows */}
              {ueMods.length === 0
                ? (
                  <p
                    class="col-dim"
                    style="font-size: 0.8rem; padding: 0.25rem 0; margin-bottom: 0.75rem"
                  >
                    Aucun module associé à cette UE pour cette promotion.
                  </p>
                )
                : (
                  <div style="margin-bottom: 0.75rem">
                    {ueMods.map((um) => {
                      const noteVal = noteMap.get(um.idModule);
                      const nomMod = moduleMap.get(um.idModule) ?? um.idModule;
                      const isEditing = editingNote?.idModule === um.idModule;

                      return (
                        <div
                          key={um.idModule}
                          class="note-row"
                        >
                          <span class="note-row-label">
                            <span class="numEtud-chip note-row-chip">
                              {um.idModule}
                            </span>
                            {nomMod}
                          </span>
                          <span class="col-dim note-row-coef">
                            coef {um.coeff}
                          </span>
                          {isEditing
                            ? (
                              <div style="display: flex; align-items: center; gap: 0.25rem">
                                <input
                                  class="form-input"
                                  style="width: 5rem; text-align: center; font-size: 0.85rem"
                                  value={editingNote!.value}
                                  autoFocus
                                  onInput={(e) =>
                                    setEditingNote({
                                      idModule: um.idModule,
                                      value:
                                        (e.target as HTMLInputElement).value,
                                    })}
                                  onKeyDown={(e) => {
                                    if (e.key === "Enter") {
                                      saveNote(
                                        um.idModule,
                                        editingNote!.value,
                                      );
                                    }
                                    if (e.key === "Escape") {
                                      setEditingNote(null);
                                    }
                                  }}
                                  onBlur={() =>
                                    saveNote(um.idModule, editingNote!.value)}
                                />
                                <span
                                  class="col-dim"
                                  style="font-size: 0.75rem"
                                >
                                  /20
                                </span>
                              </div>
                            )
                            : (
                              <span
                                class={noteVal !== undefined
                                  ? noteClass(noteVal)
                                  : "note-chip note-chip--none"}
                                style="font-size: 0.78rem; cursor: pointer"
                                title="Cliquer pour modifier"
                                onClick={() =>
                                  setEditingNote({
                                    idModule: um.idModule,
                                    value: noteVal !== undefined
                                      ? String(noteVal)
                                      : "",
                                  })}
                              >
                                {noteVal !== undefined ? fmt(noteVal) : "—/20"}
                              </span>
                            )}
                          <button
                            type="button"
                            class="btn btn-sm btn-secondary"
                            style="font-size: 0.75rem"
                            onClick={() =>
                              setEditingNote({
                                idModule: um.idModule,
                                value: noteVal !== undefined
                                  ? String(noteVal)
                                  : "",
                              })}
                          >
                            ✏ note
                          </button>
                        </div>
                      );
                    })}
                  </div>
                )}

              {/* Ajustement */}
              <div class="ajust-section">
                <p class="ajust-title">Ajustement de la moyenne UE</p>
                <p class="ajust-hint">
                  Override ponctuel – laisser vide pour utiliser la moy.
                  calculée
                </p>
                <div style="display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap">
                  <div style="display: flex; align-items: center; gap: 0.25rem">
                    <input
                      class="form-input"
                      style="width: 4.5rem; text-align: center"
                      placeholder="—"
                      value={ajustInputs[ue.id] ?? ""}
                      onInput={(e) =>
                        setAjustInputs((prev) => ({
                          ...prev,
                          [ue.id]: (e.target as HTMLInputElement).value,
                        }))}
                    />
                    <span class="col-dim" style="font-size: 0.8rem">/20</span>
                  </div>
                  <button
                    type="button"
                    class="btn btn-sm btn-primary"
                    onClick={() => applyAjust(ue.id)}
                  >
                    ✓ Appliquer
                  </button>
                  {ajust && (
                    <>
                      <button
                        type="button"
                        class="btn btn-sm btn-secondary"
                        onClick={() => resetAjust(ue.id)}
                      >
                        ✕ Réinitialiser
                      </button>
                      <span
                        class="col-dim"
                        style="font-size: 0.75rem; font-family: monospace"
                      >
                        Affiché à l'élève : {fmt(ajust.valeur)}
                        {avg !== null ? ` (calculée : ${fmt(avg)})` : ""}
                      </span>
                    </>
                  )}
                </div>
              </div>
            </div>
          );
        })}
    </div>
  );
}
