"use client";

import * as React from "react";
import { format } from "date-fns";

import { cn } from "@/lib/utils";

import { CashflowEventChip } from "@/app/customer/[tenant]/reports/cashflow/_components/cashflow-report/cashflow-event-chip";
import type { CashflowEvent } from "@/app/customer/[tenant]/reports/cashflow/_components/cashflow-report/schema";
import {
  WEEKDAY_LABELS,
  dateKey,
  format as formatDate,
  getCalendarDays,
  getWidgetCalendarDays,
  isCurrentMonth,
  isToday,
} from "@/app/customer/[tenant]/reports/cashflow/_components/cashflow-report/utils";

/** Fixed chip cap for non-widget / report-style grids. */
const MAX_VISIBLE_EVENTS = 3;
/** Soft cap for dashboard widget — actual count is driven by measured cell height. */
const MAX_VISIBLE_WIDGET_EVENTS = 8;

/** Conservative heights so widget chips never crowd out the "+N more" control. */
const CELL_DAY_HEADER_PX = 24;
const WIDGET_CHIP_PX = 20;
const WIDGET_MORE_PX = 18;
const CELL_PAD_PX = 6;

type CashflowMonthGridProps = {
  anchor: Date;
  eventsByDate: Map<string, CashflowEvent[]>;
  onDayClick: (date: string) => void;
  /** Shorter cells for dashboard widget. */
  compact?: boolean;
  /**
   * Dashboard cashflow widget mode. Adaptive chip capacity, date-filter
   * blank cells, and pinned "+more" apply only when this is true.
   */
  widget?: boolean;
  /** Distribute rows evenly to fill the widget container height. */
  fillHeight?: boolean;
  /** Optional fixed max chips (widget only; overrides measurement when > 0). */
  maxVisibleEvents?: number;
  /**
   * Inclusive yyyy-MM-dd window (widget Date Filter). Ignored unless `widget`.
   */
  dateFrom?: string | null;
  dateTo?: string | null;
};

/** Widget-only: estimate how many chips fit in a measured month cell. */
export function estimateMonthCellChipCapacity(
  cellHeightPx: number,
): { chipLimit: number; canShowMore: boolean } {
  if (cellHeightPx <= 0) {
    return { chipLimit: 2, canShowMore: true };
  }

  const content = cellHeightPx - CELL_DAY_HEADER_PX - CELL_PAD_PX;
  const canShowMore = content >= WIDGET_MORE_PX;
  const forChips = canShowMore ? content - WIDGET_MORE_PX : content;
  const chipLimit = Math.max(0, Math.floor(forChips / WIDGET_CHIP_PX));

  return { chipLimit: Math.min(MAX_VISIBLE_WIDGET_EVENTS, chipLimit), canShowMore };
}

export function CashflowMonthGrid({
  anchor,
  eventsByDate,
  onDayClick,
  compact = false,
  widget = false,
  fillHeight = false,
  maxVisibleEvents,
  dateFrom = null,
  dateTo = null,
}: CashflowMonthGridProps) {
  // Date-filter constraints are dashboard-widget only — the full report keeps a normal month grid.
  const rangeFrom = widget ? dateFrom?.trim() || null : null;
  const rangeTo = widget ? dateTo?.trim() || null : null;
  const constrainToFilter = widget && Boolean(rangeFrom || rangeTo);
  const monthDays = constrainToFilter
    ? getWidgetCalendarDays(anchor, rangeFrom, rangeTo)
    : getCalendarDays(anchor);
  const dense = compact || widget;
  const rowCount = Math.max(1, Math.ceil(monthDays.length / 7));
  const gridBodyRef = React.useRef<HTMLDivElement | null>(null);
  const [measuredCellHeight, setMeasuredCellHeight] = React.useState(0);

  const isDateInFilterRange = React.useCallback(
    (key: string) => {
      if (!widget) return true;
      if (rangeFrom && key < rangeFrom) return false;
      if (rangeTo && key > rangeTo) return false;
      return true;
    },
    [widget, rangeFrom, rangeTo],
  );

  React.useEffect(() => {
    if (!widget) return;
    const el = gridBodyRef.current;
    if (!el) return;

    let frame = 0;
    const update = () => {
      cancelAnimationFrame(frame);
      frame = requestAnimationFrame(() => {
        const rowH =
          rowCount > 0 ? Math.floor(el.clientHeight / rowCount) : el.firstElementChild?.clientHeight ?? 0;
        setMeasuredCellHeight((prev) => (prev === rowH ? prev : rowH));
      });
    };

    update();
    const ro = new ResizeObserver(update);
    ro.observe(el);
    return () => {
      cancelAnimationFrame(frame);
      ro.disconnect();
    };
  }, [widget, anchor, fillHeight, rowCount]);

  const capacity = React.useMemo(() => {
    if (!widget) {
      const cap =
        maxVisibleEvents != null && maxVisibleEvents > 0 ? maxVisibleEvents : MAX_VISIBLE_EVENTS;
      return { chipLimit: cap, canShowMore: true };
    }
    if (maxVisibleEvents != null && maxVisibleEvents > 0) {
      return { chipLimit: maxVisibleEvents, canShowMore: true };
    }
    return estimateMonthCellChipCapacity(measuredCellHeight);
  }, [widget, maxVisibleEvents, measuredCellHeight]);

  return (
    <div
      className={cn(
        "overflow-hidden rounded-lg border border-border/80 bg-card shadow-sm",
        fillHeight && "flex h-full min-h-0 flex-col",
      )}
    >
      <div className="grid shrink-0 grid-cols-7 border-b border-border/60 bg-muted/30">
        {WEEKDAY_LABELS.map((label) => (
          <div
            key={label}
            className="border-r border-border/40 px-1 py-1.5 text-center font-semibold text-[9px] text-muted-foreground uppercase tracking-wide last:border-r-0 sm:py-2 sm:text-[10px]"
          >
            {label}
          </div>
        ))}
      </div>
      <div
        ref={widget ? gridBodyRef : undefined}
        className={cn("grid grid-cols-7 bg-card", fillHeight && "min-h-0 flex-1")}
        style={fillHeight ? { gridTemplateRows: `repeat(${rowCount}, minmax(0, 1fr))` } : undefined}
      >
        {monthDays.map((day, index) => {
          if (!day) {
            return (
              <div
                key={`pad-${index}`}
                className={cn(
                  "border-r border-b border-border/40 bg-muted/10 last:border-r-0",
                  fillHeight ? "min-h-0" : widget ? "min-h-[72px]" : dense ? "min-h-[88px]" : "min-h-[148px]",
                )}
              />
            );
          }

          const key = dateKey(day);
          const dayEvents = isDateInFilterRange(key) ? (eventsByDate.get(key) ?? []) : [];
          const inMonth = isCurrentMonth(day, anchor);
          const today = isToday(day);
          const visibleCount = Math.min(dayEvents.length, Math.max(0, capacity.chipLimit));
          const visible = dayEvents.slice(0, visibleCount);
          const overflow = dayEvents.length - visible.length;
          const showMore = overflow > 0 && capacity.canShowMore;

          return (
            <div
              key={key}
              className={cn(
                "group/cell flex flex-col border-r border-b border-border/40 p-0.5 transition-colors last:border-r-0 sm:p-1",
                widget && "min-h-0 overflow-hidden",
                fillHeight ? "min-h-0" : widget ? "min-h-[72px]" : dense ? "min-h-[88px]" : "min-h-[148px]",
                !inMonth && "bg-muted/15",
                today && "bg-sky-500/[0.06] ring-1 ring-inset ring-sky-500/25",
                dayEvents.length > 0 && "hover:bg-muted/20",
              )}
            >
              <div className="mb-0.5 flex shrink-0 items-center justify-between gap-1 sm:mb-1">
                <button
                  type="button"
                  onClick={() => onDayClick(key)}
                  className={cn(
                    "flex size-5 items-center justify-center rounded-full text-[10px] tabular-nums transition-colors sm:size-6 sm:text-xs",
                    today && "bg-sky-600 font-semibold text-white",
                    !today && inMonth && "font-medium text-foreground/90 hover:bg-muted",
                    !inMonth && "text-muted-foreground/45",
                  )}
                >
                  {formatDate(day, "d")}
                </button>
                {dayEvents.length > 0 ? (
                  <span
                    className={cn(
                      "rounded-full bg-muted/80 px-1 py-0.5 font-medium text-muted-foreground tabular-nums",
                      widget ? "text-[7px]" : "text-[8px] opacity-0 transition-opacity group-hover/cell:opacity-100",
                    )}
                  >
                    {dayEvents.length}
                  </span>
                ) : null}
              </div>
              {widget ? (
                <div
                  className={cn(
                    "grid min-h-0 flex-1 overflow-hidden",
                    showMore ? "grid-rows-[minmax(0,1fr)_auto]" : "grid-rows-[minmax(0,1fr)]",
                  )}
                >
                  <div className="min-h-0 overflow-hidden">
                    <div className="flex flex-col gap-0.5">
                      {visible.map((event) => (
                        <CashflowEventChip
                          key={event.id}
                          event={event}
                          compact={dense}
                          minimal
                          onClick={() => onDayClick(key)}
                        />
                      ))}
                    </div>
                  </div>
                  {showMore ? (
                    <button
                      type="button"
                      onClick={() => onDayClick(key)}
                      className="mt-0.5 w-full shrink-0 truncate rounded border border-border/60 bg-muted/40 px-1 py-0.5 text-center text-[8px] font-semibold leading-none text-muted-foreground transition-colors hover:border-border hover:bg-muted hover:text-foreground"
                    >
                      +{overflow} more
                    </button>
                  ) : null}
                </div>
              ) : (
                <div className="flex min-h-0 flex-1 flex-col gap-0.5">
                  {visible.map((event) => (
                    <CashflowEventChip
                      key={event.id}
                      event={event}
                      compact={dense}
                      onClick={() => onDayClick(key)}
                    />
                  ))}
                  {showMore ? (
                    <button
                      type="button"
                      onClick={() => onDayClick(key)}
                      className="rounded border border-border/60 bg-muted/30 px-1.5 py-0.5 text-center text-[9px] font-medium text-muted-foreground transition-colors hover:border-border hover:bg-muted hover:text-foreground"
                    >
                      +{overflow} more
                    </button>
                  ) : null}
                </div>
              )}
            </div>
          );
        })}
      </div>
    </div>
  );
}

export function buildCashflowLegend(events: CashflowEvent[]) {
  const map = new Map<string, { label: string; color: string; count: number }>();
  for (const event of events) {
    const key = event.assetClassCode || event.assetClassLabel || "other";
    const existing = map.get(key);
    if (existing) {
      existing.count += 1;
    } else {
      map.set(key, { label: event.assetClassLabel || "Other", color: event.color, count: 1 });
    }
  }
  return [...map.values()].sort((a, b) => b.count - a.count);
}

export function formatCashflowMonthTitle(anchor: Date) {
  return format(anchor, "MMMM yyyy");
}
