import { ArrowLeftSmallIcon, ArrowRightSmallIcon } from '@blocksuite/icons';
import { assignInlineVars } from '@vanilla-extract/dynamic';
import clsx from 'clsx';
import type { HTMLAttributes, PropsWithChildren, ReactNode } from 'react';
import { forwardRef, memo } from 'react';

import { IconButton } from '../../button';
import * as styles from './calendar.css';
import type { DateCell } from './types';

interface HeaderLayoutProps extends HTMLAttributes<HTMLDivElement> {
  mode: 'day' | 'month' | 'year';
  length: number;
  left: React.ReactNode;
  right: React.ReactNode;
}

const autoHeight = { height: 'auto' };
/**
 * The `DatePicker` should work with different width
 * This is a hack to make header's item align with calendar cell's label, **instead of the cell**
 * @param length: number of items that calendar body row has
 */
const HeaderLayout = memo(function HeaderLayout({
  length,
  left,
  right,
  className,
  style,
  mode,
  ...attrs
}: HeaderLayoutProps) {
  const vars = assignInlineVars({ '--len': `${length}` });
  const finalStyle = { ...vars, ...style };
  return (
    <div
      className={clsx(styles.monthViewRow, className)}
      style={finalStyle}
      {...attrs}
    >
      {Array.from({ length })
        .fill(0)
        .map((_, index) => {
          const isLeft = index === 0;
          const isRight = index === length - 1;
          return (
            <div
              key={index}
              data-length={length}
              data-is-left={isLeft}
              data-is-right={isRight}
              className={clsx({
                [styles.monthViewBodyCell]: mode === 'day',
                [styles.yearViewBodyCell]: mode === 'month',
                [styles.decadeViewBodyCell]: mode === 'year',
              })}
              style={autoHeight}
            >
              <div className={styles.headerLayoutCellOrigin}>
                {isLeft ? left : isRight ? right : null}
              </div>
            </div>
          );
        })}
    </div>
  );
});

interface CalendarLayoutProps {
  headerLeft: ReactNode;
  headerRight: ReactNode;
  body: ReactNode;
  length: number;
  mode: 'day' | 'month' | 'year';
}
export const CalendarLayout = forwardRef<HTMLDivElement, CalendarLayoutProps>(
  (
    { headerLeft, headerRight, body, length, mode }: CalendarLayoutProps,
    ref
  ) => {
    return (
      <div className={styles.calendarWrapper} ref={ref} data-mode={mode}>
        <HeaderLayout
          mode={mode}
          length={length}
          left={headerLeft}
          right={headerRight}
          className={styles.calendarHeader}
        />
        {body}
      </div>
    );
  }
);
CalendarLayout.displayName = 'CalendarLayout';

export const DefaultDateCell = ({
  label,
  date,
  isToday,
  notCurrentMonth,
  selected,
  focused,
}: DateCell) => {
  return (
    <button
      data-is-date-cell
      data-value={date.format('YYYY-MM-DD')}
      data-is-today={isToday}
      data-not-current-month={notCurrentMonth}
      data-selected={selected}
      tabIndex={focused ? 0 : -1}
      className={styles.monthViewBodyCellInner}
    >
      {label}
    </button>
  );
};

interface NavButtonsProps extends PropsWithChildren {
  prevDisabled?: boolean;
  nextDisabled?: boolean;
  onPrev?: () => void;
  onNext?: () => void;
}
export const NavButtons = memo(function NavButtons({
  children,
  prevDisabled,
  nextDisabled,
  onPrev,
  onNext,
}: NavButtonsProps) {
  return (
    <div className={styles.headerNavButtons} key="nav-btn-group">
      <IconButton
        key="nav-btn-prev"
        size="small"
        className={styles.focusInteractive}
        disabled={prevDisabled}
        data-testid="date-picker-nav-prev"
        onClick={onPrev}
      >
        <ArrowLeftSmallIcon />
      </IconButton>

      {children ?? <div className={styles.headerNavGapFallback} />}

      <IconButton
        key="nav-btn-next"
        size="small"
        className={styles.focusInteractive}
        disabled={nextDisabled}
        data-testid="date-picker-nav-next"
        onClick={onNext}
      >
        <ArrowRightSmallIcon />
      </IconButton>
    </div>
  );
});
