'use client';

import * as React from 'react';
import { ChevronLeft, ChevronRight, ChevronDown } from 'lucide-react';
import { DayPicker, getDefaultClassNames, type DayButton } from 'react-day-picker';

import { cn } from '../../shared/utils';
import { Button, buttonVariants } from '../button';

export type CalendarProps = React.ComponentProps<typeof DayPicker> & {
  buttonVariant?: React.ComponentProps<typeof Button>['variant'];
};

/**
 * Monthly date picker built on react-day-picker.
 *
 * @description
 * Renders a customized month/year calendar styled for the Xertica UI design system.
 * Supports single date selection, date ranges, and disabled date rules.
 *
 * @ai-rules
 * 1. Commonly embedded inside a `<Popover>` to create a full DatePicker in forms.
 * 2. Control the selected date via the REQUIRED `selected={Date}` prop.
 * 3. For range selection, pass `mode="range"` and `selected={{ from, to }}`.
 */
function Calendar({
  className,
  classNames,
  showOutsideDays = true,
  captionLayout = 'label',
  buttonVariant = 'ghost',
  formatters,
  components,
  ...props
}: CalendarProps) {
  const defaultClassNames = getDefaultClassNames();
  const isDropdownCaption = captionLayout.startsWith('dropdown');

  return (
    <DayPicker
      showOutsideDays={showOutsideDays}
      className={cn(
        'bg-background group/calendar p-4 [[data-slot=card-content]_&]:bg-transparent [[data-slot=popover-content]_&]:bg-transparent font-sans',
        String.raw`rtl:**:[.rdp-button\_next>svg]:rotate-180`,
        String.raw`rtl:**:[.rdp-button\_previous>svg]:rotate-180`,
        className
      )}
      captionLayout={captionLayout}
      formatters={formatters}
      classNames={{
        root: cn('w-fit', defaultClassNames.root),
        months: cn('flex gap-6 flex-col md:flex-row relative', defaultClassNames.months),
        month: cn('flex flex-col w-full gap-5', defaultClassNames.month),
        nav: cn(
          'flex items-center gap-2 w-full absolute top-0 inset-x-0 justify-between',
          defaultClassNames.nav
        ),
        button_previous: cn(
          buttonVariants({ variant: buttonVariant }),
          'size-(--cell-size) aria-disabled:opacity-40 p-0 select-none hover:bg-accent/50 transition-colors duration-200',
          defaultClassNames.button_previous
        ),
        button_next: cn(
          buttonVariants({ variant: buttonVariant }),
          'size-(--cell-size) aria-disabled:opacity-40 p-0 select-none hover:bg-accent/50 transition-colors duration-200',
          defaultClassNames.button_next
        ),
        month_caption: cn(
          'flex items-center justify-center w-full',
          isDropdownCaption ? 'h-auto px-0' : 'h-(--cell-size) px-(--cell-size)',
          defaultClassNames.month_caption
        ),
        dropdowns: cn(
          'w-full flex items-center justify-center gap-2',
          isDropdownCaption ? 'h-auto' : 'h-(--cell-size)',
          defaultClassNames.dropdowns
        ),
        dropdown_root: cn(
          isDropdownCaption
            ? 'relative flex min-w-[7rem] items-center rounded-[var(--radius)] border border-border bg-background text-foreground transition-colors outline-none focus-within:ring-2 focus-within:ring-primary focus-within:border-transparent data-[disabled=true]:cursor-not-allowed data-[disabled=true]:opacity-50 px-2.5 py-1'
            : 'relative rounded-[var(--radius)] hover:bg-accent transition-colors',
          defaultClassNames.dropdown_root
        ),
        dropdown: cn(
          isDropdownCaption
            ? 'absolute inset-0 cursor-pointer opacity-0'
            : 'absolute bg-popover inset-0 opacity-0 cursor-pointer',
          defaultClassNames.dropdown
        ),
        caption_label: cn(
          'select-none font-[family-name:var(--font-family,Roboto)] tracking-tight transition-all duration-200',
          captionLayout === 'label'
            ? 'rounded-[var(--radius)] px-2 py-1 text-[length:var(--calendar-caption-size)] font-[number:var(--font-weight-semibold)] hover:bg-accent hover:text-accent-foreground'
            : 'flex h-full w-full items-center justify-between gap-2 rounded-[var(--radius)] text-[length:var(--calendar-caption-size)] font-[number:var(--font-weight-semibold)] [&>svg]:text-muted-foreground [&>svg]:size-4',
          defaultClassNames.caption_label
        ),
        table: 'w-full border-collapse mt-1',
        weekdays: cn('flex gap-1', defaultClassNames.weekdays),
        weekday: cn(
          'text-muted-foreground rounded-(--cell-radius) flex-1 select-none text-[length:var(--calendar-weekday-size)] font-[number:var(--font-weight-medium)] uppercase tracking-wider',
          defaultClassNames.weekday
        ),
        week: cn('flex w-full gap-1', defaultClassNames.week),
        week_number_header: cn('select-none w-(--cell-size)', defaultClassNames.week_number_header),
        week_number: cn(
          'select-none text-muted-foreground text-[length:var(--calendar-weekday-size)]',
          defaultClassNames.week_number
        ),
        day: cn(
          'relative w-full rounded-(--cell-radius) h-full p-0 text-center [&:last-child[data-selected=true]_button]:rounded-r-(--cell-radius) group/day aspect-square select-none',
          props.showWeekNumber
            ? '[&:nth-child(2)[data-selected=true]_button]:rounded-l-(--cell-radius)'
            : '[&:first-child[data-selected=true]_button]:rounded-l-(--cell-radius)',
          defaultClassNames.day
        ),
        range_start: cn(
          'rounded-l-(--cell-radius) bg-accent/50 relative after:bg-accent/50 after:absolute after:inset-y-0 after:w-2 after:right-0 -z-0 isolate',
          defaultClassNames.range_start
        ),
        range_middle: cn('rounded-none bg-accent/30', defaultClassNames.range_middle),
        range_end: cn(
          'rounded-r-(--cell-radius) bg-accent/50 relative after:bg-accent/50 after:absolute after:inset-y-0 after:w-2 after:left-0 -z-0 isolate',
          defaultClassNames.range_end
        ),
        today: cn(
          'bg-accent/60 text-accent-foreground rounded-(--cell-radius) data-[selected=true]:rounded-none font-[number:var(--font-weight-semibold)]',
          defaultClassNames.today
        ),
        outside: cn(
          'text-muted-foreground aria-selected:text-muted-foreground',
          defaultClassNames.outside
        ),
        disabled: cn('text-muted-foreground/30 opacity-40', defaultClassNames.disabled),
        hidden: cn('invisible', defaultClassNames.hidden),
        ...classNames,
      }}
      components={{
        Root: ({ className, rootRef, ...props }) => {
          return <div data-slot="calendar" ref={rootRef} className={cn(className)} {...props} />;
        },
        Chevron: ({ className, orientation, ...props }) => {
          if (orientation === 'left') {
            return (
              <ChevronLeft
                className={cn('size-5 transition-transform group-hover:scale-110', className)}
                {...props}
              />
            );
          }

          if (orientation === 'right') {
            return (
              <ChevronRight
                className={cn('size-5 transition-transform group-hover:scale-110', className)}
                {...props}
              />
            );
          }

          return <ChevronDown className={cn('size-4', className)} {...props} />;
        },
        DayButton: CalendarDayButton,
        WeekNumber: ({ children, ...props }) => {
          return (
            <td {...props}>
              <div className="flex size-(--cell-size) items-center justify-center text-center font-[number:var(--font-weight-medium)]">
                {children}
              </div>
            </td>
          );
        },
        ...components,
      }}
      {...props}
    />
  );
}

function CalendarDayButton({
  className,
  day,
  modifiers,
  ...props
}: React.ComponentProps<typeof DayButton>) {
  const defaultClassNames = getDefaultClassNames();

  const ref = React.useRef<HTMLButtonElement>(null);
  React.useEffect(() => {
    if (modifiers.focused) ref.current?.focus();
  }, [modifiers.focused]);

  return (
    <Button
      ref={ref}
      variant="ghost"
      size="icon"
      data-day={day.date.toLocaleDateString()}
      data-selected-single={
        modifiers.selected &&
        !modifiers.range_start &&
        !modifiers.range_end &&
        !modifiers.range_middle
      }
      data-range-start={modifiers.range_start}
      data-range-end={modifiers.range_end}
      data-range-middle={modifiers.range_middle}
      className={cn(
        'relative isolate z-10 flex aspect-square size-auto w-full min-w-(--cell-size) flex-col items-center justify-center gap-1 border-0 leading-none transition-all duration-200 cursor-pointer disabled:cursor-not-allowed',
        'text-[length:var(--calendar-day-size)] font-[number:var(--font-weight-regular)]',
        'hover:bg-accent/70 hover:text-accent-foreground hover:scale-105',
        'data-[selected-single=true]:bg-primary data-[selected-single=true]:text-primary-foreground data-[selected-single=true]:font-[number:var(--font-weight-semibold)] data-[selected-single=true]:shadow-sm',
        'data-[range-middle=true]:bg-accent/50 data-[range-middle=true]:text-foreground',
        'data-[range-start=true]:bg-primary data-[range-start=true]:text-primary-foreground data-[range-start=true]:font-[number:var(--font-weight-semibold)] data-[range-start=true]:shadow-sm',
        'data-[range-end=true]:bg-primary data-[range-end=true]:text-primary-foreground data-[range-end=true]:font-[number:var(--font-weight-semibold)] data-[range-end=true]:shadow-sm',
        'group-data-[focused=true]/day:border-ring group-data-[focused=true]/day:ring-ring/50 group-data-[focused=true]/day:ring-2 group-data-[focused=true]/day:ring-offset-2 group-data-[focused=true]/day:ring-offset-background',
        'data-[range-end=true]:rounded-(--cell-radius) data-[range-end=true]:rounded-r-(--cell-radius)',
        'data-[range-middle=true]:rounded-none',
        'data-[range-start=true]:rounded-(--cell-radius) data-[range-start=true]:rounded-l-(--cell-radius)',
        '[&>span]:opacity-80',
        defaultClassNames.day,
        className
      )}
      {...props}
    >
      {day.date.getDate()}
    </Button>
  );
}

export { Calendar, CalendarDayButton };
