import { useCallback } from "react";
import { CalendarDays, MapPin } from "lucide-react";
import { Link } from "react-router-dom";
import {
  DashboardWidgetList,
  DismissibleAlert,
  LoadingFrame,
  useDashboardWidgetData,
  type ApiSettings,
  type DashboardWidgetConfiguration
} from "@govoplan/core-webui";
import {
  listCalendarEvents,
  type CalendarEvent
} from "../../api/calendar";

export default function UpcomingEventsWidget({
  settings,
  refreshKey,
  configuration
}: {
  settings: ApiSettings;
  refreshKey: number;
  configuration: DashboardWidgetConfiguration;
}) {
  const maxItems = numberSetting(configuration.maxItems, 5, 1, 12);
  const daysAhead = numberSetting(configuration.daysAhead, 14, 1, 90);
  const showLocation = configuration.showLocation !== false;
  const load = useCallback(async () => {
    const start = new Date();
    const end = new Date(start);
    end.setDate(end.getDate() + daysAhead);
    const response = await listCalendarEvents(settings, {
      start_at: start.toISOString(),
      end_at: end.toISOString()
    });
    return [...response.events]
      .filter((event) => event.status !== "cancelled")
      .sort(
        (left, right) =>
          new Date(left.start_at).getTime() - new Date(right.start_at).getTime()
      )
      .slice(0, maxItems);
  }, [daysAhead, maxItems, settings]);
  const { data: events, loading, error } = useDashboardWidgetData(
    load,
    refreshKey
  );

  return (
    <LoadingFrame loading={loading} label="Loading upcoming calendar events">
      {error && (
        <DismissibleAlert tone="warning" resetKey={error}>
          {error}
        </DismissibleAlert>
      )}
      <DashboardWidgetList
        emptyText={`No events in the next ${daysAhead} days.`}
        items={(events ?? []).map((event) => ({
          id: event.id,
          title: event.summary,
          detail:
            showLocation && event.location ? (
              <>
                <MapPin size={12} aria-hidden="true" /> {event.location}
              </>
            ) : undefined,
          meta: eventTimeLabel(event),
          leading: <CalendarDays size={17} aria-hidden="true" />,
          to: "/calendar"
        }))}
      />
      <div className="dashboard-contribution-footer">
        <Link className="btn btn-secondary" to="/calendar">
          Open calendar
        </Link>
      </div>
    </LoadingFrame>
  );
}

function eventTimeLabel(event: CalendarEvent): string {
  const start = new Date(event.start_at);
  if (event.all_day) {
    return new Intl.DateTimeFormat(undefined, {
      weekday: "short",
      day: "2-digit",
      month: "short"
    }).format(start);
  }
  return new Intl.DateTimeFormat(undefined, {
    weekday: "short",
    day: "2-digit",
    month: "short",
    hour: "2-digit",
    minute: "2-digit"
  }).format(start);
}

function numberSetting(
  value: unknown,
  fallback: number,
  minimum: number,
  maximum: number
): number {
  const numeric = typeof value === "number" ? value : Number(value);
  return Number.isFinite(numeric)
    ? Math.max(minimum, Math.min(maximum, Math.floor(numeric)))
    : fallback;
}
