"use client";

import { create } from "zustand";
import { createId } from "@paralleldrive/cuid2";
import type {
  Block,
  BlockType,
  LessonPlanDocument,
  LessonPlanEdge,
  LessonPlanNode,
} from "../types";

interface EditorState {
  planId: string;
  title: string;
  doc: LessonPlanDocument;
  isDirty: boolean;
  isSaving: boolean;
  lastSavedAt: number | null;
  selectedNodeId: string | null;

  setTitle: (title: string) => void;
  setPlanId: (planId: string) => void;
  hydrate: (planId: string, title: string, doc: LessonPlanDocument) => void;

  addNode: (type: BlockType, position?: { x: number; y: number }, title?: string) => string;
  updateNode: (id: string, patch: Partial<Block>) => void;
  updateNodePosition: (id: string, position: { x: number; y: number }) => void;
  removeNode: (id: string) => void;

  connect: (source: string, target: string) => void;
  disconnect: (edgeId: string) => void;
  setEdges: (edges: LessonPlanEdge[]) => void;

  selectNode: (id: string | null) => void;

  markSaved: () => void;
  setSaving: (saving: boolean) => void;
  replaceDoc: (doc: LessonPlanDocument) => void;
}

function reindex(nodes: LessonPlanNode[]): LessonPlanNode[] {
  return nodes.map((n, i) => ({ ...n, order: i }));
}

function defaultData(type: BlockType): Block["data"] {
  return type === "exercise"
    ? { items: [], purpose: "class_practice", knowledgePointIds: [] }
    : type === "text_study"
      ? { sourceText: "", annotations: [], knowledgePointIds: [] }
      : { html: "", knowledgePointIds: [] };
}

export const useLessonPlanEditor = create<EditorState>((set, get) => ({
  planId: "",
  title: "",
  doc: { version: 2, nodes: [], edges: [] },
  isDirty: false,
  isSaving: false,
  lastSavedAt: null,
  selectedNodeId: null,

  setTitle: (title) => set({ title, isDirty: true }),

  setPlanId: (planId) => set({ planId }),

  // 仅在 planId 变化时调用，避免覆盖用户编辑内容（修复 P1-3）
  hydrate: (planId, title, doc) =>
    set({
      planId,
      title,
      doc,
      isDirty: false,
      lastSavedAt: Date.now(),
      selectedNodeId: null,
    }),

  addNode: (type, position, title) => {
    const id = createId();
    const nodeCount = get().doc.nodes.length;
    const node: LessonPlanNode = {
      id,
      type,
      title: title ?? type, // 调用方应传入翻译后的标题，fallback 为 type 键
      data: defaultData(type),
      order: nodeCount,
      position: position ?? {
        x: 80 + (nodeCount % 4) * 280,
        y: 80 + Math.floor(nodeCount / 4) * 200,
      },
    };
    set((s) => ({
      doc: { ...s.doc, nodes: [...s.doc.nodes, node] },
      isDirty: true,
      selectedNodeId: id,
    }));
    return id;
  },

  updateNode: (id, patch) =>
    set((s) => ({
      doc: {
        ...s.doc,
        nodes: s.doc.nodes.map((n) =>
          n.id === id ? { ...n, ...patch } : n,
        ),
      },
      isDirty: true,
    })),

  updateNodePosition: (id, position) =>
    set((s) => ({
      doc: {
        ...s.doc,
        nodes: s.doc.nodes.map((n) =>
          n.id === id ? { ...n, position } : n,
        ),
      },
      isDirty: true,
    })),

  removeNode: (id) =>
    set((s) => ({
      doc: {
        ...s.doc,
        nodes: reindex(s.doc.nodes.filter((n) => n.id !== id)),
        edges: s.doc.edges.filter(
          (e) => e.source !== id && e.target !== id,
        ),
      },
      isDirty: true,
      selectedNodeId:
        s.selectedNodeId === id ? null : s.selectedNodeId,
    })),

  connect: (source, target) =>
    set((s) => {
      // 避免重复连线
      if (
        s.doc.edges.some(
          (e) => e.source === source && e.target === target,
        )
      )
        return s;
      const edge: LessonPlanEdge = {
        id: `e_${source}_${target}_${createId().slice(0, 6)}`,
        source,
        target,
      };
      return { doc: { ...s.doc, edges: [...s.doc.edges, edge] }, isDirty: true };
    }),

  disconnect: (edgeId) =>
    set((s) => ({
      doc: {
        ...s.doc,
        edges: s.doc.edges.filter((e) => e.id !== edgeId),
      },
      isDirty: true,
    })),

  setEdges: (edges) => set((s) => ({ doc: { ...s.doc, edges }, isDirty: true })),

  selectNode: (id) => set({ selectedNodeId: id }),

  markSaved: () => set({ isDirty: false, lastSavedAt: Date.now() }),
  setSaving: (saving) => set({ isSaving: saving }),
  replaceDoc: (doc) => set({ doc, isDirty: false }),
}));
