import { ClockCircleOutlined, EyeOutlined, LoadingOutlined, StopOutlined, UndoOutlined } from '@ant-design/icons';
import { Button, Drawer, Empty, Modal, Space, Typography, message } from 'antd';
import { useEffect, useRef, useState } from 'react';
import { renderModalWithEnterConfirm } from '../modalKeyboard';
import {
  cancelChatRuntimeJob,
  fetchChatRuntimeJobDetail,
  removeChatRuntimeJob,
  rollbackChatRuntimeJob,
} from './chatUtils';
import type { ChatRuntimeJobDetail, ChatRuntimeJobItem, ChatRuntimeSnapshot } from './types';

const { Paragraph, Text } = Typography;

function formatRuntimeTime(value: string | null) {
  if (!value) {
    return '-';
  }

  const parsed = new Date(value);

  if (Number.isNaN(parsed.getTime())) {
    return value;
  }

  return parsed.toLocaleTimeString('ko-KR', {
    hour: '2-digit',
    minute: '2-digit',
    second: '2-digit',
    hour12: false,
  });
}

function buildTerminalLabel(terminalStatus: ChatRuntimeJobDetail['terminalStatus']) {
  if (!terminalStatus) {
    return '';
  }

  if (terminalStatus === 'cancelled') {
    return '취소됨';
  }

  if (terminalStatus === 'removed') {
    return '대기열 제거됨';
  }

  if (terminalStatus === 'failed') {
    return '실패';
  }

  return '완료';
}

function RuntimeJobList({
  title,
  emptyDescription,
  items,
  activeSessionId,
  onSelectSession,
  onOpenLog,
  onCancelJob,
  onRemoveJob,
  pendingActionRequestId,
}: {
  title: string;
  emptyDescription: string;
  items: ChatRuntimeJobItem[];
  activeSessionId: string;
  onSelectSession: (sessionId: string) => void;
  onOpenLog: (requestId: string) => void;
  onCancelJob: (requestId: string) => void;
  onRemoveJob: (requestId: string) => void;
  pendingActionRequestId: string | null;
}) {
  return (
    <section className="app-chat-runtime__section">
      <div className="app-chat-runtime__section-header">
        <Text strong>{title}</Text>
        <Text type="secondary">{items.length}건</Text>
      </div>

      {items.length === 0 ? (
        <div className="app-chat-runtime__empty">
          <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} description={emptyDescription} />
        </div>
      ) : (
        <div className="app-chat-runtime__list">
          {items.map((item) => (
            <article
              key={`${item.status}-${item.requestId}`}
              className={`app-chat-runtime__job${item.sessionId === activeSessionId ? ' app-chat-runtime__job--active' : ''}`}
            >
              <div className="app-chat-runtime__job-top">
                <div className="app-chat-runtime__job-headline">
                  <Text strong>{item.status === 'running' ? '실행 중' : '대기 중'}</Text>
                  <Text type="secondary">{item.mode === 'direct' ? '즉시' : '큐'}</Text>
                </div>
                <Space size={8} wrap className="app-chat-runtime__job-actions">
                  <Button
                    size="small"
                    icon={<EyeOutlined />}
                    onClick={() => {
                      onSelectSession(item.sessionId);
                    }}
                  >
                    세션 보기
                  </Button>
                  <Button
                    size="small"
                    onClick={() => {
                      onOpenLog(item.requestId);
                    }}
                  >
                    로그
                  </Button>
                  {item.status === 'running' ? (
                    <Button
                      size="small"
                      danger
                      icon={<StopOutlined />}
                      loading={pendingActionRequestId === item.requestId}
                      onClick={() => {
                        onCancelJob(item.requestId);
                      }}
                    >
                      취소
                    </Button>
                  ) : (
                    <Button
                      size="small"
                      danger
                      loading={pendingActionRequestId === item.requestId}
                      onClick={() => {
                        onRemoveJob(item.requestId);
                      }}
                    >
                      제거
                    </Button>
                  )}
                </Space>
              </div>
              <Text className="app-chat-runtime__job-summary">{item.summary || '요약 없음'}</Text>
              <div className="app-chat-runtime__job-meta">
                <Text type="secondary">세션: {item.sessionId}</Text>
                <Text type="secondary">요청: {item.requestId}</Text>
                <Text type="secondary">대기 시작: {formatRuntimeTime(item.enqueuedAt)}</Text>
                <Text type="secondary">실행 시작: {formatRuntimeTime(item.startedAt)}</Text>
                <Text type="secondary">PID: {item.pid ?? '-'}</Text>
              </div>
            </article>
          ))}
        </div>
      )}
    </section>
  );
}

function RecentRuntimeList({
  items,
  onSelectSession,
  onOpenLog,
  onRollbackJob,
  pendingActionRequestId,
}: {
  items: ChatRuntimeSnapshot['recent'];
  onSelectSession: (sessionId: string) => void;
  onOpenLog: (requestId: string) => void;
  onRollbackJob: (requestId: string, sessionId: string) => void;
  pendingActionRequestId: string | null;
}) {
  return (
    <section className="app-chat-runtime__section app-chat-runtime__section--recent">
      <div className="app-chat-runtime__section-header">
        <Text strong>최근 작업</Text>
        <Text type="secondary">{items.length}건</Text>
      </div>
      {items.length === 0 ? (
        <div className="app-chat-runtime__empty">
          <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} description="아직 종료된 작업 이력이 없습니다." />
        </div>
      ) : (
        <div className="app-chat-runtime__list">
          {items.map((item) => (
            <article key={`recent-${item.requestId}-${item.lastUpdatedAt}`} className="app-chat-runtime__job">
              <div className="app-chat-runtime__job-top">
                <div className="app-chat-runtime__job-headline">
                  <Text strong>{buildTerminalLabel(item.terminalStatus)}</Text>
                  <Text type="secondary">{item.mode === 'direct' ? '즉시' : '큐'}</Text>
                </div>
                <Space size={8} wrap className="app-chat-runtime__job-actions">
                  <Button
                    size="small"
                    onClick={() => {
                      onOpenLog(item.requestId);
                    }}
                  >
                    로그
                  </Button>
                  <Button
                    size="small"
                    icon={<UndoOutlined />}
                    disabled={item.terminalStatus !== 'completed' && item.terminalStatus !== 'failed'}
                    loading={pendingActionRequestId === item.requestId}
                    onClick={() => {
                      onRollbackJob(item.requestId, item.sessionId);
                    }}
                  >
                    롤백
                  </Button>
                  <Button
                    size="small"
                    onClick={() => {
                      onSelectSession(item.sessionId);
                    }}
                  >
                    채팅방 이동
                  </Button>
                </Space>
              </div>
              <Text className="app-chat-runtime__job-summary">{item.summary || '요약 없음'}</Text>
              <div className="app-chat-runtime__job-meta">
                <Text type="secondary">세션: {item.sessionId}</Text>
                <Text type="secondary">요청: {item.requestId}</Text>
                <Text type="secondary">종료 시각: {formatRuntimeTime(item.lastUpdatedAt)}</Text>
                <Text type="secondary">PID: {item.pid ?? '-'}</Text>
              </div>
            </article>
          ))}
        </div>
      )}
    </section>
  );
}

export function ChatRuntimeDashboard({
  snapshot,
  activeSessionId,
  connectionState,
  onSelectSession,
  socketRef,
  liveDetail,
  requestedLogRequestId,
  onRequestedLogHandled,
}: {
  snapshot: ChatRuntimeSnapshot | null;
  activeSessionId: string;
  connectionState: 'connecting' | 'connected' | 'disconnected';
  onSelectSession: (sessionId: string) => void;
  socketRef: { current: WebSocket | null };
  liveDetail: ChatRuntimeJobDetail | null;
  requestedLogRequestId?: string | null;
  onRequestedLogHandled?: () => void;
}) {
  const sessions = snapshot?.sessions ?? [];
  const [messageApi, messageContextHolder] = message.useMessage();
  const [modalApi, modalContextHolder] = Modal.useModal();
  const [selectedDetail, setSelectedDetail] = useState<ChatRuntimeJobDetail | null>(null);
  const [isLogModalOpen, setIsLogModalOpen] = useState(false);
  const [logLoadError, setLogLoadError] = useState('');
  const [isLogLoading, setIsLogLoading] = useState(false);
  const [pendingActionRequestId, setPendingActionRequestId] = useState<string | null>(null);
  const logViewerRef = useRef<HTMLPreElement | null>(null);

  const confirmAction = (options: {
    title: string;
    content: string;
    okText: string;
    cancelText?: string;
  }) =>
    new Promise<boolean>((resolve) => {
      modalApi.confirm({
        title: options.title,
        content: options.content,
        okText: options.okText,
        cancelText: options.cancelText ?? '닫기',
        autoFocusButton: 'ok',
        modalRender: renderModalWithEnterConfirm,
        onOk: () => resolve(true),
        onCancel: () => resolve(false),
      });
    });

  useEffect(() => {
    return () => {
      messageApi.destroy();
    };
  }, [messageApi]);

  const loadLogDetail = async (requestId: string) => {
    setIsLogLoading(true);
    setLogLoadError('');

    try {
      const detail = await fetchChatRuntimeJobDetail(requestId);
      setSelectedDetail(detail);
    } catch (error) {
      setSelectedDetail(null);
      setLogLoadError(error instanceof Error ? error.message : '실행 로그를 불러오지 못했습니다.');
    } finally {
      setIsLogLoading(false);
    }
  };

  const openLog = async (requestId: string) => {
    setIsLogModalOpen(true);
    await loadLogDetail(requestId);
  };

  const handleCancel = async (requestId: string) => {
    const confirmed = await confirmAction({
      title: '실행 중 요청을 취소할까요?',
      content: '이미 실행 중인 Codex 프로세스에 종료 신호를 보냅니다.',
      okText: '취소 실행',
    });

    if (!confirmed) {
      return;
    }

    setPendingActionRequestId(requestId);

    try {
      await cancelChatRuntimeJob(requestId);
      messageApi.success('취소 요청을 보냈습니다.');
      if (selectedDetail?.item?.requestId === requestId) {
        await loadLogDetail(requestId);
      }
    } catch (error) {
      messageApi.error(error instanceof Error ? error.message : '실행 취소 요청에 실패했습니다.');
    } finally {
      setPendingActionRequestId(null);
    }
  };

  const handleRemove = async (requestId: string) => {
    const confirmed = await confirmAction({
      title: '대기열 요청을 제거할까요?',
      content: '아직 실행되지 않은 대기 요청만 제거됩니다.',
      okText: '제거',
    });

    if (!confirmed) {
      return;
    }

    setPendingActionRequestId(requestId);

    try {
      await removeChatRuntimeJob(requestId);
      messageApi.success('대기 요청을 제거했습니다.');
      if (selectedDetail?.item?.requestId === requestId) {
        await loadLogDetail(requestId);
      }
    } catch (error) {
      messageApi.error(error instanceof Error ? error.message : '대기 요청 제거에 실패했습니다.');
    } finally {
      setPendingActionRequestId(null);
    }
  };

  const handleRollback = async (requestId: string, sessionId: string) => {
    const confirmed = await confirmAction({
      title: '최근 실행 변경을 롤백할까요?',
      content: '이 실행이 남긴 diff만 역적용합니다. 이후 다른 세션이 같은 라인을 수정했다면 실패할 수 있습니다.',
      okText: '롤백',
    });

    if (!confirmed) {
      return;
    }

    setPendingActionRequestId(requestId);

    try {
      await rollbackChatRuntimeJob(requestId, sessionId);
      messageApi.success('최근 실행 변경을 롤백했습니다.');
      if (selectedDetail?.item?.requestId === requestId) {
        await loadLogDetail(requestId);
      }
    } catch (error) {
      messageApi.error(error instanceof Error ? error.message : '최근 실행 롤백에 실패했습니다.');
    } finally {
      setPendingActionRequestId(null);
    }
  };

  useEffect(() => {
    if (!isLogModalOpen || !selectedDetail?.item?.requestId || !liveDetail?.item?.requestId) {
      return;
    }

    if (selectedDetail.item.requestId !== liveDetail.item.requestId) {
      return;
    }

    setSelectedDetail(liveDetail);
  }, [isLogModalOpen, liveDetail, selectedDetail?.item?.requestId]);

  useEffect(() => {
    const socket = socketRef.current;

    if (!socket || socket.readyState !== WebSocket.OPEN) {
      return;
    }

    socket.send(
      JSON.stringify({
        type: 'runtime:watch',
        payload: {
          requestId: isLogModalOpen ? selectedDetail?.item?.requestId ?? null : null,
        },
      }),
    );
  }, [isLogModalOpen, selectedDetail?.item?.requestId, socketRef]);

  useEffect(() => {
    if (!isLogModalOpen || !logViewerRef.current) {
      return;
    }

    logViewerRef.current.scrollTop = logViewerRef.current.scrollHeight;
  }, [isLogModalOpen, selectedDetail?.logs]);

  useEffect(() => {
    const requestId = requestedLogRequestId?.trim();

    if (!requestId) {
      return;
    }

    setIsLogModalOpen(true);
    void loadLogDetail(requestId).finally(() => {
      onRequestedLogHandled?.();
    });
  }, [onRequestedLogHandled, requestedLogRequestId]);

  return (
    <>
      {messageContextHolder}
      {modalContextHolder}
      <div className="app-chat-runtime">
        <div className="app-chat-runtime__summary-strip">
          <div className="app-chat-runtime__summary-card">
            <div className="app-chat-runtime__summary-metric">
              <LoadingOutlined />
              <Text type="secondary">실행 중</Text>
              <Text strong>{snapshot?.runningCount ?? 0}건</Text>
            </div>
            <div className="app-chat-runtime__summary-metric">
              <ClockCircleOutlined />
              <Text type="secondary">대기열</Text>
              <Text strong>{snapshot?.queuedCount ?? 0}건</Text>
            </div>
            <div className="app-chat-runtime__summary-metric">
              <EyeOutlined />
              <Text type="secondary">활성 세션</Text>
              <Text strong>{snapshot?.sessionCount ?? 0}개</Text>
            </div>
            <Text type="secondary" className="app-chat-runtime__summary-status">
              {connectionState === 'connected' ? '실시간' : connectionState === 'connecting' ? '재연결 중' : '연결 끊김'}
            </Text>
          </div>
        </div>

        <div className="app-chat-runtime__session-strip">
          {sessions.length === 0 ? (
            <Text type="secondary">현재 활성 큐/실행 세션이 없습니다.</Text>
          ) : (
            sessions.map((session) => (
              <button
                key={session.sessionId}
                type="button"
                className={`app-chat-runtime__session-chip${
                  session.sessionId === activeSessionId ? ' app-chat-runtime__session-chip--active' : ''
                }`}
                onClick={() => {
                  onSelectSession(session.sessionId);
                }}
              >
                <span>{session.sessionId}</span>
                <span>{`실행 ${session.runningCount} · 대기 ${session.queuedCount}`}</span>
              </button>
            ))
          )}
        </div>

        <div className="app-chat-runtime__content">
          <RuntimeJobList
            title="실제 실행 중인 요청"
            emptyDescription="현재 실행 중인 Codex 요청이 없습니다."
            items={snapshot?.running ?? []}
            activeSessionId={activeSessionId}
            onSelectSession={onSelectSession}
            onOpenLog={openLog}
            onCancelJob={handleCancel}
            onRemoveJob={handleRemove}
            pendingActionRequestId={pendingActionRequestId}
          />
          <RuntimeJobList
            title="실제 대기열"
            emptyDescription="현재 대기 중인 요청이 없습니다."
            items={snapshot?.queued ?? []}
            activeSessionId={activeSessionId}
            onSelectSession={onSelectSession}
            onOpenLog={openLog}
            onCancelJob={handleCancel}
            onRemoveJob={handleRemove}
            pendingActionRequestId={pendingActionRequestId}
          />
          <RecentRuntimeList
            items={snapshot?.recent ?? []}
            onSelectSession={onSelectSession}
            onOpenLog={openLog}
            onRollbackJob={handleRollback}
            pendingActionRequestId={pendingActionRequestId}
          />
        </div>
      </div>

      <Drawer
        open={isLogModalOpen}
        title="실행 로그"
        placement="right"
        width="100vw"
        rootClassName="app-chat-runtime__drawer"
        styles={{
          body: {
            padding: 0,
          },
        }}
        onClose={() => {
          setIsLogModalOpen(false);
          setSelectedDetail(null);
        }}
      >
        {isLogLoading ? (
          <div className="app-chat-runtime__log-state">
            <Text type="secondary">로그를 불러오는 중입니다.</Text>
          </div>
        ) : logLoadError ? (
          <div className="app-chat-runtime__log-state">
            <Text type="danger">{logLoadError}</Text>
          </div>
        ) : selectedDetail ? (
          <div className="app-chat-runtime__log-modal">
            {selectedDetail.item?.sessionId ? (
              <Button
                size="small"
                style={{ alignSelf: 'flex-start' }}
                onClick={() => {
                  onSelectSession(selectedDetail.item?.sessionId ?? '');
                  setIsLogModalOpen(false);
                }}
              >
                채팅방 이동
              </Button>
            ) : null}
            <div className="app-chat-runtime__job-meta">
              <Text type="secondary">요청: {selectedDetail.item?.requestId ?? '-'}</Text>
              <Text type="secondary">세션: {selectedDetail.item?.sessionId ?? '-'}</Text>
              <Text type="secondary">마지막 갱신: {formatRuntimeTime(selectedDetail.lastUpdatedAt)}</Text>
              <Text type="secondary">종료 상태: {buildTerminalLabel(selectedDetail.terminalStatus) || '-'}</Text>
            </div>
            <Paragraph className="app-chat-runtime__job-summary">
              {selectedDetail.item?.summary ?? '요약 없음'}
            </Paragraph>
            <pre ref={logViewerRef} className="app-chat-runtime__log-viewer">
              {selectedDetail.logs.length > 0 ? selectedDetail.logs.join('\n') : '아직 기록된 로그가 없습니다.'}
            </pre>
          </div>
        ) : (
          <div className="app-chat-runtime__log-state">
            <Text type="secondary">표시할 로그가 없습니다.</Text>
          </div>
        )}
      </Drawer>
    </>
  );
}
