"use client";

import { useCallback, useReducer, useRef } from "react";

import { API_BASE_PUBLIC } from "@/lib/api/config";
import {
  ReviewFrameBuffer,
  initialReviewState,
  reduceReview,
  type CharacterizationReport,
  type ForeshadowSuggestion,
  type PaceReport,
  type ReviewConflict,
  type ReviewStreamState,
  type StyleDriftReport,
} from "./sse";

export interface ReviewSeed {
  conflicts: ReviewConflict[];
  foreshadow: ForeshadowSuggestion[];
  pace: PaceReport | null;
  style: StyleDriftReport | null;
  characterization: CharacterizationReport | null;
}

type Action =
  | { type: "start" }
  | { type: "events"; events: ReturnType<ReviewFrameBuffer["push"]> }
  | { type: "abort" }
  | { type: "fail"; code: string; message: string }
  | { type: "seed"; seed: ReviewSeed };

function reducer(state: ReviewStreamState, action: Action): ReviewStreamState {
  switch (action.type) {
    case "start":
      return { ...initialReviewState, phase: "reviewing" };
    case "events":
      return action.events.reduce(reduceReview, state);
    case "abort":
      return { ...state, phase: "aborted" };
    case "fail":
      return {
        ...state,
        phase: "error",
        error: { code: action.code, message: action.message },
      };
    case "seed":
      return {
        ...initialReviewState,
        conflicts: action.seed.conflicts,
        foreshadow: action.seed.foreshadow,
        pace: action.seed.pace,
        style: action.seed.style,
        characterization: action.seed.characterization,
      };
    default:
      return state;
  }
}

export interface UseReviewStream {
  state: ReviewStreamState;
  isReviewing: boolean;
  // 用当前编辑器草稿重新审稿。
  start: (projectId: string, chapterNo: number, draft: string) => Promise<void>;
  stop: () => void;
  // 进页用历史留痕（冲突 + 伏笔建议 + 节奏）种入（无需重审即可裁决/查看）。
  seed: (seed: ReviewSeed) => void;
}

// 消费 POST .../review 的 SSE 流：fetch+ReadableStream（EventSource 不支持 POST）。
// "停" = abort（已收 section/conflict 留在 state，裁决草稿不丢）。
// 流前 503 LLM_UNAVAILABLE 是 JSON 信封（非帧）→ 经 !res.ok 检出。
export function useReviewStream(): UseReviewStream {
  const [state, dispatch] = useReducer(reducer, initialReviewState);
  const controllerRef = useRef<AbortController | null>(null);

  const stop = useCallback(() => {
    controllerRef.current?.abort();
    controllerRef.current = null;
    dispatch({ type: "abort" });
  }, []);

  const seed = useCallback((seedData: ReviewSeed) => {
    dispatch({ type: "seed", seed: seedData });
  }, []);

  const start = useCallback(
    async (
      projectId: string,
      chapterNo: number,
      draft: string,
    ): Promise<void> => {
      const controller = new AbortController();
      controllerRef.current = controller;
      dispatch({ type: "start" });
      try {
        const res = await fetch(
          `${API_BASE_PUBLIC}/projects/${projectId}/chapters/${chapterNo}/review`,
          {
            method: "POST",
            headers: {
              Accept: "text/event-stream",
              "Content-Type": "application/json",
            },
            body: JSON.stringify({ draft }),
            signal: controller.signal,
          },
        );
        if (!res.ok || !res.body) {
          let code = "REVIEW_FAILED";
          let message = `审稿请求失败（${res.status}）`;
          try {
            const body = (await res.json()) as {
              error?: { code?: string; message?: string };
            };
            if (body.error?.code) code = body.error.code;
            if (body.error?.message) message = body.error.message;
          } catch {
            // 非 JSON 信封，沿用默认文案。
          }
          dispatch({ type: "fail", code, message });
          return;
        }
        const reader = res.body.getReader();
        const decoder = new TextDecoder();
        const buffer = new ReviewFrameBuffer();
        for (;;) {
          const { value, done } = await reader.read();
          if (done) break;
          const events = buffer.push(decoder.decode(value, { stream: true }));
          if (events.length > 0) dispatch({ type: "events", events });
        }
      } catch (err: unknown) {
        if (err instanceof DOMException && err.name === "AbortError") {
          return; // 用户主动停止：state 已置 aborted。
        }
        const message = err instanceof Error ? err.message : "未知网络错误";
        dispatch({ type: "fail", code: "NETWORK", message });
      } finally {
        controllerRef.current = null;
      }
    },
    [],
  );

  return {
    state,
    isReviewing: state.phase === "reviewing",
    start,
    stop,
    seed,
  };
}
