import {
  AimOutlined,
  MenuOutlined,
  RobotOutlined,
  RollbackOutlined,
} from '@ant-design/icons';
import { Tooltip } from 'antd';
import { useCallback, useEffect, useRef, useState } from 'react';
import AddDataModal from './AddDataModal';
import AddPageModal from './AddPageModal';
import DeleteDataConfirm from './DeleteDataConfirm';
import EditDataModal from './EditDataModal';
import { resolvePagePaths } from '../components/agentPanel/pagePathUtils';
import SkillMenu from './SkillMenu';
import './style.css';
import UndoConfirm from './UndoConfirm';

declare global {
  interface Window {
    ChatSDK: any;
  }
}

export interface PageContext {
  path: string;
  resourceName?: string;
  pageType?: string;
  sourceFilePath?: string;
}

function buildContextValue(ctx: PageContext | null): string | null {
  if (!ctx?.path) return null;
  const parts = ['## 更多的辅助信息：'];
  if (!ctx.resourceName) {
    parts.push('页面URL路径: ' + ctx.path);
    parts.push('当前文件: iframe指向的外部文件，无具体文件');
    return parts.join('\n');
  }
  const paths = resolvePagePaths(ctx.sourceFilePath, ctx.resourceName, '');
  parts.push('页面URL路径: ' + ctx.path);
  parts.push('所属的业务模块（模型）: ' + paths.modelName);
  if (ctx.pageType && ctx.pageType !== 'unknown')
    parts.push('页面类型: ' + ctx.pageType);
  if (ctx.sourceFilePath) parts.push('页面文件路径: web/' + ctx.sourceFilePath);
  parts.push('页面ui配置文件路径: ' + paths.uiConfigPath);
  parts.push('页面后端api文件路径: ' + paths.backendApiPath);
  parts.push('页面对应的数据模型文件目录: ' + paths.prismaDir);
  return parts.join('\n');
}

const PAGE_CONTEXT_KEY = 'current-page';
const AGENT_PANEL_WIDTH = 480;

export type ModalType =
  | 'addData'
  | 'addPage'
  | 'editData'
  | 'deleteData'
  | 'undo'
  | null;

export default function DevShell() {
  const iframeRef = useRef<HTMLIFrameElement>(null);
  const agentPanelRef = useRef<HTMLDivElement>(null);
  const sdkRef = useRef<any>(null);

  const [agentVisible, setAgentVisible] = useState(
    () => sessionStorage.getItem('gadmin-agent-visible') === 'true',
  );
  const [isInspecting, setIsInspecting] = useState(false);
  const [skillMenuOpen, setSkillMenuOpen] = useState(false);
  const [modal, setModal] = useState<ModalType>(null);
  const [isDataMngtPage, setIsDataMngtPage] = useState(false);
  const [pageType, setPageType] = useState<string>('');
  const pageContextRef = useRef<PageContext | null>(null);
  const inspectorSendDepthRef = useRef(0);

  // ── page context → SDK ───────────────────────────────────────────────────
  const applyPageContext = useCallback(() => {
    const sdk = sdkRef.current;
    if (!sdk) return;
    const value = buildContextValue(pageContextRef.current);
    sdk
      .removeAdditionContext(PAGE_CONTEXT_KEY)
      .catch(() => {})
      .finally(() => {
        if (!value) return;
        sdk
          .addAdditionContext({
            key: PAGE_CONTEXT_KEY,
            value,
            label: '📍 ' + (pageContextRef.current?.path || ''),
          })
          .catch((err: any) =>
            console.error('[DevShell] addAdditionContext failed:', err),
          );
      });
  }, []);

  // ── new-conversation + send prompt helper ───────────────────────────────
  // Always start a fresh conversation before sending a prompt. Mirrors the
  // SDK's own "新会话" button: `addConversation('新会话', true)` → emit
  // NEW_CONVERSATION → sendUserPrompt. The second arg `true` forces creation
  // even if the current conversation is empty (no id), so callers always get
  // a fresh slate.
  const startNewConversationAndSend = useCallback(
    async (sdk: any, prompt: string) => {
      await sdk.addConversation('新会话', true);
      // const NEW_CONV = window.ChatSDK?.ChatEventKey?.NEW_CONVERSATION;
      // if (NEW_CONV) sdk.emit(NEW_CONV, {});
      return sdk.sendUserPrompt(prompt);
    },
    [],
  );

  // ── send prompt helper ───────────────────────────────────────────────────
  const sendPromptToAgent = useCallback(
    (prompt: string) => {
      setAgentVisible(true);
      const sdk = sdkRef.current;
      if (!sdk) return;
      setTimeout(() => {
        startNewConversationAndSend(sdk, prompt).catch((err: any) =>
          console.error('[DevShell] sendUserPrompt failed:', err),
        );
      }, 300);
    },
    [startNewConversationAndSend],
  );

  // ── persist agent visibility ─────────────────────────────────────────────
  useEffect(() => {
    sessionStorage.setItem('gadmin-agent-visible', String(agentVisible));
  }, [agentVisible]);

  // ── SDK bootstrap ────────────────────────────────────────────────────────
  useEffect(() => {
    function tryInit(remaining: number) {
      if (window.ChatSDK) {
        window.ChatSDK.init({
          header: { logo: '', title: 'Coding Agent' },
          empty: '',
          streamingTimeout: 1800,
          initialConversation: false,
          service: {
            agentId: import.meta.env.VITE_AGENT_ID,
            baseURL: import.meta.env.VITE_AGENT_BASE_URL,
          },
          additionContext: { position: 'after', scope: 'persist' },
        })
          .then((instance: any) => {
            sdkRef.current = instance;
            if (agentPanelRef.current) instance.appendTo(agentPanelRef.current);
            instance.on(window.ChatSDK.ChatEventKey.CLOSE, () => {
              setAgentVisible(false);
              setSkillMenuOpen(false);
            });
            applyPageContext();
            console.log('[DevShell] Agent ready');
          })
          .catch((err: any) =>
            console.error('[DevShell] Agent init failed:', err),
          );
        return;
      }
      if (remaining <= 0) {
        console.error('[DevShell] ChatSDK load timeout');
        return;
      }
      setTimeout(() => tryInit(remaining - 200), 200);
    }
    tryInit(10000);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  // ── postMessage handler ──────────────────────────────────────────────────
  useEffect(() => {
    function handleMessage(e: MessageEvent) {
      const data = e.data || {};
      switch (data.type) {
        case 'OPEN_AGENT':
          setAgentVisible(true);
          break;
        case 'CLOSE_AGENT':
          setAgentVisible(false);
          break;
        case 'PAGE_CONTEXT_CHANGED': {
          const ctx: PageContext = data.payload || null;
          pageContextRef.current = ctx;
          setIsDataMngtPage(
            !!ctx?.path?.startsWith('/admin/data-mngt/') &&
              ['list', 'show', 'create', 'edit'].includes(ctx?.pageType ?? ''),
          );
          setPageType(ctx?.pageType ?? '');
          if (inspectorSendDepthRef.current === 0) applyPageContext();
          break;
        }
        case 'SEND_PROMPT': {
          setAgentVisible(true);
          const sdk = sdkRef.current;
          if (!sdk) break;
          if (data.inspectorSend) {
            inspectorSendDepthRef.current++;
            sdk
              .removeAdditionContext(PAGE_CONTEXT_KEY)
              .catch(() => {})
              .finally(() => {
                setTimeout(() => {
                  startNewConversationAndSend(sdk, data.payload)
                    .catch((err: any) =>
                      console.error('[DevShell] sendUserPrompt failed:', err),
                    )
                    .finally(() => {
                      inspectorSendDepthRef.current--;
                      if (inspectorSendDepthRef.current === 0)
                        applyPageContext();
                    });
                }, 300);
              });
          } else {
            setTimeout(() => {
              startNewConversationAndSend(sdk, data.payload).catch((err: any) =>
                console.error('[DevShell] sendUserPrompt failed:', err),
              );
            }, 300);
          }
          break;
        }
        case 'INSPECT_STATE':
          setIsInspecting(!!data.payload);
          break;
        case 'WORKFLOW_AGENT_REQUEST': {
          const sdk = sdkRef.current;
          const reqId = data.requestId;
          if (!sdk) {
            iframeRef.current?.contentWindow?.postMessage(
              {
                type: 'WORKFLOW_AGENT_ERROR',
                requestId: reqId,
                error: 'Agent not ready',
              },
              '*',
            );
            break;
          }
          setAgentVisible(true);

          setTimeout(() => {
            // Persistent listener: forward ALL agent responses until WORKFLOW_AGENT_DONE received
            const handleStreamStop = (...args: any[]) => {
              try {
                const rawContent = args[0]?.message?.content || '';
                const lines = rawContent.split('\n');
                let fullText = '';
                for (const line of lines) {
                  if (!line.trim()) continue;
                  try {
                    const event = JSON.parse(line);
                    if (event.type === 'TEXT_MESSAGE_CONTENT' && event.delta) {
                      fullText += event.delta;
                    }
                  } catch {
                    // skip non-JSON lines
                  }
                }
                if (fullText.length > 0) {
                  iframeRef.current?.contentWindow?.postMessage(
                    {
                      type: 'WORKFLOW_AGENT_MESSAGE',
                      requestId: reqId,
                      response: fullText,
                    },
                    '*',
                  );
                }
              } catch {
                // ignore parse errors
              }
            };

            // Listen for iframe signaling it got valid DSL or abort
            const handleDone = (e: MessageEvent) => {
              if (
                e.data?.type === 'WORKFLOW_AGENT_DONE' &&
                e.data?.requestId === reqId
              ) {
                cleanup();
              }
            };

            function cleanup() {
              const keys = window.ChatSDK?.ChatEventKey;
              if (keys?.STREAMING_STOP) {
                sdk.off(keys.STREAMING_STOP, handleStreamStop);
              }
              window.removeEventListener('message', handleDone);
            }

            window.addEventListener('message', handleDone);

            // Register persistent STREAMING_STOP listener
            const keys = window.ChatSDK?.ChatEventKey;
            if (keys?.STREAMING_STOP) {
              sdk.on(keys.STREAMING_STOP, handleStreamStop);
            }

            startNewConversationAndSend(sdk, data.prompt).catch((err: any) => {
              cleanup();
              iframeRef.current?.contentWindow?.postMessage(
                {
                  type: 'WORKFLOW_AGENT_ERROR',
                  requestId: reqId,
                  error: err?.message || 'Agent send failed',
                },
                '*',
              );
            });
          }, 300);
          break;
        }
      }
    }
    window.addEventListener('message', handleMessage);
    return () => window.removeEventListener('message', handleMessage);
  }, [applyPageContext, startNewConversationAndSend]);

  // ── Escape key stops inspect ─────────────────────────────────────────────
  useEffect(() => {
    function handleKeyDown(e: KeyboardEvent) {
      if (e.key === 'Escape' && isInspecting) {
        iframeRef.current?.contentWindow?.postMessage(
          { type: 'STOP_INSPECT' },
          '*',
        );
      }
    }
    document.addEventListener('keydown', handleKeyDown);
    return () => document.removeEventListener('keydown', handleKeyDown);
  }, [isInspecting]);

  const btnRight = agentVisible ? AGENT_PANEL_WIDTH + 12 : 12;
  const menuPopupRight = agentVisible ? AGENT_PANEL_WIDTH + 56 : 56;
  const iframeWidth = agentVisible
    ? `calc(100% - ${AGENT_PANEL_WIDTH}px)`
    : '100%';

  const getPageContext = () => pageContextRef.current;

  return (
    <>
      {/* App iframe */}
      <iframe
        ref={iframeRef}
        id="app-iframe"
        src="/app"
        title="Gadmin App"
        style={{ width: iframeWidth }}
      />

      {/* Agent panel */}
      <div
        ref={agentPanelRef}
        id="agent-panel"
        className={agentVisible ? 'visible' : ''}
      />

      {/* Toggle agent button */}
      <Tooltip title="Coding Agent" placement="left">
        <button
          id="toggle-btn"
          className={agentVisible ? 'active' : ''}
          style={{ right: btnRight, bottom: 24 }}
          onClick={() => {
            setAgentVisible((v) => {
              if (v) setSkillMenuOpen(false);
              return !v;
            });
          }}
        >
          <RobotOutlined />
        </button>
      </Tooltip>

      {/* Inspect button */}
      {agentVisible && (
        <Tooltip title="Inspect 元素 (Alt+I)" placement="left">
          <button
            id="inspect-btn"
            className={isInspecting ? 'active' : ''}
            style={{ right: btnRight, bottom: 64 }}
            onClick={() =>
              iframeRef.current?.contentWindow?.postMessage(
                { type: 'TOGGLE_INSPECT' },
                '*',
              )
            }
          >
            <AimOutlined />
          </button>
        </Tooltip>
      )}

      {/* Undo button */}
      {agentVisible && (
        <Tooltip title="回退上一步修改" placement="left">
          <button
            id="undo-btn"
            style={{ right: btnRight, bottom: 144 }}
            onClick={() => setModal('undo')}
          >
            <RollbackOutlined />
          </button>
        </Tooltip>
      )}

      {/* Menu button */}
      {agentVisible && (
        <Tooltip title="快捷操作菜单" placement="left">
          <button
            id="menu-btn"
            className={skillMenuOpen ? 'active' : ''}
            style={{ right: btnRight, bottom: 104 }}
            onClick={(e) => {
              e.stopPropagation();
              setSkillMenuOpen((v) => !v);
            }}
          >
            <MenuOutlined />
          </button>
        </Tooltip>
      )}

      {/* Skill menu */}
      <SkillMenu
        open={skillMenuOpen}
        popupRight={menuPopupRight}
        isDataMngtList={isDataMngtPage}
        pageType={pageType}
        onClose={() => setSkillMenuOpen(false)}
        onAddData={() => {
          setSkillMenuOpen(false);
          setModal('addData');
        }}
        onAddPage={() => {
          setSkillMenuOpen(false);
          setModal('addPage');
        }}
        onEditData={() => {
          setSkillMenuOpen(false);
          setModal('editData');
        }}
        onDeleteData={() => {
          setSkillMenuOpen(false);
          setModal('deleteData');
        }}
        onFormSkill={(skill, label) => {
          setSkillMenuOpen(false);
          sendPromptToAgent(`使用 ${skill} skill，${label}`);
        }}
      />

      {/* Modals */}
      {modal === 'undo' && (
        <UndoConfirm
          onConfirm={(prompt) => {
            setModal(null);
            sendPromptToAgent(prompt);
          }}
          onCancel={() => setModal(null)}
        />
      )}
      {modal === 'addData' && (
        <AddDataModal
          onConfirm={(prompt) => {
            setModal(null);
            sendPromptToAgent(prompt);
          }}
          onCancel={() => setModal(null)}
        />
      )}
      {modal === 'addPage' && (
        <AddPageModal
          getIframe={() => iframeRef.current}
          onConfirm={(prompt) => {
            setModal(null);
            sendPromptToAgent(prompt);
          }}
          onCancel={() => setModal(null)}
          onGoAddData={() => {
            setModal('addData');
          }}
        />
      )}
      {modal === 'editData' && (
        <EditDataModal
          getPageContext={getPageContext}
          onConfirm={(prompt) => {
            setModal(null);
            sendPromptToAgent(prompt);
          }}
          onCancel={() => setModal(null)}
        />
      )}
      {modal === 'deleteData' && (
        <DeleteDataConfirm
          getPageContext={getPageContext}
          onConfirm={(prompt) => {
            setModal(null);
            sendPromptToAgent(prompt);
          }}
          onCancel={() => setModal(null)}
        />
      )}
    </>
  );
}
