import React, { useMemo, useState } from 'react';
import {
  CheckCircleOutlined,
  CloseCircleOutlined,
  LoadingOutlined,
  TableOutlined,
} from '@ant-design/icons';
import FileCard from '@ant-design/x/es/file-card';
import Sources from '@ant-design/x/es/sources';
import Think from '@ant-design/x/es/think';
import ThoughtChain from '@ant-design/x/es/thought-chain';
import type { ThoughtChainItemType } from '@ant-design/x';
import XMarkdown, { type ComponentProps } from '@ant-design/x-markdown';
import { Alert, Button, Flex, Input, Space, Typography } from 'antd';
import { useUserStore } from '../../store/user/userStore';
import { message } from '../../ui/app-message';
import { DynamicChart } from './DynamicChart';
import { DynamicForm } from './DynamicForm';
import { DynamicReview } from './DynamicReview';
import { ArtifactErrorBoundary } from './ArtifactErrorBoundary';
import { LiteCodeHighlighter } from './LiteCodeHighlighter';
import { LiteMermaid } from './LiteMermaid';
import type {
  AiAttachment,
  AiChatMessage,
  AiChatMessageStatus,
  AiChartSchema,
  AiFormSchema,
  AiImportWizard,
  AiReviewSection,
  AiReviewSchema,
  AiReviewSectionType,
  AiToolRun,
} from './types';

const toolLabels: Record<string, string> = {
  search_students: '查询学生',
  get_student_basic: '读取学生信息',
  search_classes: '查询班级',
  get_attendance_summary: '统计考勤',
  search_rooms: '查询房间',
  get_room_occupancy_summary: '统计入住',
  search_bills: '查询账单',
  get_dashboard_stats: '读取经营概览',
  render_form: '生成表单',
  render_review: '生成导入预览',
  render_chart: '生成图表',
  start_import_wizard: '生成导入向导',
  create_student: '创建学生',
  search_exams: '查询考试',
  search_schedules: '查询课表',
  search_deposits: '查询押金',
  search_expenses: '查询费用',
  search_classrooms: '查询教室',
  search_classroom_rentals: '查询教室租用',
  get_sync_status: '查询同步状态',
  get_business_context: '读取业务流程',
  get_entity_schema: '读取实体字典',
  get_pending_tasks: '查询业务待办',
};

const markdownComponents = {
  code: ({ children, lang, block }: ComponentProps) => {
    const content = String(children ?? '').replace(/\n$/, '');
    if (!block) return <code>{content}</code>;
    if (lang === 'mermaid') return <LiteMermaid>{content}</LiteMermaid>;
    return <LiteCodeHighlighter lang={lang}>{content}</LiteCodeHighlighter>;
  },
};

const markdownSanitizerConfig = {
  ALLOW_UNKNOWN_PROTOCOLS: false,
  FORBID_TAGS: ['script', 'style', 'iframe', 'object', 'embed', 'form'],
  FORBID_ATTR: ['style'],
};

function attachmentIcon(attachment: AiAttachment) {
  if (attachment.mimeType === 'application/pdf') return 'pdf' as const;
  if (attachment.mimeType.includes('wordprocessingml')) return 'word' as const;
  if (attachment.mimeType.includes('spreadsheetml')) return 'excel' as const;
  if (attachment.mimeType.startsWith('image/')) return 'image' as const;
  return 'default' as const;
}

async function openAttachment(attachment: AiAttachment): Promise<void> {
  const token = useUserStore.getState().token;
  const response = await fetch(attachment.url, {
    headers: token ? { Authorization: `Bearer ${token}` } : undefined,
  });
  if (!response.ok) throw new Error('附件打开失败');
  const objectUrl = URL.createObjectURL(await response.blob());
  window.open(objectUrl, '_blank', 'noopener,noreferrer');
  window.setTimeout(() => URL.revokeObjectURL(objectUrl), 60_000);
}

async function openSourceUrl(item: { url?: string }): Promise<void> {
  if (!item.url) return;
  const token = useUserStore.getState().token;
  const response = await fetch(item.url, {
    headers: token ? { Authorization: `Bearer ${token}` } : undefined,
  });
  if (!response.ok) throw new Error('来源打开失败');
  const objectUrl = URL.createObjectURL(await response.blob());
  window.open(objectUrl, '_blank', 'noopener,noreferrer');
  window.setTimeout(() => URL.revokeObjectURL(objectUrl), 60_000);
}

/** 打开附件，失败时给出明确提示（避免「点了没反应」） */
async function handleOpenAttachment(attachment: AiAttachment): Promise<void> {
  try {
    await openAttachment(attachment);
  } catch (error: unknown) {
    message.error(error instanceof Error ? error.message : '附件打开失败，请重试');
  }
}

/** 打出来源链接，失败时给出明确提示 */
async function handleOpenSource(item: { url?: string }): Promise<void> {
  try {
    await openSourceUrl(item);
  } catch (error: unknown) {
    message.error(error instanceof Error ? error.message : '来源打开失败，请重试');
  }
}

function ToolChain({ tools }: { tools: AiToolRun[] }) {
  const items = useMemo<ThoughtChainItemType[]>(
    () =>
      tools.map((tool) => {
        const running = tool.status === 'running';
        const success = tool.status === 'success';
        return {
          key: tool.toolCallId,
          title: toolLabels[tool.toolName] || tool.toolName,
          description: tool.durationMs ? `${tool.durationMs}ms` : undefined,
          content:
            tool.summary || (running ? '正在查询业务数据' : success ? '查询完成' : '查询失败'),
          status: running ? 'loading' : success ? 'success' : 'error',
          icon: running ? (
            <LoadingOutlined spin />
          ) : success ? (
            <CheckCircleOutlined />
          ) : (
            <CloseCircleOutlined />
          ),
          collapsible: Boolean(tool.summary),
        };
      }),
    [tools],
  );
  return <ThoughtChain items={items} line="solid" />;
}

function EditUserContent({
  initial,
  onConfirm,
  onCancel,
}: {
  initial: string;
  onConfirm: (value: string) => void;
  onCancel?: () => void;
}) {
  const [draft, setDraft] = useState(initial);
  return (
    <Space orientation="vertical" size={8} className="ai-chat-user-edit">
      <Input.TextArea
        value={draft}
        onChange={(event) => setDraft(event.target.value)}
        autoSize={{ minRows: 2, maxRows: 8 }}
        onKeyDown={(event) => {
          // 中文输入法合成中的回车不应触发保存
          if (event.nativeEvent.isComposing || event.keyCode === 229) return;
          if (event.key === 'Enter' && !event.shiftKey) {
            event.preventDefault();
            onConfirm(draft);
          } else if (event.key === 'Escape') {
            onCancel?.();
          }
        }}
      />
      <Flex gap={8} justify="flex-end">
        <Button size="small" onClick={onCancel}>
          取消
        </Button>
        <Button size="small" type="primary" onClick={() => onConfirm(draft)}>
          保存
        </Button>
      </Flex>
    </Space>
  );
}

export interface AiMessageContentProps {
  message: AiChatMessage;
  status?: AiChatMessageStatus;
  editing?: boolean;
  onEditConfirm?: (value: string) => void;
  onEditCancel?: () => void;
  onSubmitForm?: (form: AiFormSchema, values: Record<string, unknown>) => void;
  onSubmitReview?: (reviewId: string, reviewTitle?: string) => void;
  onConfirmReviewStep?: (
    messageId: number | undefined,
    reviewId: string,
    sectionKey: AiReviewSection['key'],
  ) => AiReviewSchema | Promise<AiReviewSchema> | void;
  onConfirmReviewGroup?: (
    messageId: number | undefined,
    reviewId: string,
    type: AiReviewSectionType,
  ) => AiReviewSchema | Promise<AiReviewSchema> | void;
  onOpenImportWizard?: (runId: string) => void;
}

export const AiMessageContent: React.FC<AiMessageContentProps> = ({
  message,
  status,
  editing,
  onEditConfirm,
  onEditCancel,
  onSubmitForm,
  onSubmitReview,
  onConfirmReviewStep,
  onConfirmReviewGroup,
  onOpenImportWizard,
}) => {
  const streaming = status === 'loading' || status === 'updating';
  const formSubmission = message.metadata?.a2uiSubmit;
  const reviewSubmission = message.metadata?.a2uiReviewSubmit;
  const sourceMeta = message.metadata?.a2uiSources;
  const sourceItems = Array.isArray(sourceMeta)
    ? sourceMeta
        .filter(
          (item): item is { title: string; url?: string; description?: string } =>
            Boolean(item) && typeof (item as { title?: unknown }).title === 'string',
        )
        .map((item, index) => ({
          key: `source-${index}`,
          title: item.title,
          ...(item.url ? { url: item.url } : {}),
          ...(item.description ? { description: item.description } : {}),
        }))
    : [];
  const attachmentCards = message.attachments.map((attachment) => (
    <FileCard
      key={attachment.id}
      name={attachment.name}
      byte={attachment.size}
      size="small"
      icon={attachmentIcon(attachment)}
      onClick={() => void handleOpenAttachment(attachment)}
    />
  ));

  if (message.role === 'user') {
    if (reviewSubmission && typeof reviewSubmission === 'object') {
      const reviewTitle =
        typeof (reviewSubmission as Record<string, unknown>).reviewTitle === 'string'
          ? String((reviewSubmission as Record<string, unknown>).reviewTitle)
          : '批量导入';
      return (
        <Space orientation="vertical" size={8} className="ai-chat-user-content">
          <Alert type="success" showIcon title={`已确认导入《${reviewTitle}》`} />
        </Space>
      );
    }
    if (formSubmission && typeof formSubmission === 'object') {
      const formTitle =
        typeof (formSubmission as Record<string, unknown>).formTitle === 'string'
          ? String((formSubmission as Record<string, unknown>).formTitle)
          : '表单';
      return (
        <Space orientation="vertical" size={8} className="ai-chat-user-content">
          <Alert type="info" showIcon title={`已提交《${formTitle}》`} />
        </Space>
      );
    }
    return (
      <Space orientation="vertical" size={8} className="ai-chat-user-content">
        {attachmentCards.length > 0 && (
          <Flex wrap gap={8}>
            {attachmentCards}
          </Flex>
        )}
        {editing ? (
          <EditUserContent
            initial={message.content}
            onConfirm={(value) => onEditConfirm?.(value)}
            onCancel={onEditCancel}
          />
        ) : (
          <div className="ai-chat-user-text">{message.content}</div>
        )}
      </Space>
    );
  }

  return (
    <Space orientation="vertical" size={10} className="ai-chat-answer">
      {streaming &&
        !message.content &&
        !message.reasoningContent &&
        message.toolRuns.length === 0 && (
          <div className="ai-chat-streaming-placeholder" role="status" aria-label="生成中">
            <LoadingOutlined spin />
          </div>
        )}
      {message.retrying && (
        <Alert
          type="warning"
          showIcon
          title={`AI 服务繁忙，正在自动重试（第 ${message.retrying.attempt} / ${message.retrying.maxRetries} 次）...`}
          description={message.retrying.reason ? `原因：${message.retrying.reason}` : undefined}
        />
      )}
      {message.reasoningContent && (
        <Think
          title={streaming ? '正在思考' : '思考过程'}
          loading={streaming}
          defaultExpanded={false}
        >
          <XMarkdown
            content={message.reasoningContent}
            components={markdownComponents}
            escapeRawHtml
            openLinksInNewTab
            dompurifyConfig={markdownSanitizerConfig}
            streaming={{ hasNextChunk: streaming, tail: streaming }}
          />
        </Think>
      )}
      {message.toolRuns.length > 0 && <ToolChain tools={message.toolRuns} />}
      {attachmentCards.length > 0 && (
        <Flex wrap gap={8}>
          {attachmentCards}
        </Flex>
      )}
      {(() => {
        const wizard = message.metadata?.a2uiImportWizard as AiImportWizard | undefined;
        if (!wizard || !onOpenImportWizard) return null;
        return (
          <Flex wrap gap={8} align="center">
            <Button
              type="primary"
              icon={<TableOutlined />}
              onClick={() => onOpenImportWizard(wizard.runId)}
            >
              打开导入向导
            </Button>
            <Typography.Text type="secondary" style={{ fontSize: 12 }}>
              {wizard.fileName}
            </Typography.Text>
          </Flex>
        );
      })()}
      {message.content && (
        <XMarkdown
          content={message.content}
          components={markdownComponents}
          escapeRawHtml
          openLinksInNewTab
          dompurifyConfig={markdownSanitizerConfig}
          streaming={{
            hasNextChunk: streaming,
            enableAnimation: true,
            tail: streaming,
            incompleteMarkdownComponentMap: { link: 'span', image: 'span', table: 'div' },
          }}
        />
      )}
      {sourceItems.length > 0 && (
        <Sources
          items={sourceItems}
          title="引用来源"
          onClick={(item) => void handleOpenSource(item as { url?: string })}
        />
      )}
      {(message.forms ?? []).map((form) => (
        <ArtifactErrorBoundary key={form.id} title="表单">
          <DynamicForm
            form={form}
            disabled={streaming}
            onSubmit={(values) => onSubmitForm?.(form, values)}
          />
        </ArtifactErrorBoundary>
      ))}
      {(message.reviews ?? []).map((review: AiReviewSchema) => (
        <ArtifactErrorBoundary key={review.id} title="导入预览">
          <DynamicReview
            review={review}
            messageId={typeof message.id === 'number' ? message.id : undefined}
            disabled={streaming}
            onSubmit={(reviewId) => onSubmitReview?.(reviewId, review.title)}
            onConfirmStep={onConfirmReviewStep}
            onConfirmGroup={onConfirmReviewGroup}
          />
        </ArtifactErrorBoundary>
      ))}
      {(message.charts ?? []).map((chart: AiChartSchema) => (
        <ArtifactErrorBoundary key={chart.id} title="图表">
          <DynamicChart chart={chart} />
        </ArtifactErrorBoundary>
      ))}
      {message.error && <Alert type="error" showIcon title={message.error} />}
      {message.cancelled && <Typography.Text type="secondary">回答已停止</Typography.Text>}
    </Space>
  );
};
