import {
  CodeOutlined,
  DownloadOutlined,
  EyeOutlined,
  FileMarkdownOutlined,
  FilePdfOutlined,
  FileTextOutlined,
  LinkOutlined,
  PictureOutlined,
  VideoCameraOutlined,
} from '@ant-design/icons';
import { Alert, Button, Empty, Space, Spin, Typography } from 'antd';
import { InlineImage } from '../../../components/common/InlineImage';
import { MarkdownPreviewContent } from '../../../components/markdownPreview/MarkdownPreviewContent';
import { CodexDiffBlock } from '../../../components/previewer';
import { inferCodeLanguage, renderEditorBlock } from '../../../components/previewer/renderers';
import { triggerResourceDownload } from './downloadUtils';
import '../../../components/previewer/PreviewerUI.css';

const { Paragraph, Text } = Typography;

export type ChatPreviewKind = 'image' | 'video' | 'markdown' | 'code' | 'diff' | 'document' | 'pdf' | 'file';

export type ChatPreviewTarget = {
  label: string;
  url: string;
  kind: ChatPreviewKind;
};

export function resolveChatPreviewGlyph(kind: ChatPreviewKind) {
  switch (kind) {
    case 'image':
      return <PictureOutlined />;
    case 'video':
      return <VideoCameraOutlined />;
    case 'markdown':
      return <FileMarkdownOutlined />;
    case 'code':
    case 'diff':
      return <CodeOutlined />;
    case 'document':
      return <FileTextOutlined />;
    case 'pdf':
      return <FilePdfOutlined />;
    default:
      return <LinkOutlined />;
  }
}

export function resolveChatPreviewKindLabel(kind: ChatPreviewKind) {
  switch (kind) {
    case 'image':
      return 'image preview';
    case 'video':
      return 'video preview';
    case 'markdown':
      return 'markdown preview';
    case 'code':
      return 'code preview';
    case 'diff':
      return 'diff preview';
    case 'document':
      return 'document preview';
    case 'pdf':
      return 'pdf preview';
    default:
      return 'resource preview';
  }
}

function resolvePreviewErrorMessage(previewError: string) {
  const normalized = previewError.trim();

  if (!normalized) {
    return '';
  }

  if (/^\s*403\b/.test(normalized) || normalized.includes('권한으로 열 수 없습니다')) {
    return '권한이 없거나 허용되지 않은 경로입니다. 세션 리소스 경로와 접근 권한을 확인해 주세요.';
  }

  if (/^\s*404\b/.test(normalized) || normalized.includes('찾을 수 없습니다')) {
    return '파일이 이동되었거나 아직 세션 리소스 경로에 생성되지 않았습니다. 경로를 다시 확인해 주세요.';
  }

  if (/^\s*401\b/.test(normalized) || normalized.includes('인증이 필요합니다')) {
    return '인증 정보가 없어서 문서를 열 수 없습니다.';
  }

  return normalized;
}

function resolvePreviewExtension(target: ChatPreviewTarget) {
  const raw = target.label || target.url;
  const normalized = raw.toLowerCase().split('?')[0] ?? '';
  const match = normalized.match(/\.([a-z0-9]+)$/i);
  return match?.[1] ?? '';
}

function resolveCodeLanguage(target: ChatPreviewTarget, previewText: string) {
  const extension = resolvePreviewExtension(target);

  if (extension === 'tsx' || extension === 'ts') {
    return 'typescript';
  }

  if (extension === 'jsx' || extension === 'js' || extension === 'mjs' || extension === 'cjs') {
    return 'javascript';
  }

  if (extension === 'json') {
    return 'json';
  }

  if (extension === 'css') {
    return 'css';
  }

  if (extension === 'scss') {
    return 'scss';
  }

  if (extension === 'html' || extension === 'htm') {
    return 'html';
  }

  if (extension === 'md' || extension === 'markdown') {
    return 'markdown';
  }

  if (extension === 'java') {
    return 'java';
  }

  if (extension === 'kt') {
    return 'kotlin';
  }

  if (extension === 'py') {
    return 'python';
  }

  if (extension === 'go') {
    return 'go';
  }

  if (extension === 'rs') {
    return 'rust';
  }

  if (extension === 'sql') {
    return 'sql';
  }

  if (extension === 'sh' || extension === 'bash' || extension === 'zsh') {
    return 'bash';
  }

  if (extension === 'yml' || extension === 'yaml') {
    return 'yaml';
  }

  if (extension === 'xml') {
    return 'xml';
  }

  if (extension === 'diff' || extension === 'patch') {
    return 'diff';
  }

  if (/^(diff --git|@@\s|--- a\/|\+\+\+ b\/)/m.test(previewText)) {
    return 'diff';
  }

  return inferCodeLanguage(extension || 'text');
}

function isAppRouteUrl(url: string) {
  if (typeof window === 'undefined') {
    return false;
  }

  try {
    const parsed = new URL(url, window.location.href);
    const pathname = parsed.pathname.toLowerCase();
    const hasKnownFileExtension = /\.[a-z0-9]+$/i.test(pathname);
    return parsed.origin === window.location.origin && !hasKnownFileExtension;
  } catch {
    return false;
  }
}

function canRenderFramePreview(url: string) {
  if (typeof window === 'undefined') {
    return false;
  }

  try {
    const parsed = new URL(url, window.location.href);
    return parsed.origin === window.location.origin;
  } catch {
    return false;
  }
}

type ChatPreviewBodyProps = {
  target: ChatPreviewTarget | null;
  previewText: string;
  isPreviewLoading: boolean;
  previewError: string;
  previewContentType?: string;
  maxMarkdownBlocks?: number;
};

function isHtmlFallbackPreview(target: ChatPreviewTarget, previewText: string, previewContentType: string | undefined) {
  const extension = resolvePreviewExtension(target);
  const normalizedContentType = previewContentType?.toLowerCase() ?? '';
  const normalizedPreview = previewText.trimStart().toLowerCase();

  if (extension === 'html' || extension === 'htm' || target.kind === 'markdown') {
    return false;
  }

  const looksLikeHtml =
    normalizedContentType.includes('text/html') ||
    normalizedPreview.startsWith('<!doctype html') ||
    normalizedPreview.startsWith('<html') ||
    normalizedPreview.includes('<head') ||
    normalizedPreview.includes('<body');

  return looksLikeHtml;
}

export function ChatPreviewBody({
  target,
  previewText,
  isPreviewLoading,
  previewError,
  previewContentType,
  maxMarkdownBlocks,
}: ChatPreviewBodyProps) {
  if (!target) {
    return <Empty description="preview 가능한 링크가 아직 없습니다." />;
  }

  if (isPreviewLoading) {
    return (
      <div className="app-chat-panel__preview-loading">
        <Spin size="small" />
        <Text type="secondary">preview를 불러오는 중입니다.</Text>
      </div>
    );
  }

  if (previewError) {
    return (
      <Alert
        showIcon
        type="warning"
        message="preview를 불러오지 못했습니다."
        description={resolvePreviewErrorMessage(previewError)}
      />
    );
  }

  if (isHtmlFallbackPreview(target, previewText, previewContentType)) {
    return (
      <Alert
        showIcon
        type="info"
        message="실제 소스 파일 대신 앱 HTML 화면이 반환되었습니다."
        description={`${target.label} 경로가 raw 파일이 아니라 현재 앱의 fallback HTML을 돌려주고 있습니다. 정적 파일 경로 또는 실제 다운로드 경로를 사용해야 코드 preview가 정확하게 표시됩니다.`}
      />
    );
  }

  if (target.kind === 'image') {
    return (
      <InlineImage
        src={target.url}
        alt={target.label}
        className="app-chat-panel__preview-image"
        fallbackText="이미지 preview를 불러오지 못했습니다."
      />
    );
  }

  if (target.kind === 'video') {
    return <video src={target.url} className="app-chat-panel__preview-video" controls playsInline />;
  }

  if (target.kind === 'pdf') {
    return <iframe title={target.label} src={target.url} className="app-chat-panel__preview-frame" />;
  }

  if (target.kind === 'markdown') {
    return (
      <div className="app-chat-panel__preview-rich app-chat-panel__preview-rich--markdown">
        <MarkdownPreviewContent
          content={previewText || '# Preview\n\n표시할 preview 본문이 없습니다.'}
          maxBlocks={maxMarkdownBlocks}
        />
      </div>
    );
  }

  if (target.kind === 'code' || target.kind === 'diff' || target.kind === 'document') {
    const resolvedLanguage = resolveCodeLanguage(target, previewText);

    if (target.kind === 'diff' || resolvedLanguage === 'diff') {
      return (
        <div className="app-chat-panel__preview-rich app-chat-panel__preview-rich--code">
          <CodexDiffBlock
            diffText={previewText || ''}
            summary={`${target.label} 기준 raw diff preview입니다.`}
            showToolbar={false}
            className="app-chat-panel__preview-diff"
          />
        </div>
      );
    }

    return (
      <div className="app-chat-panel__preview-rich app-chat-panel__preview-rich--code">
        {renderEditorBlock(previewText || '표시할 preview 본문이 없습니다.', resolvedLanguage, 'code')}
      </div>
    );
  }

  if (isAppRouteUrl(target.url)) {
    return (
      <Alert
        showIcon
        type="info"
        message="앱 화면 경로는 preview iframe으로 열지 않습니다."
        description="현재 화면 문맥은 이미 WebSocket으로 서버에 전달됩니다. 이 경로를 다시 열면 앱만 새로 렌더링되어 preview처럼 보이지 않을 수 있습니다."
      />
    );
  }

  if (canRenderFramePreview(target.url)) {
    return <iframe title={target.label} src={target.url} className="app-chat-panel__preview-frame" />;
  }

  return (
    <div className="app-chat-panel__preview-file">
      <Paragraph>
        브라우저에서 직접 렌더링하지 않는 형식입니다. 아래 버튼으로 새 탭에서 열거나 바로 다운로드할 수 있습니다.
      </Paragraph>
      <Space wrap>
        <Button type="text" href={target.url} target="_blank" rel="noreferrer" aria-label="새 탭 열기" icon={<EyeOutlined />} />
        <Button
          type="text"
          aria-label="다운로드"
          icon={<DownloadOutlined />}
          onClick={() => {
            const fileName = target.url.split('/').pop()?.trim() || target.label;
            triggerResourceDownload(target.url, fileName);
          }}
        />
      </Space>
    </div>
  );
}
