"use client";

import * as React from "react";
import Link from "next/link";
import {
  addDays,
  addMonths,
  format,
  isSameMonth,
  startOfMonth,
  subDays,
  subMonths,
} from "date-fns";
import { ChevronLeft, ChevronRight } from "lucide-react";

import { Button } from "@/components/ui/button";
import { Skeleton } from "@/components/ui/skeleton";
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group";
import { cn } from "@/lib/utils";
import { customerUrl } from "@/lib/tenant";

import { DashboardWidgetBody } from "@/app/customer/_components/dashboard-charts/dashboard-widget-body";
import { DashboardWidgetShell } from "@/app/customer/_components/dashboard-widget-shell";
import { useWidgetSettingsAction } from "@/app/customer/_components/dashboard-widget-configure-provider";
import { PortfolioScopeWidgetHint } from "@/app/customer/_components/portfolio-scope-widget-hint";
import { LAYOUT_IDS } from "@/app/customer/_lib/dashboard-layout";
import { useDashboardWidgetData } from "@/app/customer/_lib/use-dashboard-widget-data";
import { getStaticWidgetDefinition } from "@/app/customer/_lib/dashboard-widget-registry-definitions";
import { configureParamForWidget } from "@/app/customer/[tenant]/settings/_components/widget-config";
import { fetchCashflowCalendarWidgetClient } from "@/app/customer/[tenant]/reports/cashflow/_lib/cashflow-widget-api";
import type { CashflowCalendarWidgetData } from "@/app/customer/[tenant]/reports/cashflow/_lib/cashflow-widget-types";
import { CashflowDaySheet } from "@/app/customer/[tenant]/reports/cashflow/_components/cashflow-report/cashflow-day-sheet";
import { CashflowEventChip } from "@/app/customer/[tenant]/reports/cashflow/_components/cashflow-report/cashflow-event-chip";
import { CashflowLegendPopover } from "@/app/customer/[tenant]/reports/cashflow/_components/cashflow-report/cashflow-legend-popover";
import type { CashflowEvent } from "@/app/customer/[tenant]/reports/cashflow/_components/cashflow-report/schema";
import {
  buildCashflowLegend,
  CashflowMonthGrid,
  formatCashflowMonthTitle,
} from "@/app/customer/[tenant]/reports/cashflow/_components/cashflow-report/cashflow-month-grid";
import { CashflowStructureStatusIcon } from "@/app/customer/[tenant]/reports/cashflow/_components/cashflow-report/cashflow-structure-status-icon";
import {
  CASHFLOW_STRUCTURE_STATUSES,
  CASHFLOW_STRUCTURE_STATUS_DISPLAY,
} from "@/app/customer/[tenant]/reports/cashflow/_lib/cashflow-structure-status";
import {
  dateKey,
  clampDateToFilterRange,
  getWeekDays,
  groupEventsByDate,
  isToday,
} from "@/app/customer/[tenant]/reports/cashflow/_components/cashflow-report/utils";

const widgetMeta = getStaticWidgetDefinition("cashflow_calendar");

type WidgetViewMode = "day" | "week" | "month";

const toggleItemClass =
  "rounded-md px-2.5 text-xs data-[state=on]:bg-background data-[state=on]:text-foreground data-[state=on]:shadow-sm";

/** Month cells need room for day header + ≥1 chip + "+N more". */
const MONTH_MIN_CELL_HEIGHT_PX = 56;
const MONTH_MIN_WIDTH_PX = 460;
const WEEK_MIN_HEIGHT_PX = 240;
const WEEK_MIN_WIDTH_PX = 320;
const LEGEND_BAR_PX = 40;
const MONTH_PAD_PX = 32;
const WEEKDAY_HEADER_PX = 28;

/**
 * Prefer month when there is room for entries + "+more";
 * shrink to week, then day, when the widget gets too short/narrow.
 */
export function resolveCashflowAutoView(
  width: number,
  height: number,
  hasLegend: boolean,
): WidgetViewMode {
  if (width <= 0 || height <= 0) return "week";

  const legendH = hasLegend ? LEGEND_BAR_PX : 0;
  const monthAvailable = height - legendH - MONTH_PAD_PX - WEEKDAY_HEADER_PX;
  const monthCellH = monthAvailable / 6;

  if (monthCellH >= MONTH_MIN_CELL_HEIGHT_PX && width >= MONTH_MIN_WIDTH_PX) {
    return "month";
  }
  if (height >= WEEK_MIN_HEIGHT_PX && width >= WEEK_MIN_WIDTH_PX) {
    return "week";
  }
  return "day";
}

function CashflowWidgetDayView({
  anchor,
  eventsByDate,
  onDayClick,
  dateFrom = null,
  dateTo = null,
}: {
  anchor: Date;
  eventsByDate: Map<string, CashflowEvent[]>;
  onDayClick: (date: string) => void;
  dateFrom?: string | null;
  dateTo?: string | null;
}) {
  const focusKey = dateKey(anchor);
  const inRange =
    (!dateFrom || focusKey >= dateFrom.trim()) && (!dateTo || focusKey <= dateTo.trim());
  const events = inRange ? (eventsByDate.get(focusKey) ?? []) : [];
  const today = isToday(anchor);

  return (
    <div className="flex min-h-0 flex-1 flex-col gap-3 overflow-y-auto p-4">
      <div className="flex items-center justify-between gap-2 rounded-lg bg-sky-50 px-3 py-2.5 dark:bg-sky-950/30">
        <div className="min-w-0">
          <p className="text-sm font-semibold">{format(anchor, "EEEE, d MMM")}</p>
          <p className="text-[10px] text-muted-foreground">
            {events.length} event{events.length === 1 ? "" : "s"}
          </p>
        </div>
        {today ? (
          <span className="shrink-0 rounded-full bg-sky-600 px-2.5 py-0.5 text-[10px] font-medium text-white">
            Today
          </span>
        ) : null}
      </div>

      <div className="space-y-2">
        {events.map((event) => (
          <CashflowEventChip
            key={event.id}
            event={event}
            onClick={() => onDayClick(focusKey)}
          />
        ))}
        {events.length === 0 ? (
          <p className="rounded-md border border-dashed px-3 py-6 text-center text-xs text-muted-foreground">
            No events on this day.
          </p>
        ) : null}
      </div>
    </div>
  );
}

function CashflowWidgetWeekView({
  anchor,
  eventsByDate,
  onDayClick,
  dateFrom = null,
  dateTo = null,
}: {
  anchor: Date;
  eventsByDate: Map<string, CashflowEvent[]>;
  onDayClick: (date: string) => void;
  dateFrom?: string | null;
  dateTo?: string | null;
}) {
  const weekDays = React.useMemo(() => getWeekDays(anchor), [anchor]);
  const rangeFrom = dateFrom?.trim() || null;
  const rangeTo = dateTo?.trim() || null;

  return (
    <div className="grid min-h-0 min-w-0 flex-1 grid-cols-7 gap-px overflow-hidden rounded-lg border border-border/60 bg-border/60">
      {weekDays.map((day) => {
        const key = dateKey(day);
        const inRange =
          (!rangeFrom || key >= rangeFrom) && (!rangeTo || key <= rangeTo);
        const dayEvents = inRange ? (eventsByDate.get(key) ?? []) : [];
        const today = isToday(day);

        if (!inRange) {
          return (
            <div
              key={key}
              className="flex h-full min-h-0 min-w-0 flex-col border-0 bg-muted/15"
              aria-hidden
            />
          );
        }

        return (
          <div
            key={key}
            className={cn(
              "flex h-full min-h-0 min-w-0 flex-col border-0 bg-card",
              today && "bg-sky-50 ring-1 ring-inset ring-sky-500/25 dark:bg-sky-950/40",
            )}
          >
            <div
              className={cn(
                "shrink-0 border-b border-border/50 px-1 py-2 text-center",
                today ? "bg-sky-500/10" : "bg-muted/40",
              )}
            >
              <p className="font-medium text-[9px] text-muted-foreground uppercase tracking-wide">
                {format(day, "EEE")}
              </p>
              <button
                type="button"
                onClick={() => onDayClick(key)}
                className={cn(
                  "mt-0.5 inline-flex size-7 items-center justify-center rounded-full text-sm font-semibold tabular-nums transition-colors",
                  today ? "bg-sky-600 text-white" : "hover:bg-muted",
                )}
              >
                {format(day, "d")}
              </button>
              <p className="mt-0.5 text-[9px] text-muted-foreground tabular-nums">
                {dayEvents.length}
              </p>
            </div>
            <div className="min-h-0 flex-1 space-y-1 overflow-y-auto p-1">
              {dayEvents.length === 0 ? (
                <p className="py-4 text-center text-[9px] text-muted-foreground">—</p>
              ) : (
                dayEvents.map((event) => (
                  <CashflowEventChip
                    key={event.id}
                    event={event}
                    compact
                    minimal
                    onClick={() => onDayClick(key)}
                  />
                ))
              )}
            </div>
          </div>
        );
      })}
    </div>
  );
}

function CashflowLegendBar({
  legend,
}: {
  legend: ReturnType<typeof buildCashflowLegend>;
}) {
  return (
    <div className="shrink-0 border-b border-border/60 bg-muted/20 px-4 py-2">
      <div className="flex flex-wrap items-center gap-x-4 gap-y-2">
        <div className="flex flex-wrap items-center gap-2">
          {CASHFLOW_STRUCTURE_STATUS_DISPLAY.map((entry) => {
            const status = CASHFLOW_STRUCTURE_STATUSES.find((row) => row.id === entry.statusId);
            if (!status) return null;
            return (
              <div
                key={entry.statusId}
                className="flex shrink-0 items-center gap-1.5 rounded-full border border-border/50 bg-card/80 px-2.5 py-1 text-[10px] shadow-sm"
              >
                <CashflowStructureStatusIcon
                  earlyRedemption={status.earlyRedemption}
                  delivery={status.delivery}
                  size="sm"
                  suppressTitle
                />
                <span className="font-medium text-foreground/85">{entry.label}</span>
              </div>
            );
          })}
        </div>
        {legend.length > 0 ? (
          <div className="flex flex-wrap items-center gap-2">
            {legend.slice(0, 8).map((entry) => (
              <div
                key={entry.label}
                className="flex shrink-0 items-center gap-1.5 rounded-full border border-border/50 bg-card/80 px-2.5 py-1 text-[10px] shadow-sm"
              >
                <span className="size-2 rounded-full" style={{ backgroundColor: entry.color }} />
                <span className="max-w-[120px] truncate font-medium text-foreground/85">{entry.label}</span>
                <span className="rounded-full bg-muted px-1.5 py-0.5 font-semibold text-muted-foreground tabular-nums">
                  {entry.count}
                </span>
              </div>
            ))}
          </div>
        ) : null}
      </div>
    </div>
  );
}

function CashflowCalendarBody({
  anchor,
  anchorKey,
  view,
  eventsByDate,
  onDayClick,
  legend,
  onAutoViewChange,
  userPickedView,
  dateFrom = null,
  dateTo = null,
}: {
  anchor: Date;
  anchorKey: string;
  view: WidgetViewMode;
  eventsByDate: ReturnType<typeof groupEventsByDate>;
  onDayClick: (date: string) => void;
  legend: ReturnType<typeof buildCashflowLegend>;
  onAutoViewChange: (autoView: WidgetViewMode | null) => void;
  userPickedView: boolean;
  dateFrom?: string | null;
  dateTo?: string | null;
}) {
  const renderContent = () => {
    if (view === "day") {
      return (
        <CashflowWidgetDayView
          anchor={anchor}
          eventsByDate={eventsByDate}
          onDayClick={onDayClick}
          dateFrom={dateFrom}
          dateTo={dateTo}
        />
      );
    }

    if (view === "week") {
      return (
        <div className="flex min-h-0 flex-1 flex-col overflow-hidden p-4">
          <CashflowWidgetWeekView
            anchor={anchor}
            eventsByDate={eventsByDate}
            onDayClick={onDayClick}
            dateFrom={dateFrom}
            dateTo={dateTo}
          />
        </div>
      );
    }

    return (
      <div className="flex min-h-0 flex-1 flex-col overflow-hidden p-4">
        <CashflowMonthGrid
          key={anchorKey}
          anchor={anchor}
          eventsByDate={eventsByDate}
          onDayClick={onDayClick}
          widget
          fillHeight
          dateFrom={dateFrom}
          dateTo={dateTo}
        />
      </div>
    );
  };

  return (
    <DashboardWidgetBody>
      {({ width, height }) => (
        <CashflowSizeSync
          width={width}
          height={height}
          hasLegend={false}
          userPickedView={userPickedView}
          onAutoViewChange={onAutoViewChange}
        >
          {renderContent()}
        </CashflowSizeSync>
      )}
    </DashboardWidgetBody>
  );
}

function CashflowSizeSync({
  width,
  height,
  hasLegend,
  userPickedView,
  onAutoViewChange,
  children,
}: {
  width: number;
  height: number;
  hasLegend: boolean;
  userPickedView: boolean;
  onAutoViewChange: (autoView: WidgetViewMode | null) => void;
  children: React.ReactNode;
}) {
  React.useEffect(() => {
    if (userPickedView) {
      onAutoViewChange(null);
      return;
    }
    onAutoViewChange(resolveCashflowAutoView(width, height, hasLegend));
  }, [width, height, hasLegend, userPickedView, onAutoViewChange]);

  return <>{children}</>;
}

export function CashflowCalendarWidget({
  widgetId,
  title,
  layoutId,
}: {
  widgetId?: number;
  title?: string;
  layoutId?: string;
} = {}) {
  const [anchor, setAnchor] = React.useState(() => new Date());
  const [selectedDate, setSelectedDate] = React.useState<string | null>(null);
  const [sheetOpen, setSheetOpen] = React.useState(false);
  const [view, setView] = React.useState<WidgetViewMode>("week");
  const [userPickedView, setUserPickedView] = React.useState(false);

  const anchorKey = format(anchor, "yyyy-MM-dd");
  const isCurrentMonth = isSameMonth(anchor, new Date());
  const effectiveView = view;
  const showViewToggle = true;
  const resolvedLayoutId =
    layoutId ?? (widgetId && widgetId > 0 ? `cfw-${widgetId}` : LAYOUT_IDS.cashflowCalendar);
  const scopedWidgetId = widgetId && widgetId > 0 ? widgetId : null;
  // Instance widgets fetch a fixed configured range — do not refetch on calendar navigation.
  const anchorKeyForFetch = scopedWidgetId ? "" : anchorKey;

  const handleAutoViewChange = React.useCallback((autoView: WidgetViewMode | null) => {
    if (!autoView) return;
    setView((prev) => (prev === autoView ? prev : autoView));
  }, []);

  const handleViewChange = React.useCallback((next: WidgetViewMode) => {
    setUserPickedView(true);
    setView(next);
  }, []);

  const fetchIndividual = React.useCallback(
    async (resolvedTenant: string) => {
      const result = await fetchCashflowCalendarWidgetClient(
        resolvedTenant,
        scopedWidgetId
          ? { widgetId: scopedWidgetId }
          : { anchor: anchorKeyForFetch || format(new Date(), "yyyy-MM-dd") },
      );
      return { data: result.data, errorMessage: result.errorMessage };
    },
    [anchorKeyForFetch, scopedWidgetId],
  );

  const { tenant, data, loading, refreshing, error, refresh } = useDashboardWidgetData<CashflowCalendarWidgetData>({
    layoutId: resolvedLayoutId,
    fetchIndividual,
    skipBatch: !isCurrentMonth || Boolean(scopedWidgetId),
    widgetId: scopedWidgetId ?? undefined,
  });

  const allEvents = data?.events ?? [];
  const rangeFrom = data?.meta?.from?.trim() || null;
  const rangeTo = data?.meta?.to?.trim() || null;

  // Keep the calendar inside the Date Filter — no months before/after the selection.
  React.useEffect(() => {
    if (!rangeFrom && !rangeTo) return;
    setAnchor((prev) => {
      const clamped = clampDateToFilterRange(prev, rangeFrom, rangeTo);
      const next = effectiveView === "month" ? startOfMonth(clamped) : clamped;
      return next.getTime() === prev.getTime() ? prev : next;
    });
  }, [rangeFrom, rangeTo, effectiveView]);

  const navigatePrev = React.useCallback(() => {
    setAnchor((d) => {
      const stepped =
        effectiveView === "month"
          ? subMonths(d, 1)
          : effectiveView === "week"
            ? subDays(d, 7)
            : subDays(d, 1);
      const clamped = clampDateToFilterRange(stepped, rangeFrom, rangeTo);
      return effectiveView === "month" ? startOfMonth(clamped) : clamped;
    });
  }, [effectiveView, rangeFrom, rangeTo]);

  const navigateNext = React.useCallback(() => {
    setAnchor((d) => {
      const stepped =
        effectiveView === "month"
          ? addMonths(d, 1)
          : effectiveView === "week"
            ? addDays(d, 7)
            : addDays(d, 1);
      const clamped = clampDateToFilterRange(stepped, rangeFrom, rangeTo);
      return effectiveView === "month" ? startOfMonth(clamped) : clamped;
    });
  }, [effectiveView, rangeFrom, rangeTo]);

  /** Respect Dashboard Date Filter — chips only for dates inside meta.from/meta.to. */
  const eventsInConfiguredRange = React.useMemo(() => {
    if (!rangeFrom && !rangeTo) return allEvents;
    return allEvents.filter((event) => {
      const d = event.date?.trim();
      if (!d) return false;
      if (rangeFrom && d < rangeFrom) return false;
      if (rangeTo && d > rangeTo) return false;
      return true;
    });
  }, [allEvents, rangeFrom, rangeTo]);

  const eventsByDate = React.useMemo(
    () => groupEventsByDate(eventsInConfiguredRange),
    [eventsInConfiguredRange],
  );

  /** Legend chips only for events inside the Date Filter window. */
  const legend = React.useMemo(
    () => buildCashflowLegend(eventsInConfiguredRange),
    [eventsInConfiguredRange],
  );
  const selectedDayEvents = selectedDate
    ? rangeFrom && selectedDate < rangeFrom
      ? []
      : rangeTo && selectedDate > rangeTo
        ? []
        : (eventsByDate.get(selectedDate) ?? [])
    : [];
  const reportHref = customerUrl(tenant, widgetMeta.reportPath ?? "/reports/cashflow");
  const settingsHrefFallback =
    widgetId && widgetId > 0
      ? customerUrl(tenant, `/settings?section=dashboard&configure=${configureParamForWidget("cf", widgetId)}`)
      : customerUrl(tenant, "/settings?section=dashboard");
  const { settingsHref, onSettingsClick } = useWidgetSettingsAction(widgetId ?? 0, settingsHrefFallback);
  const displayTitle = title?.trim() || widgetMeta.label;
  const eventCountLabel = eventsInConfiguredRange.length;

  const openDay = (date: string) => {
    setSelectedDate(date);
    setSheetOpen(true);
  };

  const prevLabel =
    effectiveView === "month" ? "Previous month" : effectiveView === "week" ? "Previous week" : "Previous day";
  const nextLabel =
    effectiveView === "month" ? "Next month" : effectiveView === "week" ? "Next week" : "Next day";

  return (
    <>
      <DashboardWidgetShell
        title={displayTitle}
        subtitle={
          <p className="flex min-w-0 items-center gap-1.5 truncate">
            <span className="shrink-0">
              {formatCashflowMonthTitle(anchor)}
              {eventCountLabel > 0
                ? ` · ${eventCountLabel} event${eventCountLabel === 1 ? "" : "s"}`
                : ""}
            </span>
            <PortfolioScopeWidgetHint inline />
          </p>
        }
        reportHref={reportHref}
        settingsHref={settingsHref}
        onSettingsClick={onSettingsClick}
        loading={loading && !data}
        refreshing={refreshing}
        error={error}
        onRefresh={refresh}
        toolbar={
          showViewToggle ? (
            <div className="flex justify-end px-4 py-2">
              <ToggleGroup
                type="single"
                value={view}
                onValueChange={(v) => v && handleViewChange(v as WidgetViewMode)}
                variant="outline"
                size="sm"
                className="rounded-lg border border-border/60 bg-muted/40 p-1"
              >
                <ToggleGroupItem value="day" className={toggleItemClass}>
                  Day
                </ToggleGroupItem>
                <ToggleGroupItem value="week" className={toggleItemClass}>
                  Week
                </ToggleGroupItem>
                <ToggleGroupItem value="month" className={toggleItemClass}>
                  Month
                </ToggleGroupItem>
              </ToggleGroup>
            </div>
          ) : undefined
        }
        headerActions={
          <>
            <CashflowLegendPopover legend={legend} />
            <Button
              type="button"
              variant="outline"
              size="icon"
              className="size-8"
              onClick={navigatePrev}
              aria-label={prevLabel}
            >
              <ChevronLeft className="size-4" />
            </Button>
            <Button
              type="button"
              variant="outline"
              size="sm"
              className="h-8 px-2.5 text-xs"
              onClick={() =>
                setAnchor(
                  effectiveView === "month"
                    ? startOfMonth(clampDateToFilterRange(new Date(), rangeFrom, rangeTo))
                    : clampDateToFilterRange(new Date(), rangeFrom, rangeTo),
                )
              }
            >
              Today
            </Button>
            <Button
              type="button"
              variant="outline"
              size="icon"
              className="size-8"
              onClick={navigateNext}
              aria-label={nextLabel}
            >
              <ChevronRight className="size-4" />
            </Button>
          </>
        }
        loadingContent={<Skeleton className="m-4 min-h-[200px] w-[calc(100%-2rem)] rounded-lg" />}
        emptyContent={
          <div className="flex min-h-[200px] flex-col items-center justify-center p-4 text-center">
            <p className="text-sm text-muted-foreground">No cashflow events in this date range.</p>
            <Button asChild variant="link" size="sm" className="mt-1 h-auto p-0">
              <Link href={reportHref}>Open full cashflow report</Link>
            </Button>
          </div>
        }
      >
        {eventsInConfiguredRange.length > 0 ? (
          <CashflowCalendarBody
            anchor={anchor}
            anchorKey={anchorKey}
            view={effectiveView}
            eventsByDate={eventsByDate}
            onDayClick={openDay}
            legend={legend}
            onAutoViewChange={handleAutoViewChange}
            userPickedView={userPickedView}
            dateFrom={rangeFrom}
            dateTo={rangeTo}
          />
        ) : null}
      </DashboardWidgetShell>

      <CashflowDaySheet
        date={selectedDate}
        events={selectedDayEvents}
        open={sheetOpen}
        onOpenChange={setSheetOpen}
      />
    </>
  );
}
