import {
  CheckCircleOutlined,
  ExclamationCircleOutlined,
  InboxOutlined,
  LoadingOutlined,
} from '@ant-design/icons';
import { Card, Flex, Skeleton, Typography } from 'antd';
import type { CardProps } from 'antd';
import type { ReactNode } from 'react';
import './DataStatePanel.css';

const { Paragraph, Text, Title } = Typography;

export type DataStatePanelStatus = 'loading' | 'empty' | 'error' | 'ready';

export type DataStatePanelProps = {
  state: DataStatePanelStatus;
  title?: ReactNode;
  description?: ReactNode;
  actions?: ReactNode;
  children?: ReactNode;
  compact?: boolean;
  icon?: ReactNode;
  loadingRows?: number;
  className?: string;
  cardProps?: Omit<CardProps, 'children' | 'className'>;
};

function getDefaultIcon(state: DataStatePanelStatus) {
  switch (state) {
    case 'loading':
      return <LoadingOutlined />;
    case 'empty':
      return <InboxOutlined />;
    case 'error':
      return <ExclamationCircleOutlined />;
    case 'ready':
      return <CheckCircleOutlined />;
    default:
      return null;
  }
}

function getDefaultTitle(state: DataStatePanelStatus) {
  switch (state) {
    case 'loading':
      return '데이터를 불러오는 중입니다.';
    case 'empty':
      return '표시할 데이터가 없습니다.';
    case 'error':
      return '데이터를 불러오지 못했습니다.';
    case 'ready':
      return '데이터를 확인할 수 있습니다.';
    default:
      return undefined;
  }
}

function getDefaultDescription(state: DataStatePanelStatus) {
  switch (state) {
    case 'loading':
      return '응답을 정리하는 동안 패널 레이아웃을 유지합니다.';
    case 'empty':
      return '조건을 조정하거나 새 항목을 추가하면 이 영역이 채워집니다.';
    case 'error':
      return '네트워크 또는 권한 상태를 확인한 뒤 다시 시도하세요.';
    case 'ready':
      return undefined;
    default:
      return undefined;
  }
}

function getSkeletonWidths(compact: boolean, rows: number) {
  if (compact) {
    return Array.from({ length: rows }, (_, index) => (index === rows - 1 ? '84%' : '100%'));
  }

  return Array.from({ length: rows }, (_, index) => {
    if (index === rows - 1) {
      return '74%';
    }

    return '100%';
  });
}

function renderLoadingBody(compact: boolean, rows: number) {
  return (
    <div className="data-state-panel__skeleton">
      <Skeleton
        active
        title={{ width: compact ? '52%' : '38%' }}
        paragraph={{ rows, width: getSkeletonWidths(compact, rows) }}
      />
    </div>
  );
}

export function DataStatePanel({
  state,
  title,
  description,
  actions,
  children,
  compact = false,
  icon,
  loadingRows = compact ? 2 : 3,
  className,
  cardProps,
}: DataStatePanelProps) {
  const resolvedTitle = title ?? getDefaultTitle(state);
  const resolvedDescription = description ?? getDefaultDescription(state);
  const panelClassName = [
    'data-state-panel',
    `data-state-panel--${state}`,
    compact ? 'data-state-panel--compact' : '',
    className ?? '',
  ]
    .filter(Boolean)
    .join(' ');

  return (
    <Card {...cardProps} className={panelClassName}>
      <Flex vertical gap={compact ? 14 : 18} className="data-state-panel__inner">
        <div className="data-state-panel__hero">
          <span className="data-state-panel__icon" aria-hidden="true">
            {icon ?? getDefaultIcon(state)}
          </span>
          <Flex vertical gap={4} className="data-state-panel__copy">
            {resolvedTitle ? (
              compact ? (
                <Text strong className="data-state-panel__title data-state-panel__title--compact">
                  {resolvedTitle}
                </Text>
              ) : (
                <Title level={5} className="data-state-panel__title">
                  {resolvedTitle}
                </Title>
              )
            ) : null}
            {resolvedDescription ? (
              <Paragraph className="data-state-panel__description" type="secondary">
                {resolvedDescription}
              </Paragraph>
            ) : null}
          </Flex>
        </div>

        {state === 'loading' ? renderLoadingBody(compact, loadingRows) : children ? (
          <div className="data-state-panel__content">{children}</div>
        ) : null}

        {actions ? <div className="data-state-panel__actions">{actions}</div> : null}
      </Flex>
    </Card>
  );
}
