import { ArrowLeft, ImagePlus, Paperclip, Send, Sparkles, X } from 'lucide-react';
import type { ChangeEvent } from 'react';
import { useEffect, useRef, useState } from 'react';

import {
  type CreationAgentProgressCopy,
  normalizeCreationAgentProgress,
  parseCreationAgentDocumentInput,
  resolveCreationAgentProgressHint,
} from '../../services/creation-agent';

export type CreationAgentAnchorView = {
  key: string;
  label: string;
  value: string;
  status: string;
};

export type CreationAgentMessageView = {
  id: string;
  role: string;
  kind?: string;
  text: string;
  createdAt?: string;
};

export type CreationAgentOperationView = {
  operationId?: string;
  type?: string;
  status: string;
  phaseLabel: string;
  phaseDetail?: string;
  progress: number;
  error?: string | null;
};

export type CreationAgentSessionView = {
  sessionId: string;
  title?: string | null;
  assistantSummary?: string | null;
  currentTurn: number;
  progressPercent: number;
  anchors: CreationAgentAnchorView[];
  messages: CreationAgentMessageView[];
  recommendedReplies?: string[];
};

export type CreationAgentTheme = {
  accentTextClass: string;
  accentBgClass: string;
  accentButtonClass: string;
  userBubbleClass: string;
  heroClass: string;
  anchorGridClass?: string;
};

export type CreationAgentQuickAction = {
  key: string;
  label: string;
  minTurn?: number;
  minProgress?: number;
  showWhenComplete?: boolean;
};

type CreationAgentWorkspaceProps = {
  session: CreationAgentSessionView | null;
  theme: CreationAgentTheme;
  loadingText: string;
  composerPlaceholder: string;
  primaryActionLabel: string;
  progressCopy?: CreationAgentProgressCopy;
  activeOperation?: CreationAgentOperationView | null;
  streamingReplyText?: string;
  isStreamingReply?: boolean;
  isBusy?: boolean;
  error?: string | null;
  quickActions?: CreationAgentQuickAction[];
  referenceImagePreviewSrc?: string | null;
  referenceImageLabel?: string | null;
  referenceImageError?: string | null;
  showBackButton?: boolean;
  onBack: () => void;
  onSubmitText: (text: string, quickActionKey?: string) => void;
  onPrimaryAction: () => void;
  onQuickAction?: (action: CreationAgentQuickAction) => void;
  onReferenceImageChange?: (file: File) => Promise<void> | void;
  onClearReferenceImage?: () => void;
};

const AUTO_SCROLL_FOLLOW_THRESHOLD_PX = 96;
const DOCUMENT_INPUT_ACCEPT =
  '.txt,.md,.markdown,.docx,.csv,.json,text/plain,text/markdown,text/csv,application/json,application/vnd.openxmlformats-officedocument.wordprocessingml.document';
const REFERENCE_IMAGE_INPUT_ACCEPT = 'image/png,image/jpeg,image/webp';

function uniqueRecommendedReplies(recommendedReplies: string[] = []) {
  return [
    ...new Set(recommendedReplies.map((reply) => reply.trim()).filter(Boolean)),
  ].slice(0, 3);
}

function CreationAgentOperationBanner({
  operation,
}: {
  operation: CreationAgentOperationView | null | undefined;
}) {
  const [visibleOperation, setVisibleOperation] =
    useState<CreationAgentOperationView | null>(operation ?? null);

  useEffect(() => {
    setVisibleOperation(operation ?? null);

    if (operation?.status !== 'completed') {
      return;
    }

    const timeoutId = window.setTimeout(() => {
      setVisibleOperation((current) =>
        current?.operationId === operation.operationId ? null : current,
      );
    }, 1200);

    return () => window.clearTimeout(timeoutId);
  }, [operation]);

  if (!visibleOperation) {
    return null;
  }

  const isFailed = visibleOperation.status === 'failed';
  const isRunning =
    visibleOperation.status === 'running' ||
    visibleOperation.status === 'queued';
  const bannerToneClass = isFailed
    ? 'platform-banner--danger'
    : isRunning
      ? 'platform-banner--info'
      : 'platform-banner--success';
  const progress = normalizeCreationAgentProgress(visibleOperation.progress);
  const progressFillStyle = isFailed
    ? { background: 'linear-gradient(90deg, #c7653d 0%, #a6402f 100%)' }
    : isRunning
      ? { background: 'var(--platform-button-primary-fill)' }
      : { background: 'linear-gradient(90deg, #86efac 0%, #34d399 100%)' };

  return (
    <div
      className={`platform-remap-surface platform-banner rounded-[1.4rem] px-4 py-4 ${bannerToneClass}`}
    >
      <div className="flex items-center justify-between gap-3">
        <div className="text-sm font-semibold">
          {visibleOperation.phaseLabel}
        </div>
        <div className="text-xs opacity-80">{progress}%</div>
      </div>
      {visibleOperation.phaseDetail ? (
        <div className="mt-1 text-xs opacity-80">
          {visibleOperation.phaseDetail}
        </div>
      ) : null}
      {visibleOperation.error ? (
        <div className="mt-2 text-sm opacity-90">{visibleOperation.error}</div>
      ) : null}
      <div className="platform-progress-track mt-3 h-2 overflow-hidden rounded-full">
        <div
          className="h-full rounded-full transition-[width] duration-300"
          style={{
            width: `${Math.max(8, progress)}%`,
            ...progressFillStyle,
          }}
        />
      </div>
    </div>
  );
}

function CreationAgentMessageBubble({
  message,
  theme,
  recommendedReplies,
  isStreaming = false,
  onRecommendedReply,
}: {
  message: CreationAgentMessageView;
  theme: CreationAgentTheme;
  recommendedReplies?: string[];
  isStreaming?: boolean;
  onRecommendedReply: (text: string) => void;
}) {
  const isUser = message.role === 'user';
  const isSystem = message.role === 'system';
  const visibleRecommendedReplies =
    isUser || isStreaming ? [] : uniqueRecommendedReplies(recommendedReplies);
  const bubbleToneClass = isUser
    ? theme.userBubbleClass
    : isSystem
      ? 'border border-[var(--platform-warm-border)] bg-[var(--platform-warm-bg)] text-[var(--platform-warm-text)]'
      : 'platform-subpanel text-[var(--platform-text-strong)]';

  return (
    <div className={`flex ${isUser ? 'justify-end' : 'justify-start'}`}>
      <div
        className={`max-w-[90%] rounded-[1.4rem] px-4 py-3 text-sm leading-7 break-words sm:max-w-[82%] ${bubbleToneClass}`}
      >
        {isStreaming ? (
          message.text ? (
            <div className="whitespace-pre-wrap">
              {message.text}
              <span
                className={`ml-1 inline-block h-4 w-1 animate-pulse rounded-full align-[-2px] ${theme.accentBgClass}`}
              />
            </div>
          ) : (
            <div
              data-testid="creation-agent-waiting-dots"
              aria-label="等待回复"
              className="flex items-center gap-1.5 py-1"
            >
              <span className="h-2 w-2 animate-pulse rounded-full bg-[var(--platform-text-soft)] [animation-delay:-0.2s]" />
              <span className="h-2 w-2 animate-pulse rounded-full bg-[var(--platform-text-soft)] [animation-delay:-0.1s]" />
              <span className="h-2 w-2 animate-pulse rounded-full bg-[var(--platform-text-soft)]" />
            </div>
          )
        ) : (
          <div className="whitespace-pre-wrap">{message.text}</div>
        )}
        {visibleRecommendedReplies.length > 0 ? (
          <div className="mt-2.5 flex flex-col gap-1.5">
            {visibleRecommendedReplies.map((reply, replyIndex) => (
              <button
                key={`recommended-reply-${replyIndex}-${reply}`}
                type="button"
                onClick={() => onRecommendedReply(reply)}
                className="platform-button platform-button--ghost min-h-0 justify-start rounded-[0.95rem] px-2.5 py-1.5 text-left text-[11px] leading-4.5 whitespace-normal"
              >
                {reply}
              </button>
            ))}
          </div>
        ) : null}
      </div>
    </div>
  );
}

function shouldShowQuickAction(
  action: CreationAgentQuickAction,
  session: CreationAgentSessionView,
  progress: number,
) {
  if (action.showWhenComplete && progress < 100) {
    return false;
  }

  if (
    typeof action.minTurn === 'number' &&
    session.currentTurn < action.minTurn
  ) {
    return false;
  }

  if (typeof action.minProgress === 'number' && progress < action.minProgress) {
    return false;
  }

  return true;
}

function isMessageListNearBottom(container: HTMLDivElement) {
  return (
    container.scrollHeight - container.scrollTop - container.clientHeight <=
    AUTO_SCROLL_FOLLOW_THRESHOLD_PX
  );
}

function scrollMessageListToBottom(container: HTMLDivElement) {
  if (typeof container.scrollTo === 'function') {
    container.scrollTo({
      top: container.scrollHeight,
      behavior: 'auto',
    });
    return;
  }

  container.scrollTop = container.scrollHeight;
}

export function CreationAgentWorkspace({
  session,
  theme,
  loadingText,
  composerPlaceholder,
  primaryActionLabel,
  progressCopy,
  activeOperation = null,
  streamingReplyText = '',
  isStreamingReply = false,
  isBusy = false,
  error = null,
  quickActions = [],
  referenceImagePreviewSrc = null,
  referenceImageLabel = null,
  referenceImageError = null,
  showBackButton = true,
  onBack,
  onSubmitText,
  onPrimaryAction,
  onQuickAction,
  onReferenceImageChange,
  onClearReferenceImage,
}: CreationAgentWorkspaceProps) {
  const [draftText, setDraftText] = useState('');
  const [documentInputError, setDocumentInputError] = useState<string | null>(
    null,
  );
  const [isParsingDocumentInput, setIsParsingDocumentInput] = useState(false);
  const [isReadingReferenceImage, setIsReadingReferenceImage] = useState(false);
  // 统一聊天区只在用户仍停留在底部附近时跟随新内容，避免流式回复持续抢走阅读位置。
  const messageListRef = useRef<HTMLDivElement | null>(null);
  const documentInputRef = useRef<HTMLInputElement | null>(null);
  const referenceImageInputRef = useRef<HTMLInputElement | null>(null);
  const shouldAutoScrollRef = useRef(true);

  useEffect(() => {
    const container = messageListRef.current;
    if (!container || !shouldAutoScrollRef.current) {
      return;
    }

    scrollMessageListToBottom(container);
  }, [
    session?.sessionId,
    session?.messages,
    streamingReplyText,
    isStreamingReply,
  ]);

  if (!session) {
    return (
      <div className="flex h-full items-center justify-center">
        <div className="platform-subpanel rounded-2xl px-5 py-4 text-sm text-[var(--platform-text-base)]">
          {error || loadingText}
        </div>
      </div>
    );
  }

  const progress = normalizeCreationAgentProgress(session.progressPercent);
  const progressFillWidth = progress <= 0 ? '0%' : `${Math.max(6, progress)}%`;
  const hasHeroCopy = Boolean(session.title || session.assistantSummary);
  const canShowPrimaryAction = progress >= 100;
  const visibleQuickActions = quickActions.filter((action) =>
    shouldShowQuickAction(action, session, progress),
  );
  const streamingMessageId = `streaming-assistant-${session.sessionId}`;
  // 用户消息提交后、首个流式文本到达前，也要立刻展示等待气泡。
  const shouldShowStreamingReply = isStreamingReply;
  const displayedMessages = shouldShowStreamingReply
    ? [
        ...session.messages,
        {
          id: streamingMessageId,
          role: 'assistant',
          kind: 'chat',
          text: streamingReplyText,
        } satisfies CreationAgentMessageView,
      ]
    : session.messages;
  const lastAssistantMessageIndex = session.messages.reduce(
    (lastIndex, message, index) =>
      message.role === 'assistant' ? index : lastIndex,
    -1,
  );

  const armAutoScrollToBottom = () => {
    shouldAutoScrollRef.current = true;
  };

  const handleMessageListScroll = () => {
    const container = messageListRef.current;
    if (!container) {
      return;
    }

    shouldAutoScrollRef.current = isMessageListNearBottom(container);
  };

  const submitRecommendedReply = (text: string) => {
    armAutoScrollToBottom();
    onSubmitText(text);
  };

  const submit = () => {
    const text = draftText.trim();
    if (!text || isBusy || isParsingDocumentInput || isReadingReferenceImage) {
      return;
    }

    armAutoScrollToBottom();
    onSubmitText(text);
    setDraftText('');
    setDocumentInputError(null);
  };

  const appendDocumentInputText = (text: string) => {
    setDraftText((current) => {
      const currentText = current.trimEnd();
      const nextText = text.trim();

      return currentText ? `${currentText}\n\n${nextText}` : nextText;
    });
  };

  const openDocumentInputPicker = () => {
    documentInputRef.current?.click();
  };

  const openReferenceImagePicker = () => {
    referenceImageInputRef.current?.click();
  };

  const handleDocumentInputChange = async (
    event: ChangeEvent<HTMLInputElement>,
  ) => {
    const file = event.target.files?.[0] ?? null;
    event.target.value = '';

    if (!file || isBusy || isParsingDocumentInput) {
      return;
    }

    setIsParsingDocumentInput(true);
    setDocumentInputError(null);

    try {
      const response = await parseCreationAgentDocumentInput(file);
      appendDocumentInputText(response.document.text);
    } catch (parseError) {
      setDocumentInputError(
        parseError instanceof Error
          ? parseError.message
          : '解析文档失败，请重新选择文件。',
      );
    } finally {
      setIsParsingDocumentInput(false);
    }
  };

  const handleReferenceImageInputChange = async (
    event: ChangeEvent<HTMLInputElement>,
  ) => {
    const file = event.target.files?.[0] ?? null;
    event.target.value = '';

    if (!file || isBusy || isReadingReferenceImage || !onReferenceImageChange) {
      return;
    }

    setIsReadingReferenceImage(true);

    try {
      await onReferenceImageChange(file);
    } finally {
      setIsReadingReferenceImage(false);
    }
  };

  return (
    <div className="mx-auto flex h-full min-h-0 w-full max-w-6xl flex-col gap-3 overflow-hidden px-1 sm:px-0">
      <div
        className={`creation-agent-hero relative overflow-hidden rounded-[1.8rem] px-4 py-4 text-white shadow-[0_20px_60px_rgba(15,23,42,0.18)] sm:px-5 ${theme.heroClass}`}
      >
        <div className="flex items-start justify-between gap-3">
          {showBackButton ? (
            <button
              type="button"
              aria-label="返回"
              onClick={onBack}
              disabled={isBusy}
              className="creation-agent-hero__icon-button inline-flex h-10 w-10 items-center justify-center rounded-full border border-white/20 bg-white/10 text-white/80 disabled:opacity-45"
            >
              <ArrowLeft className="h-4 w-4" />
            </button>
          ) : (
            <span aria-hidden="true" />
          )}
          {canShowPrimaryAction ? (
            <button
              type="button"
              disabled={isBusy}
              onClick={onPrimaryAction}
              className={`inline-flex items-center gap-2 rounded-full px-4 py-2 text-sm font-bold text-slate-950 shadow-lg disabled:cursor-not-allowed disabled:opacity-50 ${theme.accentButtonClass}`}
            >
              <Sparkles className="h-4 w-4" />
              {primaryActionLabel}
            </button>
          ) : null}
        </div>

        {hasHeroCopy ? (
          <div className="mt-6">
            {session.title ? (
              <div className="text-2xl font-black leading-tight sm:text-3xl">
                {session.title}
              </div>
            ) : null}
            {session.assistantSummary ? (
              <div className="creation-agent-hero__summary mt-2 max-w-2xl text-sm leading-6 text-white/75">
                {session.assistantSummary}
              </div>
            ) : null}
          </div>
        ) : null}

        <div className={hasHeroCopy ? 'mt-4' : 'mt-6'}>
          <div className="mb-2 flex items-center justify-between gap-3">
            <span className="creation-agent-hero__progress-label text-xs font-semibold tracking-[0.14em] text-white/75">
              创作进度
            </span>
            <span className="creation-agent-hero__progress-value text-sm font-semibold text-white/90">
              {progress}%
            </span>
          </div>
          <div
            className="creation-agent-hero__progress-track h-2 overflow-hidden rounded-full bg-white/20"
            role="progressbar"
            aria-valuemin={0}
            aria-valuemax={100}
            aria-valuenow={progress}
          >
            <div
              className={`h-full rounded-full transition-all ${theme.accentBgClass}`}
              style={{ width: progressFillWidth }}
            />
          </div>
          <div className="creation-agent-hero__progress-hint mt-2 text-xs leading-5 text-white/70">
            {resolveCreationAgentProgressHint(progress, progressCopy)}
          </div>
        </div>

        {visibleQuickActions.length > 0 ? (
          <div className="mt-4 flex flex-wrap gap-2">
            {visibleQuickActions.map((action) => (
              <button
                key={action.key}
                type="button"
                disabled={isBusy}
                onClick={() => onQuickAction?.(action)}
                className="creation-agent-hero__quick-action rounded-full border border-white/20 bg-white/10 px-3 py-1.5 text-xs font-semibold text-white/80 disabled:cursor-not-allowed disabled:opacity-45"
              >
                {action.label}
              </button>
            ))}
          </div>
        ) : null}
      </div>

      <CreationAgentOperationBanner operation={activeOperation} />

      <div className="min-h-0 flex-1 overflow-hidden rounded-[1.6rem] border border-[var(--platform-subpanel-border)] bg-[var(--platform-subpanel-fill)]">
        <div className="flex h-full min-h-0 flex-col">
          <div
            ref={messageListRef}
            data-testid="creation-agent-message-list"
            onScroll={handleMessageListScroll}
            className="min-h-0 flex-1 space-y-3 overflow-y-auto px-4 py-4"
          >
            {displayedMessages.length === 0 ? (
              <div className="flex h-full items-center justify-center text-sm text-[var(--platform-text-soft)]">
                暂无消息
              </div>
            ) : (
              displayedMessages.map((message, index) => (
                <CreationAgentMessageBubble
                  key={message.id || `message-${index}`}
                  message={message}
                  theme={theme}
                  isStreaming={message.id === streamingMessageId}
                  recommendedReplies={
                    message.id !== streamingMessageId &&
                    index === lastAssistantMessageIndex
                      ? session.recommendedReplies
                      : []
                  }
                  onRecommendedReply={submitRecommendedReply}
                />
              ))
            )}
          </div>

          {referenceImagePreviewSrc ? (
            <div className="mx-4 mb-3 flex items-center gap-3 rounded-[1rem] border border-[var(--platform-subpanel-border)] bg-white/70 px-3 py-2">
              <div className="h-12 w-12 shrink-0 overflow-hidden rounded-[0.9rem] bg-[var(--platform-track-fill)]">
                <img
                  src={referenceImagePreviewSrc}
                  alt="参考图"
                  className="h-full w-full object-cover"
                />
              </div>
              <div className="min-w-0 flex-1 truncate text-sm font-semibold text-[var(--platform-text-strong)]">
                {referenceImageLabel || '已选择参考图'}
              </div>
              {onClearReferenceImage ? (
                <button
                  type="button"
                  disabled={isBusy || isReadingReferenceImage}
                  onClick={onClearReferenceImage}
                  className="platform-icon-button h-9 w-9"
                  aria-label="移除参考图"
                  title="移除参考图"
                >
                  <X className="h-4 w-4" />
                </button>
              ) : null}
            </div>
          ) : null}

          {documentInputError || referenceImageError || error ? (
            <div className="mx-4 mb-3 rounded-[1rem] border border-red-200/70 bg-red-50 px-3 py-2 text-sm text-red-600">
              {documentInputError || referenceImageError || error}
            </div>
          ) : null}

          <div className="border-t border-[var(--platform-subpanel-border)] p-3">
            <div className="flex items-end gap-2 rounded-[1.25rem] bg-white/80 p-2">
              <input
                ref={documentInputRef}
                type="file"
                accept={DOCUMENT_INPUT_ACCEPT}
                className="hidden"
                onChange={handleDocumentInputChange}
              />
              {onReferenceImageChange ? (
                <input
                  ref={referenceImageInputRef}
                  type="file"
                  accept={REFERENCE_IMAGE_INPUT_ACCEPT}
                  className="hidden"
                  onChange={handleReferenceImageInputChange}
                />
              ) : null}
              <button
                type="button"
                aria-label={
                  isParsingDocumentInput ? '正在解析文档' : '上传文档'
                }
                title={isParsingDocumentInput ? '正在解析文档' : '上传文档'}
                aria-busy={isParsingDocumentInput}
                disabled={isBusy || isParsingDocumentInput}
                onClick={openDocumentInputPicker}
                className="inline-flex h-11 w-11 shrink-0 items-center justify-center rounded-full text-[var(--platform-text-base)] hover:bg-black/5 disabled:cursor-not-allowed disabled:opacity-40"
              >
                <Paperclip
                  className={`h-4 w-4 ${isParsingDocumentInput ? 'animate-pulse' : ''}`}
                />
              </button>
              {onReferenceImageChange ? (
                <button
                  type="button"
                  aria-label={
                    isReadingReferenceImage ? '正在读取参考图' : '上传参考图'
                  }
                  title={
                    isReadingReferenceImage ? '正在读取参考图' : '上传参考图'
                  }
                  aria-busy={isReadingReferenceImage}
                  disabled={isBusy || isReadingReferenceImage}
                  onClick={openReferenceImagePicker}
                  className="inline-flex h-11 w-11 shrink-0 items-center justify-center rounded-full text-[var(--platform-text-base)] hover:bg-black/5 disabled:cursor-not-allowed disabled:opacity-40"
                >
                  <ImagePlus
                    className={`h-4 w-4 ${isReadingReferenceImage ? 'animate-pulse' : ''}`}
                  />
                </button>
              ) : null}
              <textarea
                value={draftText}
                disabled={
                  isBusy || isParsingDocumentInput || isReadingReferenceImage
                }
                rows={2}
                onChange={(event) => {
                  setDraftText(event.target.value);
                  setDocumentInputError(null);
                }}
                onKeyDown={(event) => {
                  if (event.key === 'Enter' && !event.shiftKey) {
                    event.preventDefault();
                    submit();
                  }
                }}
                placeholder={composerPlaceholder}
                className="min-h-[3rem] flex-1 resize-none bg-transparent px-2 py-2 text-sm text-[var(--platform-text-strong)] outline-none placeholder:text-[var(--platform-text-soft)]"
              />
              <button
                type="button"
                aria-label="发送"
                disabled={
                  isBusy ||
                  isParsingDocumentInput ||
                  isReadingReferenceImage ||
                  !draftText.trim()
                }
                onClick={submit}
                className={`inline-flex h-11 w-11 items-center justify-center rounded-full text-white disabled:cursor-not-allowed disabled:opacity-40 ${theme.userBubbleClass}`}
              >
                <Send className="h-4 w-4" />
              </button>
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}

export default CreationAgentWorkspace;
