import { createContext, useContext, type ReactNode, type HTMLAttributes, type TdHTMLAttributes, type ThHTMLAttributes } from 'react';
import { tv } from 'tailwind-variants';

// ============================================================================
// Styles
// ============================================================================

const tableStyles = tv({
  slots: {
    wrapper: 'flex flex-col gap-2 w-full',
    scrollContainer: 'relative flex-1 overflow-y-auto overflow-x-auto min-h-0',
    table: 'w-full border-collapse',
    thead: 'sticky top-0 z-1 bg-primary-tertiary02',
    th: 'px-2 h-[42px] align-middle whitespace-pre-line text-sm font-bold text-primary-secondary',
    thGrouped: 'h-[38px] border-l border-r border-white text-sm font-bold text-primary-secondary',
    thGroupedBottom: 'h-[38px] border-l border-r border-b border-white text-sm font-bold text-primary-secondary',
    tr: 'cursor-default transition-colors duration-200',
    trEmpty: 'text-center align-middle text-sm text-dabeeo-gray-44',
    td: 'border-b border-dabeeo-gray-eb py-2.5 px-2 text-sm text-dabeeo-gray-44 align-middle whitespace-nowrap overflow-hidden text-ellipsis font-medium',
    caption: 'flex justify-between text-sm',
    captionLeft: 'flex items-end gap-6',
    total: 'font-medium text-dabeeo-gray-44',
    totalCount: 'font-bold text-primary',
    loading: 'flex py-2 gap-2 w-full items-center justify-center h-16',
    spinner: 'w-5 h-5 border-2 border-primary border-t-transparent rounded-full animate-spin',
  },
  variants: {
    isLayoutFixed: {
      true: { table: 'table-fixed' },
    },
    isFullHeight: {
      true: { wrapper: 'h-full' },
    },
    isHoverable: {
      true: { tr: 'hover:bg-dabeeo-gray-eb' },
    },
    isClickable: {
      true: { tr: 'cursor-pointer' },
    },
    isSelected: {
      true: { tr: 'bg-primary-tertiary01' },
    },
  },
});

// ============================================================================
// Context
// ============================================================================

type TableContextValue = {
  isLayoutFixed: boolean;
  isFullHeight: boolean;
  isHoverable: boolean;
  isClickable: boolean;
  columnCount: number;
  setColumnCount: (count: number) => void;
};

const TableContext = createContext<TableContextValue | null>(null);

function useTableContext() {
  const context = useContext(TableContext);
  if (!context) {
    throw new Error('Table compound components must be used within a Table component');
  }
  return context;
}

// ============================================================================
// Table (Root)
// ============================================================================

type TableRootProps = {
  children: ReactNode;
  isLayoutFixed?: boolean;
  isFullHeight?: boolean;
  isHoverable?: boolean;
  isClickable?: boolean;
  className?: string;
};

function TableRoot({
  children,
  isLayoutFixed = true,
  isFullHeight = true,
  isHoverable = true,
  isClickable = true,
  className,
}: TableRootProps) {
  const [columnCount, setColumnCount] = useState(0);
  const styles = tableStyles({ isLayoutFixed, isFullHeight });

  return (
    <TableContext.Provider
      value={{ isLayoutFixed, isFullHeight, isHoverable, isClickable, columnCount, setColumnCount }}
    >
      <div className={styles.wrapper({ className })}>{children}</div>
    </TableContext.Provider>
  );
}

// ============================================================================
// Caption
// ============================================================================

type CaptionProps = {
  children?: ReactNode;
  className?: string;
};

function Caption({ children, className }: CaptionProps) {
  const styles = tableStyles();
  return <div className={styles.caption({ className })}>{children}</div>;
}

type CaptionLeftProps = {
  children?: ReactNode;
  className?: string;
};

function CaptionLeft({ children, className }: CaptionLeftProps) {
  const styles = tableStyles();
  return <div className={styles.captionLeft({ className })}>{children}</div>;
}

type CaptionRightProps = {
  children?: ReactNode;
  className?: string;
};

function CaptionRight({ children, className }: CaptionRightProps) {
  return <div className={className}>{children}</div>;
}

type TotalProps = {
  count: number;
  className?: string;
};

function Total({ count, className }: TotalProps) {
  const styles = tableStyles();
  return (
    <div className={styles.total({ className })}>
      Total&nbsp;<span className={styles.totalCount()}>{count.toLocaleString()}</span>
    </div>
  );
}

// ============================================================================
// Container (scroll wrapper + table)
// ============================================================================

type ContainerProps = {
  children: ReactNode;
  className?: string;
};

function Container({ children, className }: ContainerProps) {
  const { isLayoutFixed } = useTableContext();
  const styles = tableStyles({ isLayoutFixed });

  return (
    <div className={styles.scrollContainer({ className })}>
      <table className={styles.table()}>{children}</table>
    </div>
  );
}

// ============================================================================
// Colgroup
// ============================================================================

type ColgroupProps = {
  children: ReactNode;
};

function Colgroup({ children }: ColgroupProps) {
  return <colgroup>{children}</colgroup>;
}

type ColProps = {
  width?: number | string;
};

function Col({ width }: ColProps) {
  const widthStyle = typeof width === 'number' ? `${width}px` : width || 'auto';
  return <col style={{ width: widthStyle }} />;
}

// ============================================================================
// Header
// ============================================================================

type HeaderProps = {
  children: ReactNode;
  className?: string;
};

function Header({ children, className }: HeaderProps) {
  const styles = tableStyles();
  return <thead className={styles.thead({ className })}>{children}</thead>;
}

type HeaderRowProps = {
  children: ReactNode;
  className?: string;
};

function HeaderRow({ children, className }: HeaderRowProps) {
  return <tr className={className}>{children}</tr>;
}

type HeaderCellProps = ThHTMLAttributes<HTMLTableCellElement> & {
  children?: ReactNode;
  align?: 'left' | 'center' | 'right';
  isGroupTitle?: boolean;
  isGroupChild?: boolean;
  className?: string;
};

function HeaderCell({
  children,
  align = 'left',
  isGroupTitle = false,
  isGroupChild = false,
  className,
  style,
  ...props
}: HeaderCellProps) {
  const styles = tableStyles();

  let cellClass = styles.th();
  if (isGroupTitle) {
    cellClass = styles.thGroupedBottom();
  } else if (isGroupChild) {
    cellClass = styles.thGrouped();
  }

  return (
    <th align={align} className={`${cellClass} ${className || ''}`} style={style} {...props}>
      {children}
    </th>
  );
}

// ============================================================================
// Body
// ============================================================================

type BodyProps = {
  children: ReactNode;
  className?: string;
};

function Body({ children, className }: BodyProps) {
  return <tbody className={className}>{children}</tbody>;
}

type RowProps = HTMLAttributes<HTMLTableRowElement> & {
  children: ReactNode;
  isSelected?: boolean;
  className?: string;
};

function Row({ children, isSelected = false, className, ...props }: RowProps) {
  const { isHoverable, isClickable } = useTableContext();
  const styles = tableStyles({ isHoverable, isClickable, isSelected });

  return (
    <tr className={styles.tr({ className })} {...props}>
      {children}
    </tr>
  );
}

type CellProps = TdHTMLAttributes<HTMLTableCellElement> & {
  children?: ReactNode;
  align?: 'left' | 'center' | 'right';
  className?: string;
};

function Cell({ children, align = 'left', className, style, ...props }: CellProps) {
  const styles = tableStyles();

  return (
    <td className={styles.td({ className })} style={{ textAlign: align, ...style }} {...props}>
      {children}
    </td>
  );
}

// ============================================================================
// Empty & Loading
// ============================================================================

type EmptyProps = {
  colSpan: number;
  children?: ReactNode;
  className?: string;
};

function Empty({ colSpan, children = '데이터가 없습니다.', className }: EmptyProps) {
  const styles = tableStyles();
  return (
    <tr className={styles.trEmpty({ className })}>
      <td colSpan={colSpan} className="py-2.5">
        {children}
      </td>
    </tr>
  );
}

type LoadingProps = {
  colSpan: number;
  className?: string;
};

function Loading({ colSpan, className }: LoadingProps) {
  const styles = tableStyles();
  return (
    <tr className={styles.trEmpty({ className })}>
      <td colSpan={colSpan} className="py-2.5">
        <div className={styles.loading()}>
          <div className={styles.spinner()} />
        </div>
      </td>
    </tr>
  );
}

// ============================================================================
// Import useState
// ============================================================================

import { useState } from 'react';

// ============================================================================
// Export
// ============================================================================

export const Table = Object.assign(TableRoot, {
  Caption,
  CaptionLeft,
  CaptionRight,
  Total,
  Container,
  Colgroup,
  Col,
  Header,
  HeaderRow,
  HeaderCell,
  Body,
  Row,
  Cell,
  Empty,
  Loading,
});
