import { useEffect, useRef, useState, type ReactNode } from "react";
import type { CalendarResponse } from "../shared/calendar";
import { habitRequest, scheduleLabel, type TodayHabit } from "../lib/dashboard";
import { CalendarHeatmap } from "./design-system/CalendarHeatmap";
import { monthWindow } from "./design-system/calendar-model";
import { Button } from "./design-system/primitives";
import { HabitChart } from "./design-system/HabitChart";
import { CalendarLegend } from "./design-system/CalendarLegend";
import { shade } from "../habits/calendar";
import { CheckInEditor } from "./CheckInEditor";
import { Field } from "./design-system/Field";
import { ItemActions } from "./design-system/ItemActions";

export function HabitHistory({
  habit,
  date,
  revision,
  onEdit,
  onDelete,
  disabled = false,
  children,
  tasks,
  editor,
  onExpired,
  onHistorySaved,
  calendarOnly = false,
}: {
  habit: TodayHabit;
  date: string;
  revision: number;
  onEdit?: (color: string) => void;
  onDelete?: () => void;
  disabled?: boolean;
  children?: ReactNode;
  tasks?: ReactNode;
  editor?: ReactNode;
  onExpired?: () => void;
  onHistorySaved?: () => void;
  calendarOnly?: boolean;
}) {
  const [selectedDate, setSelectedDate] = useState<string>();
  const [editingDay, setEditingDay] = useState(false);
  const [calendar, setCalendar] = useState<CalendarResponse | null>(null);
  const [error, setError] = useState("");
  const [attempt, setAttempt] = useState(0);
  const expired = useRef(onExpired);
  expired.current = onExpired;
  useEffect(() => {
    const controller = new AbortController();
    setError("");
    const range = monthWindow(date, 12);
    habitRequest<CalendarResponse>(
      `/habits/${habit.habitId}/calendar?${new URLSearchParams(range)}`,
      { signal: controller.signal },
    )
      .then((result) => {
        if (!controller.signal.aborted) setCalendar(result);
      })
      .catch((error) => {
        if (controller.signal.aborted) return;
        if (error.message.includes("session has expired") && expired.current)
          expired.current();
        else setError(error.message);
      });
    return () => controller.abort();
  }, [habit.habitId, date, revision, attempt]);

  const days =
    calendar?.days.map((day) => ({
      date: day.date,
      color: day.color,
      unit: day.habits[0]?.unit,
      value: day.habits[0]?.value ?? 0,
      target: day.habits[0]?.target ?? 0,
      state: day.future
        ? ("future" as const)
        : day.due
          ? ("due" as const)
          : ("not-due" as const),
    })) ?? [];
  const steps = Math.max(
    1,
    calendar?.days.find((day) => day.date === date)?.shadeCount ??
      habit.target ??
      1,
  );
  const shades = calendar
    ? [
        calendar.settings.emptyColor,
        ...Array.from(
          { length: Math.min(8, steps) },
          (_, index) =>
            shade(
              Math.ceil(((index + 1) * steps) / Math.min(8, steps)) / steps,
              steps,
              calendar.settings,
              true,
            ).color,
        ),
      ]
    : [];
  const chart = error ? (
    <div className="ds-form-feedback">
      <p role="alert">{error}</p>
      <Button
        variant="secondary"
        onClick={() => setAttempt((value) => value + 1)}
      >
        Retry history
      </Button>
    </div>
  ) : !calendar ? (
    <p className="ds-form-feedback" role="status">
      Loading your habit history…
    </p>
  ) : (
    <>
    <CalendarHeatmap
      onSelectDate={setSelectedDate}
      selectedDate={selectedDate}
      compact
      historyLabel="Your recorded progress"
      label={`${habit.name} progress calendar`}
      unit={habit.unit}
      color={calendar.settings.mainColor}
      emptyColor={calendar.settings.emptyColor}
      days={days}
      legend={
        <CalendarLegend
          label={`${habit.name} progress calendar`}
          days={days}
          color={calendar.settings.mainColor}
          shades={shades}
        />
      }
    />
    <div className="ds-action-row ds-history-actions">
      <Button variant="text" disabled={disabled} onClick={() => { setSelectedDate(selectedDate ?? date); setEditingDay(!editingDay); }} aria-expanded={editingDay}>
        {editingDay ? "Close check-in editor" : "Edit selected check-in"}
      </Button>
    </div>
    {editingDay && <div className="ds-history-editor">
      <div className="ds-form-stack"><Field label="Check-in date">{id => <input id={id} type="date" max={date} value={selectedDate ?? date} onChange={event => { if (event.target.value) setSelectedDate(event.target.value); }} />}</Field><p className="ds-supporting-copy">Update the progress recorded for this day.</p></div>
      <CheckInEditor key={`${habit.habitId}:${selectedDate ?? date}`} habitId={habit.habitId} date={selectedDate ?? date} disabled={disabled} onExpired={onExpired}
        onSaved={() => { setAttempt(value => value + 1); onHistorySaved?.(); }} />
    </div>}
    </>
  );
  if (calendarOnly) return chart;
  return (
    <HabitChart
      id={`history-${habit.habitId}`}
      name={habit.name ?? "Habit"}
      method={
        habit.method === "count"
          ? "Count target"
          : habit.method === "tasks"
            ? "Task-based"
            : "Simple check-in"
      }
      schedule={scheduleLabel(habit.requirements?.schedule)}
      due={habit.due}
      value={habit.value}
      target={habit.target ?? 0}
      unit={habit.unit}
      color={calendar?.settings.mainColor ?? "#196127"}
      calendar={chart}
      tasks={tasks}
      tasksLabel="Tasks"
      headingLevel={3}
      editor={editor}
      headingActions={onEdit && onDelete ? (
        <ItemActions name={habit.name ?? "Habit"} kind="habit" disabled={disabled || !calendar}
          onEdit={() => onEdit(calendar!.settings.mainColor)} onDelete={onDelete} />
      ) : undefined}
    >
      {children}
      {(onEdit || onDelete) && !(onEdit && onDelete) && (
        <div
          className="ds-actions"
          role="group"
          aria-label={`${habit.name} actions`}
        >
          {onEdit && (
            <Button
              variant="text"
              aria-label={`Edit ${habit.name}`}
              disabled={disabled || !calendar}
              onClick={() => onEdit(calendar!.settings.mainColor)}
            >
              Edit
            </Button>
          )}
          {onDelete && (
            <Button
              variant="text"
              aria-label={`Archive ${habit.name}`}
              disabled={disabled}
              onClick={onDelete}
            >
              Archive
            </Button>
          )}
        </div>
      )}
    </HabitChart>
  );
}
