import {
  AudioOutlined,
  CodeOutlined,
  CopyOutlined,
  DownloadOutlined,
  FileImageOutlined,
  FileMarkdownOutlined,
  FilePdfOutlined,
  FileTextOutlined,
  FullscreenOutlined,
  LinkOutlined,
  PlayCircleOutlined,
} from '@ant-design/icons';
import { Button, Card, Empty, Flex, Space, Tag, Typography, message } from 'antd';
import type { ReactNode } from 'react';
import { InlineImage } from '../common/InlineImage';
import { PreviewerUI } from '../previewer';
import type {
  EvidenceAttachmentItem,
  EvidenceAttachmentKind,
  EvidenceAttachmentPreviewBodyProps,
  EvidenceAttachmentStripProps,
} from './types';
import { copyTextToClipboard } from '../../utils/clipboard';
import './EvidenceAttachmentStrip.css';

const { Paragraph, Text } = Typography;

function getAttachmentTypeLabel(kind: EvidenceAttachmentKind) {
  switch (kind) {
    case 'image':
      return 'Image';
    case 'markdown':
      return 'Markdown';
    case 'code':
      return 'Code';
    case 'text':
      return 'Text';
    case 'json':
      return 'JSON';
    case 'preview':
      return 'Preview';
    case 'video':
      return 'Video';
    case 'audio':
      return 'Audio';
    case 'pdf':
      return 'PDF';
    case 'empty':
      return 'Empty';
    default:
      return 'Attachment';
  }
}

function getAttachmentTypeColor(kind: EvidenceAttachmentKind) {
  switch (kind) {
    case 'image':
      return 'green';
    case 'markdown':
      return 'geekblue';
    case 'code':
      return 'cyan';
    case 'text':
      return 'blue';
    case 'json':
      return 'volcano';
    case 'preview':
      return 'purple';
    case 'video':
      return 'magenta';
    case 'audio':
      return 'gold';
    case 'pdf':
      return 'red';
    case 'empty':
      return 'default';
    default:
      return 'default';
  }
}

function getAttachmentTypeIcon(kind: EvidenceAttachmentKind): ReactNode {
  switch (kind) {
    case 'image':
      return <FileImageOutlined />;
    case 'markdown':
      return <FileMarkdownOutlined />;
    case 'code':
      return <CodeOutlined />;
    case 'text':
      return <FileTextOutlined />;
    case 'json':
      return <CodeOutlined />;
    case 'preview':
      return <LinkOutlined />;
    case 'video':
      return <PlayCircleOutlined />;
    case 'audio':
      return <AudioOutlined />;
    case 'pdf':
      return <FilePdfOutlined />;
    case 'empty':
      return <FileTextOutlined />;
    default:
      return <FileTextOutlined />;
  }
}

async function copyAttachmentValue(attachment: EvidenceAttachmentItem) {
  const copyValue = attachment.copyValue ?? attachment.value;
  return copyTextToClipboard(copyValue);
}

function resolveAttachmentDownloadFileName(attachment: EvidenceAttachmentItem) {
  if (typeof attachment.title === 'string' && attachment.title.trim()) {
    return attachment.title.trim();
  }

  if (attachment.linkUrl) {
    try {
      const resolvedUrl = new URL(
        attachment.linkUrl,
        typeof window !== 'undefined' ? window.location.origin : 'https://preview.sm-home.cloud/',
      );
      const fileName = resolvedUrl.pathname.split('/').pop()?.trim();

      if (fileName) {
        return fileName;
      }
    } catch {
      return `${attachment.key}.txt`;
    }
  }

  return `${attachment.key}.txt`;
}

function resolveAttachmentMimeType(attachment: EvidenceAttachmentItem) {
  switch (attachment.kind) {
    case 'markdown':
      return 'text/markdown;charset=utf-8';
    case 'json':
      return 'application/json;charset=utf-8';
    case 'code':
    case 'text':
    case 'empty':
      return 'text/plain;charset=utf-8';
    default:
      return 'application/octet-stream';
  }
}

function downloadAttachmentValue(attachment: EvidenceAttachmentItem) {
  if (typeof document === 'undefined') {
    throw new Error('download-unavailable');
  }

  const fileName = resolveAttachmentDownloadFileName(attachment);
  const link = document.createElement('a');

  if (attachment.linkUrl) {
    link.href = attachment.linkUrl;

    if (attachment.kind === 'preview') {
      link.target = '_blank';
      link.rel = 'noreferrer';
    } else {
      link.download = fileName;
    }
  } else {
    const blob = new Blob([attachment.value], {
      type: resolveAttachmentMimeType(attachment),
    });
    const objectUrl = URL.createObjectURL(blob);
    link.href = objectUrl;
    link.download = fileName;
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);
    URL.revokeObjectURL(objectUrl);
    return;
  }

  document.body.appendChild(link);
  link.click();
  document.body.removeChild(link);
}

function resolvePreviewerType(kind: EvidenceAttachmentKind) {
  switch (kind) {
    case 'markdown':
      return 'markdown';
    case 'code':
      return 'code';
    case 'json':
      return 'json';
    case 'empty':
      return 'empty';
    default:
      return 'text';
  }
}

export function EvidenceAttachmentPreviewBody({
  attachment,
  compact = false,
  height,
}: EvidenceAttachmentPreviewBodyProps) {
  const previewHeight = height ?? (compact ? 220 : 'calc(100dvh - 280px)');

  if (attachment.kind === 'image') {
    return (
      <InlineImage
        className={[
          'evidence-attachment-preview-body__image',
          compact ? 'evidence-attachment-preview-body__image--compact' : '',
        ]
          .filter(Boolean)
          .join(' ')}
        src={attachment.value}
        alt={typeof attachment.title === 'string' ? attachment.title : 'attachment'}
        fallbackText="첨부 이미지를 불러오지 못했습니다."
      />
    );
  }

  if (attachment.kind === 'preview' || attachment.kind === 'pdf') {
    return (
      <div
        className={[
          'evidence-attachment-preview-body__frame-wrap',
          compact ? 'evidence-attachment-preview-body__frame-wrap--compact' : '',
        ]
          .filter(Boolean)
          .join(' ')}
      >
        <iframe
          className="evidence-attachment-preview-body__frame"
          src={attachment.value}
          title={typeof attachment.title === 'string' ? attachment.title : 'attachment-preview'}
          loading="lazy"
          referrerPolicy="no-referrer"
        />
      </div>
    );
  }

  if (attachment.kind === 'video') {
    return (
      <div className="evidence-attachment-preview-body__media-wrap">
        <video className="evidence-attachment-preview-body__media" src={attachment.value} controls preload="metadata" />
      </div>
    );
  }

  if (attachment.kind === 'audio') {
    return (
      <div className="evidence-attachment-preview-body__audio-wrap">
        <audio className="evidence-attachment-preview-body__audio" src={attachment.value} controls preload="metadata" />
      </div>
    );
  }

  return (
    <div
      className={[
        'evidence-attachment-preview-body',
        compact ? 'evidence-attachment-preview-body--compact' : '',
      ]
        .filter(Boolean)
        .join(' ')}
    >
      <div className="evidence-attachment-preview-body__previewer">
        <PreviewerUI
          type={resolvePreviewerType(attachment.kind)}
          title={attachment.title}
          description={attachment.description}
          showHeader={false}
          copyable={false}
          maximizable={false}
          value={attachment.value}
          language={attachment.language}
          format={attachment.format}
          height={previewHeight}
        />
      </div>
    </div>
  );
}

export function EvidenceAttachmentStrip({
  attachments,
  onPreview,
  onCopy,
  maxVisible,
  compact = false,
  emptyText = '표시할 첨부 자료가 없습니다.',
  title,
  description,
  className,
  previewBodyHeight,
}: EvidenceAttachmentStripProps) {
  const visibleAttachments =
    typeof maxVisible === 'number' && maxVisible >= 0 ? attachments.slice(0, maxVisible) : attachments;
  const overflowCount = Math.max(0, attachments.length - visibleAttachments.length);

  async function handleCopy(attachment: EvidenceAttachmentItem) {
    try {
      if (onCopy) {
        await onCopy(attachment);
        return;
      }

      await copyAttachmentValue(attachment);
      message.success('복사했습니다.');
    } catch {
      message.error('복사에 실패했습니다.');
    }
  }

  async function handleDownload(attachment: EvidenceAttachmentItem) {
    try {
      downloadAttachmentValue(attachment);
    } catch {
      message.error('다운로드에 실패했습니다.');
    }
  }

  if (attachments.length === 0) {
    return (
      <div className={['evidence-attachment-strip', className].filter(Boolean).join(' ')}>
        {title || description ? (
          <div className="evidence-attachment-strip__header">
            {title ? <Text strong>{title}</Text> : null}
            {description ? (
              <Paragraph type="secondary" className="evidence-attachment-strip__description">
                {description}
              </Paragraph>
            ) : null}
          </div>
        ) : null}
        <Empty className="evidence-attachment-strip__empty" description={emptyText} />
      </div>
    );
  }

  return (
    <div className={['evidence-attachment-strip', className].filter(Boolean).join(' ')}>
      {title || description ? (
        <Flex vertical gap={4} className="evidence-attachment-strip__header">
          {title ? <Text strong>{title}</Text> : null}
          {description ? (
            <Paragraph type="secondary" className="evidence-attachment-strip__description">
              {description}
            </Paragraph>
          ) : null}
        </Flex>
      ) : null}

      <div className="evidence-attachment-strip__grid">
        {visibleAttachments.map((attachment) => (
          <Card
            key={attachment.key}
            size="small"
            className="evidence-attachment-strip__card"
            extra={
              <Space size={4} className="evidence-attachment-strip__actions">
                <Button
                  aria-label="복사"
                  size="small"
                  type="text"
                  icon={<CopyOutlined />}
                  onClick={() => {
                    void handleCopy(attachment);
                  }}
                />
                {attachment.linkUrl || attachment.value ? (
                  <Button
                    type="text"
                    size="small"
                    aria-label="다운로드"
                    icon={<DownloadOutlined />}
                    onClick={() => {
                      void handleDownload(attachment);
                    }}
                  />
                ) : null}
                {onPreview ? (
                  <Button
                    size="small"
                    type="text"
                    aria-label="최대화"
                    icon={<FullscreenOutlined />}
                    onClick={() => {
                      void onPreview(attachment);
                    }}
                  />
                ) : null}
              </Space>
            }
          >
            <Flex vertical gap={10} className="evidence-attachment-strip__card-copy">
              <div className="evidence-attachment-strip__meta">
                <Flex gap={8} className="evidence-attachment-strip__meta-row">
                  <Tag
                    color={getAttachmentTypeColor(attachment.kind)}
                    icon={getAttachmentTypeIcon(attachment.kind)}
                    className="evidence-attachment-strip__badge"
                  >
                    {getAttachmentTypeLabel(attachment.kind)}
                  </Tag>
                </Flex>
                <Text strong className="evidence-attachment-strip__title">
                  {attachment.title}
                </Text>
                {attachment.description ? (
                  <Text type="secondary" className="evidence-attachment-strip__description-text">
                    {attachment.description}
                  </Text>
                ) : null}
              </div>
              <EvidenceAttachmentPreviewBody
                attachment={attachment}
                compact={compact}
                height={previewBodyHeight}
              />
            </Flex>
          </Card>
        ))}
      </div>

      {overflowCount > 0 ? (
        <Flex align="center" className="evidence-attachment-strip__summary">
          <Text type="secondary" className="evidence-attachment-strip__overflow">
            {`추가 첨부 ${overflowCount}건은 상세 미리보기에서 확인하세요.`}
          </Text>
        </Flex>
      ) : null}
    </div>
  );
}
