import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { AppIcon } from "./PixelIcons";
import {
  coachLogMessages,
  fetchCoachChat,
  fetchPersonalNote,
  savePersonalNoteApi,
  type SkillNotesIndex,
} from "../lib/skillCardNotes";

function formatWhen(iso?: string) {
  if (!iso) return "";
  try {
    return new Date(iso).toLocaleString("zh-TW", {
      month: "short",
      day: "numeric",
      hour: "2-digit",
      minute: "2-digit",
    });
  } catch {
    return "";
  }
}

export default function SkillNotesPanel({
  principleId,
  cardTitle,
  onNotesChange,
}: {
  principleId: string;
  cardTitle: string;
  onNotesChange?: (notesIndex: SkillNotesIndex) => void;
}) {
  const [draft, setDraft] = useState("");
  const [loadedDraft, setLoadedDraft] = useState<string | null>(null);
  const [savedAt, setSavedAt] = useState<string | undefined>();
  const [saveState, setSaveState] = useState<"idle" | "saving" | "saved" | "error">("idle");
  const [coachMessages, setCoachMessages] = useState<Awaited<ReturnType<typeof fetchCoachChat>>>([]);
  const [loading, setLoading] = useState(true);
  const onNotesChangeRef = useRef(onNotesChange);

  const coachLog = useMemo(() => coachLogMessages(coachMessages), [coachMessages]);
  const dirty = loadedDraft !== null && draft !== loadedDraft;

  useEffect(() => {
    onNotesChangeRef.current = onNotesChange;
  }, [onNotesChange]);

  useEffect(() => {
    let cancelled = false;
    setLoading(true);
    setSaveState("idle");
    setLoadedDraft(null);
    void Promise.all([fetchPersonalNote(principleId), fetchCoachChat(principleId, cardTitle)])
      .then(([note, messages]) => {
        if (cancelled) return;
        const text = note?.text || "";
        setDraft(text);
        setLoadedDraft(text);
        setSavedAt(note?.updatedAt);
        setCoachMessages(messages);
      })
      .finally(() => {
        if (!cancelled) setLoading(false);
      });
    return () => {
      cancelled = true;
    };
  }, [principleId, cardTitle]);

  useEffect(() => {
    const reloadCoach = (e: Event) => {
      const pid = (e as CustomEvent<{ principleId?: string }>).detail?.principleId;
      if (!pid || pid === principleId) {
        void fetchCoachChat(principleId, cardTitle).then(setCoachMessages);
      }
    };
    window.addEventListener("skill-coach-chat-updated", reloadCoach);
    return () => window.removeEventListener("skill-coach-chat-updated", reloadCoach);
  }, [principleId, cardTitle]);

  const saveDraft = useCallback(
    async (text: string) => {
      setSaveState("saving");
      try {
        const { note, notesIndex } = await savePersonalNoteApi(principleId, text);
        setSavedAt(note?.updatedAt);
        setLoadedDraft(text);
        setSaveState("saved");
        onNotesChangeRef.current?.(notesIndex);
        window.setTimeout(() => setSaveState("idle"), 1500);
      } catch {
        setSaveState("error");
      }
    },
    [principleId],
  );

  useEffect(() => {
    if (loading || !dirty) return;
    const timer = window.setTimeout(() => {
      void saveDraft(draft);
    }, 600);
    return () => window.clearTimeout(timer);
  }, [draft, dirty, loading, saveDraft]);

  const clipCoach = (text: string, role: "user" | "assistant") => {
    const label = role === "user" ? "我問" : "教練說";
    const block = `【${label}】\n${text.trim()}`;
    const next = draft.trim() ? `${draft}\n\n---\n\n${block}` : block;
    setDraft(next);
  };

  return (
    <section className="skill-notes" aria-label="心法筆記">
      <div className="skill-notes-head">
        <AppIcon name="scroll" size={22} framed variant="hero" />
        <div>
          <strong>修煉筆記</strong>
          <p className="small muted">個人心得與教練對談都儲存在後端資料庫，可一鍵摘錄進筆記。</p>
        </div>
        <div className="skill-notes-save">
          <span className={`small ${saveState === "error" || dirty ? "skill-notes-save-alert" : "muted"}`}>
            {loading
              ? "載入中…"
              : saveState === "saving"
                ? "存檔中…"
                : saveState === "error"
                  ? "存檔失敗，請重試"
                  : dirty
                    ? "有未存檔變更"
                    : saveState === "saved"
                      ? "已寫入資料庫"
                      : savedAt
                        ? `已存檔 ${formatWhen(savedAt)}`
                        : "尚未寫入"}
          </span>
          <button
            type="button"
            className="btn-primary sm"
            disabled={loading || saveState === "saving" || !dirty}
            onClick={() => void saveDraft(draft)}
          >
            {saveState === "saving" ? "存檔中…" : dirty ? "存檔" : "已存檔"}
          </button>
        </div>
      </div>

      <label className="skill-notes-field">
        <span className="skill-notes-label">我的心得</span>
        <textarea
          className="skill-notes-textarea"
          rows={8}
          value={draft}
          disabled={loading}
          placeholder="這條心法對你代表什麼？實戰情境、提醒自己的話、和教練討論後的結論…"
          onChange={(e) => setDraft(e.target.value)}
          onKeyDown={(e) => {
            if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === "s") {
              e.preventDefault();
              if (dirty && saveState !== "saving") void saveDraft(draft);
            }
          }}
        />
      </label>

      <div className="skill-notes-coach-log">
        <div className="skill-notes-coach-head">
          <AppIcon name="wizard" size={18} framed variant="hero" />
          <strong>教練對談紀錄</strong>
          <span className="small muted">{coachLog.length ? `${coachLog.length} 則` : "尚無對話"}</span>
        </div>
        {!coachLog.length ? (
          <p className="small muted skill-notes-empty">到「教練」分頁聊過之後，對話會出現在這裡。</p>
        ) : (
          <ul className="skill-notes-log-list">
            {coachLog.map((msg) => (
              <li className={`skill-notes-log-item role-${msg.role}`} key={msg.id}>
                <div className="skill-notes-log-role">{msg.role === "user" ? "我" : "教練"}</div>
                <div className="skill-notes-log-body">
                  <p>{msg.text}</p>
                  {msg.meta && msg.meta !== "教練" && msg.meta !== "思考中" ? (
                    <span className="small muted">{msg.meta}</span>
                  ) : null}
                </div>
                <button
                  type="button"
                  className="btn-ghost sm skill-notes-clip"
                  onClick={() => clipCoach(msg.text, msg.role as "user" | "assistant")}
                >
                  摘錄
                </button>
              </li>
            ))}
          </ul>
        )}
      </div>
    </section>
  );
}
