import { useCallback, useEffect, useRef, useState } from 'react';
import {
  ApiError,
  cancelRequest,
  closeMindSpacePageEditSession,
  confirmTool,
  forkMindSpacePageEditSession,
  getMindSpace,
  loadSessionDetail,
  resumeSession,
  uploadMindSpaceAsset,
  sendReply,
  subscribeSessionEvents,
} from '../api/client';
import type { ChatState, Message, MindSpaceChatContext, PortalUser, Session, SessionEvent } from '../types';
import { buildContextPrefix } from '../utils/mindspaceChatContext';
import { buildUserAddressPrefix } from '../utils/userAddress';
import {
  CHAT_IMAGE_UPLOAD_MAX_INPUT_BYTES,
  CHAT_IMAGE_UPLOAD_MAX_OUTPUT_BYTES,
  CHAT_IMAGE_MAX_SIDE,
  compressImageForUpload,
} from '../utils/imageUpload';
import { buildAbsoluteAssetImageUrl } from '../utils/mindspaceCards';
import {
  buildUserMessage,
  normalizeConversationMessages,
  getDisplayText,
  getToolConfirmation,
  pushMessage,
} from '../utils/message';

function buildPageEditSummary(messages: Message[], pageTitle: string): string {
  const lines = messages
    .map((message) => {
      const text = getDisplayText(message).trim();
      if (!text) return null;
      return `${message.role === 'user' ? '用户' : 'Agent'}: ${text}`;
    })
    .filter(Boolean)
    .slice(-12);

  if (lines.length === 0) return '';
  return [`[全屏页面编辑摘要 · ${pageTitle}]`, '用户在预览模式下的子 Agent 对话：', ...lines]
    .join('\n')
    .slice(0, 6000);
}

export function usePageEditSubChat({
  pageId,
  pageTitle,
  parentSessionId,
  h5ApiBase,
  user,
  enabled,
  onSessionChange,
  onForkUnavailable,
}: {
  pageId: string;
  pageTitle: string;
  parentSessionId?: string | null;
  h5ApiBase?: string | null;
  user?: PortalUser | null;
  enabled: boolean;
  onSessionChange?: (sessionId: string | null) => void;
  onForkUnavailable?: () => void;
}) {
  const [session, setSession] = useState<Session | null>(null);
  const [messages, setMessages] = useState<Message[]>([]);
  const [chatState, setChatState] = useState<ChatState>('idle');
  const [error, setError] = useState<string | null>(null);
  const [notice, setNotice] = useState<string | null>(null);
  const [pendingTool, setPendingTool] = useState<ReturnType<typeof getToolConfirmation>>(null);

  const activeRequestId = useRef<string | null>(null);
  const unsubscribeRef = useRef<(() => void) | null>(null);
  const messagesRef = useRef<Message[]>([]);
  const sessionRef = useRef<Session | null>(null);
  const closingRef = useRef(false);
  const chatImageCategoryIdRef = useRef<string | null>(null);

  useEffect(() => {
    messagesRef.current = messages;
  }, [messages]);

  useEffect(() => {
    sessionRef.current = session;
  }, [session]);

  const dismissNotice = useCallback(() => setNotice(null), []);

  const resolveChatImageUploadCategoryId = useCallback(async () => {
    if (chatImageCategoryIdRef.current) return chatImageCategoryIdRef.current;

    const space = await getMindSpace();
    const category =
      space.categories.find((item) => item.code === 'private') ??
      space.categories.find((item) => item.code === 'oa') ??
      space.categories.find((item) => item.code === 'public') ??
      space.categories[0];
    if (!category) {
      throw new Error('当前空间暂无可用的图片上传分类');
    }
    chatImageCategoryIdRef.current = category.id;
    return category.id;
  }, []);

  const uploadChatImage = useCallback(async (file: File): Promise<string> => {
    if (!file.type.startsWith('image/')) {
      throw new Error('只支持图片文件');
    }
    const compressed = await compressImageForUpload(file, {
      maxInputBytes: CHAT_IMAGE_UPLOAD_MAX_INPUT_BYTES,
      maxOutputBytes: CHAT_IMAGE_UPLOAD_MAX_OUTPUT_BYTES,
      maxDimension: CHAT_IMAGE_MAX_SIDE,
    });
    const categoryId = await resolveChatImageUploadCategoryId();
    const asset = await uploadMindSpaceAsset(categoryId, compressed);
    return buildAbsoluteAssetImageUrl({ id: asset.id, updatedAt: asset.updatedAt });
  }, [resolveChatImageUploadCategoryId]);

  const processEvent = useCallback((event: SessionEvent, requestId: string) => {
    const raw = event as SessionEvent & { chat_request_id?: string; request_id?: string };
    const eventRequestId = raw.chat_request_id ?? raw.request_id;
    if (eventRequestId && eventRequestId !== requestId) return;

    switch (event.type) {
      case 'Message': {
        if (!event.message.metadata?.userVisible) return;
        setMessages((prev) => {
          const next = pushMessage(prev, event.message);
          messagesRef.current = next;
          return next;
        });
        const confirmation = getToolConfirmation(event.message);
        if (confirmation) {
          setPendingTool(confirmation);
          setChatState('waiting');
        } else {
          setChatState('streaming');
        }
        return;
      }
      case 'UpdateConversation':
        messagesRef.current = normalizeConversationMessages(
          event.conversation.filter((message) => message.metadata?.userVisible),
        );
        setMessages(messagesRef.current);
        return;
      case 'Error':
        setError(event.error);
        setChatState('error');
        activeRequestId.current = null;
        return;
      case 'Finish':
        setChatState('idle');
        setPendingTool(null);
        activeRequestId.current = null;
        return;
      default:
        return;
    }
  }, []);

  const connectSubSession = useCallback(
    async (sessionId: string) => {
      unsubscribeRef.current?.();
      unsubscribeRef.current = null;
      setChatState('loading');
      setError(null);
      setPendingTool(null);
      activeRequestId.current = null;

      await resumeSession(sessionId);
      const { session: detail, messages: history } = await loadSessionDetail(sessionId);
      const nextSession = { ...detail, id: sessionId };
      sessionRef.current = nextSession;
      setSession(nextSession);
      messagesRef.current = history;
      setMessages(history);
      setChatState('idle');

      unsubscribeRef.current = subscribeSessionEvents(
        sessionId,
        (event) => {
          const rid = activeRequestId.current;
          if (rid) processEvent(event, rid);
          else if (event.type === 'ActiveRequests' && event.request_ids.length > 0) {
            activeRequestId.current = event.request_ids[0];
            setChatState('streaming');
          }
        },
        (err) => {
          if (err instanceof ApiError && (err.status === 401 || err.status === 402)) return;
          setError(err.message);
        },
        { pauseWhenHidden: false },
      );
    },
    [processEvent],
  );

  const start = useCallback(async () => {
    if (!enabled || !parentSessionId || !pageId || closingRef.current) return;
    setChatState('loading');
    setError(null);
    try {
      const forked = await forkMindSpacePageEditSession(pageId, parentSessionId, h5ApiBase);
      onSessionChange?.(forked.sessionId);
      await connectSubSession(forked.sessionId);
    } catch (err) {
      if (
        err instanceof ApiError &&
        (err.status === 404 || err.code === 'not_found')
      ) {
        onForkUnavailable?.();
        setChatState('idle');
        setError(null);
        onSessionChange?.(null);
        return;
      }
      setError(err instanceof Error ? err.message : '无法启动页面编辑 Agent');
      setChatState('error');
      onSessionChange?.(null);
    }
  }, [
    connectSubSession,
    enabled,
    h5ApiBase,
    onForkUnavailable,
    onSessionChange,
    pageId,
    parentSessionId,
  ]);

  const close = useCallback(
    async (options?: { merge?: boolean }) => {
      const currentSession = sessionRef.current;
      if (!currentSession || closingRef.current) return;
      closingRef.current = true;
      unsubscribeRef.current?.();
      unsubscribeRef.current = null;

      try {
        if (options?.merge !== false) {
          const summary = buildPageEditSummary(messagesRef.current, pageTitle);
          if (summary) {
            await closeMindSpacePageEditSession(pageId, {
              sessionId: currentSession.id,
              parentSessionId,
              summary,
            });
          } else {
            await closeMindSpacePageEditSession(pageId, {
              sessionId: currentSession.id,
              parentSessionId,
              summary: '',
            });
          }
        }
      } catch {
        // best-effort merge on close
      } finally {
        onSessionChange?.(null);
        sessionRef.current = null;
        setSession(null);
        messagesRef.current = [];
        setMessages([]);
        setChatState('idle');
        setPendingTool(null);
        activeRequestId.current = null;
        closingRef.current = false;
      }
    },
    [pageId, pageTitle, parentSessionId, onSessionChange],
  );

  const submit = useCallback(
    async (text: string, context: MindSpaceChatContext, imageUrls?: string[]) => {
      const currentSession = sessionRef.current;
      const normalizedImageUrls = (imageUrls ?? []).filter((value) => typeof value === 'string' && value.trim());
      if (!currentSession || (!text.trim() && normalizedImageUrls.length === 0)) return;
      if (chatState === 'streaming' || chatState === 'loading' || chatState === 'connecting') return;

      const trimmed = text.trim();
      const mindspacePrefix = buildContextPrefix(context);
      const userPrefix = buildUserAddressPrefix(user);
      const agentPrefix = `${userPrefix}${mindspacePrefix}`;
      const userMessage = buildUserMessage(trimmed, {
        agentText: `${agentPrefix}${trimmed}`,
        displayText: trimmed,
        imageUrls: normalizedImageUrls,
      });
      const requestId = crypto.randomUUID();
      activeRequestId.current = requestId;
      messagesRef.current = [...messagesRef.current, userMessage];
      setMessages(messagesRef.current);
      setChatState('streaming');
      setError(null);
      setPendingTool(null);

      try {
        await sendReply(currentSession.id, requestId, userMessage);
      } catch (err) {
        if (err instanceof ApiError && err.status === 402) {
          setNotice('余额不足，请充值后继续使用');
          setChatState('idle');
        } else {
          setError(err instanceof Error ? err.message : String(err));
          setChatState('error');
        }
        activeRequestId.current = null;
      }
    },
    [chatState, user],
  );

  const stop = useCallback(async () => {
    const currentSession = sessionRef.current;
    if (!currentSession || !activeRequestId.current) return;
    try {
      await cancelRequest(currentSession.id, activeRequestId.current);
    } finally {
      activeRequestId.current = null;
      setChatState('idle');
    }
  }, []);

  const approveTool = useCallback(
    async (allow: boolean) => {
      const currentSession = sessionRef.current;
      if (!currentSession || !pendingTool) return;
      await confirmTool(currentSession.id, pendingTool.id, allow ? 'allow_once' : 'deny_once');
      setPendingTool(null);
      setChatState('streaming');
    },
    [pendingTool],
  );

  const retryConnect = useCallback(async () => {
    const currentSession = sessionRef.current;
    if (!currentSession) {
      await start();
      return;
    }
    try {
      await connectSubSession(currentSession.id);
    } catch (err) {
      setError(err instanceof Error ? err.message : String(err));
      setChatState('error');
    }
  }, [connectSubSession, start]);

  const startedRef = useRef(false);

  useEffect(() => {
    if (!enabled) {
      startedRef.current = false;
      return;
    }
    if (startedRef.current) return;
    startedRef.current = true;
    void start();
    return () => {
      startedRef.current = false;
      void close({ merge: true });
    };
  }, [close, enabled, pageId, parentSessionId, start]);

  return {
    session,
    messages,
    chatState,
    error,
    notice,
    pendingTool,
    submit,
    stop,
    approveTool,
    uploadChatImage,
    dismissNotice,
    retryConnect,
    openRecharge: () => setNotice('余额不足，请充值后继续使用'),
    close,
  };
}

export type PageEditSubChatBridge = ReturnType<typeof usePageEditSubChat>;
