"use client";

import { useMemo, useState, type Key, type ReactNode } from "react";

import ChevronLeftRoundedIcon from "@mui/icons-material/ChevronLeftRounded";
import ChevronRightRoundedIcon from "@mui/icons-material/ChevronRightRounded";
import Box from "@mui/material/Box";
import ButtonBase from "@mui/material/ButtonBase";
import IconButton from "@mui/material/IconButton";
import Paper from "@mui/material/Paper";
import Typography from "@mui/material/Typography";
import { alpha, useTheme } from "@mui/material/styles";
import type { SxProps, Theme } from "@mui/material/styles";

import { useAppLanguage } from "@/components/providers/app-language-provider";

import {
  buildCalendarMonth,
  formatCalendarNumber,
  getCalendarLabels,
  getCalendarMonthLabel,
  getCalendarTodayDateKey,
  getCalendarWeekdayLabels,
  type CalendarLanguage,
  type CalendarMonth,
  type CalendarWeekStartsOn,
} from "./month-calendar-utils";

export type MonthCalendarHeaderLayout = "centered-year" | "inline-year";
export type MonthCalendarNavigationStyle = "icons" | "text";

export type MonthCalendarRenderContext = {
  language: CalendarLanguage;
};

export type MonthCalendarStyles = {
  minWidth?: number;
  headerHeight?: number;
  headerPaddingX?: number;
  monthMinWidth?: number;
  monthFontSize?: number;
  monthFontWeight?: number;
  yearFontSize?: number;
  yearFontWeight?: number;
  inlineYearMarginLeft?: number;
  weekdayHeight?: number;
  dayMinHeight?: number;
  dayPadding?: number;
  dayFontSize?: number;
  dayFontWeight?: number;
  todaySize?: number;
  todayColor?: string;
  itemContainerSx?: SxProps<Theme>;
};

export type MonthCalendarProps<T> = {
  items: T[];
  getItemId: (item: T) => Key;
  getItemDateKey: (item: T) => string | null | undefined;
  renderItem: (item: T, context: MonthCalendarRenderContext) => ReactNode;
  initialMonth?: CalendarMonth;
  month?: CalendarMonth;
  onMonthChange?: (month: CalendarMonth) => void;
  weekStartsOn?: CalendarWeekStartsOn;
  headerLayout?: MonthCalendarHeaderLayout;
  navigationStyle?: MonthCalendarNavigationStyle;
  styles?: MonthCalendarStyles;
};

const DEFAULT_STYLES: Required<
  Omit<MonthCalendarStyles, "itemContainerSx">
> = {
  minWidth: 980,
  headerHeight: 70,
  headerPaddingX: 22,
  monthMinWidth: 92,
  monthFontSize: 18,
  monthFontWeight: 500,
  yearFontSize: 18,
  yearFontWeight: 500,
  inlineYearMarginLeft: 0,
  weekdayHeight: 48,
  dayMinHeight: 124,
  dayPadding: 12,
  dayFontSize: 13,
  dayFontWeight: 600,
  todaySize: 30,
  todayColor: "#2584ce",
};

export function MonthCalendar<T>({
  items,
  getItemId,
  getItemDateKey,
  renderItem,
  initialMonth,
  month,
  onMonthChange,
  weekStartsOn = 0,
  headerLayout = "centered-year",
  navigationStyle = "icons",
  styles,
}: MonthCalendarProps<T>) {
  const theme = useTheme();
  const isDark = theme.palette.mode === "dark";
  const { language } = useAppLanguage();
  const calendarLanguage: CalendarLanguage = language;
  const resolvedStyles = { ...DEFAULT_STYLES, ...styles };

  const [internalMonth, setInternalMonth] = useState<CalendarMonth>(() =>
    initialMonth ?? {
      year: new Date().getFullYear(),
      monthIndex: new Date().getMonth(),
    },
  );
  const visibleMonth = month ?? internalMonth;

  const days = useMemo(
    () =>
      buildCalendarMonth(
        visibleMonth.year,
        visibleMonth.monthIndex,
        weekStartsOn,
      ),
    [visibleMonth, weekStartsOn],
  );
  const weekdays = getCalendarWeekdayLabels(
    weekStartsOn,
    calendarLanguage,
  );
  const monthLabel = getCalendarMonthLabel(
    visibleMonth,
    calendarLanguage,
  );
  const labels = getCalendarLabels(calendarLanguage);
  const todayDateKey = getCalendarTodayDateKey();

  const itemsByDate = useMemo(() => {
    const groupedItems = new Map<string, T[]>();

    for (const item of items) {
      const dateKey = getItemDateKey(item);
      if (!dateKey || !/^\d{4}-\d{2}-\d{2}$/.test(dateKey)) continue;

      const dateItems = groupedItems.get(dateKey) ?? [];
      groupedItems.set(dateKey, [...dateItems, item]);
    }

    return groupedItems;
  }, [getItemDateKey, items]);

  const setVisibleMonth = (nextMonth: CalendarMonth) => {
    if (!month) {
      setInternalMonth(nextMonth);
    }

    onMonthChange?.(nextMonth);
  };

  const changeMonth = (amount: number) => {
    const nextDate = new Date(
      Date.UTC(
        visibleMonth.year,
        visibleMonth.monthIndex + amount,
        1,
      ),
    );

    setVisibleMonth({
      year: nextDate.getUTCFullYear(),
      monthIndex: nextDate.getUTCMonth(),
    });
  };

  const monthNavigation = (
    <Box sx={{ display: "flex", alignItems: "center", gap: 1.25 }}>
      {navigationStyle === "text" ? (
        <ButtonBase
          aria-label={labels.previousMonth}
          onClick={() => changeMonth(-1)}
          sx={{
            width: 32,
            height: 32,
            borderRadius: "8px",
            color: theme.palette.text.secondary,
            fontSize: 22,
            "&:hover": { bgcolor: theme.palette.action.hover },
          }}
        >
          ‹
        </ButtonBase>
      ) : (
        <IconButton
          aria-label={labels.previousMonth}
          onClick={() => changeMonth(-1)}
          size="small"
          sx={{ color: theme.palette.text.secondary }}
        >
          <ChevronLeftRoundedIcon />
        </IconButton>
      )}

      <Typography
        sx={{
          minWidth: resolvedStyles.monthMinWidth,
          textAlign: headerLayout === "centered-year" ? "left" : "center",
          fontSize: resolvedStyles.monthFontSize,
          fontWeight: resolvedStyles.monthFontWeight,
          letterSpacing: "-0.02em",
          color: theme.palette.text.primary,
        }}
      >
        {monthLabel}
      </Typography>

      {navigationStyle === "text" ? (
        <ButtonBase
          aria-label={labels.nextMonth}
          onClick={() => changeMonth(1)}
          sx={{
            width: 32,
            height: 32,
            borderRadius: "8px",
            color: theme.palette.text.secondary,
            fontSize: 22,
            "&:hover": { bgcolor: theme.palette.action.hover },
          }}
        >
          ›
        </ButtonBase>
      ) : (
        <IconButton
          aria-label={labels.nextMonth}
          onClick={() => changeMonth(1)}
          size="small"
          sx={{ color: theme.palette.text.secondary }}
        >
          <ChevronRightRoundedIcon />
        </IconButton>
      )}
    </Box>
  );

  const yearLabel = (
    <Typography
      sx={{
        ml:
          headerLayout === "inline-year"
            ? resolvedStyles.inlineYearMarginLeft
            : 0,
        fontSize: resolvedStyles.yearFontSize,
        fontWeight: resolvedStyles.yearFontWeight,
        letterSpacing: "-0.02em",
        color: theme.palette.text.primary,
      }}
    >
      {formatCalendarNumber(visibleMonth.year, calendarLanguage)}
    </Typography>
  );

  return (
    <Box sx={{ width: "100%", overflowX: "auto", pb: 0.5 }}>
      <Paper
        variant="outlined"
        sx={{
          minWidth: resolvedStyles.minWidth,
          overflow: "hidden",
          borderRadius: "12px",
          borderColor: isDark ? alpha("#ffffff", 0.12) : "#f5f5f5",
          bgcolor: theme.palette.background.paper,
          backgroundImage: "none",
          boxShadow: "none",
        }}
      >
        <Box
          sx={
            headerLayout === "centered-year"
              ? {
                  height: resolvedStyles.headerHeight,
                  px: `${resolvedStyles.headerPaddingX}px`,
                  display: "grid",
                  gridTemplateColumns: "1fr auto 1fr",
                  alignItems: "center",
                }
              : {
                  height: resolvedStyles.headerHeight,
                  px: `${resolvedStyles.headerPaddingX}px`,
                  display: "flex",
                  alignItems: "center",
                  gap: 3,
                }
          }
        >
          {monthNavigation}
          {yearLabel}
        </Box>

        <Box
          sx={{
            display: "grid",
            gridTemplateColumns: "repeat(7, minmax(0, 1fr))",
            borderTop: `1px solid ${theme.palette.divider}`,
          }}
        >
          {weekdays.map((weekday) => (
            <Box
              key={weekday}
              sx={{
                height: resolvedStyles.weekdayHeight,
                display: "flex",
                alignItems: "center",
                justifyContent: "center",
                borderLeft: `1px solid ${theme.palette.divider}`,
                "&:first-of-type": { borderLeft: 0 },
              }}
            >
              <Typography
                sx={{
                  fontSize: 13,
                  fontWeight: 600,
                  color: theme.palette.text.primary,
                }}
              >
                {weekday}
              </Typography>
            </Box>
          ))}

          {days.map((day, index) => {
            const dayItems = itemsByDate.get(day.dateKey) ?? [];
            const columnIndex = index % 7;
            const isWeekend =
              weekStartsOn === 0
                ? columnIndex === 0 || columnIndex === 6
                : columnIndex === 5 || columnIndex === 6;
            const isToday = day.dateKey === todayDateKey;

            return (
              <Box
                key={day.dateKey}
                sx={{
                  minWidth: 0,
                  minHeight: resolvedStyles.dayMinHeight,
                  p: `${resolvedStyles.dayPadding}px`,
                  borderTop: `1px solid ${theme.palette.divider}`,
                  borderLeft:
                    columnIndex === 0
                      ? 0
                      : `1px solid ${theme.palette.divider}`,
                  bgcolor: isWeekend
                    ? isDark
                      ? alpha("#ffffff", 0.02)
                      : "#fcfcfc"
                    : "transparent",
                }}
              >
                <Box
                  sx={{
                    width: isToday ? resolvedStyles.todaySize : "auto",
                    height: isToday ? resolvedStyles.todaySize : "auto",
                    display: "inline-flex",
                    alignItems: "center",
                    justifyContent: "center",
                    borderRadius: "50%",
                    bgcolor: isToday
                      ? resolvedStyles.todayColor
                      : "transparent",
                    color: isToday
                      ? "#ffffff"
                      : day.isCurrentMonth
                        ? theme.palette.text.primary
                        : theme.palette.text.disabled,
                    fontSize: resolvedStyles.dayFontSize,
                    fontWeight: resolvedStyles.dayFontWeight,
                  }}
                >
                  {formatCalendarNumber(day.dayNumber, calendarLanguage)}
                </Box>

                {dayItems.length > 0 ? (
                  <Box sx={styles?.itemContainerSx}>
                    {dayItems.map((item) => (
                      <Box key={getItemId(item)} sx={{ width: "100%" }}>
                        {renderItem(item, { language: calendarLanguage })}
                      </Box>
                    ))}
                  </Box>
                ) : null}
              </Box>
            );
          })}
        </Box>
      </Paper>
    </Box>
  );
}
