"use client";

import {
  useEffect,
  useId,
  useRef,
  useState,
  type CSSProperties,
} from "react";
import { timePickerDict, type TimePeriod } from "@/components/time-picker/dict";
import {
  formatOptionNumber,
  formatTimeDisplay,
  hourOptions,
  minuteOptions,
  parseTime24,
  toTime24,
} from "@/components/time-picker/utils";

type TimePickerProps = {
  id?: string;
  value: string;
  onChange: (value: string) => void;
  disabled?: boolean;
  className?: string;
};

export function TimePicker({
  id,
  value,
  onChange,
  disabled = false,
  className = "",
}: TimePickerProps) {
  const generatedId = useId();
  const inputId = id ?? generatedId;
  const containerRef = useRef<HTMLDivElement>(null);
  const panelRef = useRef<HTMLDivElement>(null);
  const parsed = parseTime24(value);

  const [open, setOpen] = useState(false);
  const [panelStyle, setPanelStyle] = useState<CSSProperties>({});
  const [hour12, setHour12] = useState(parsed.hour12);
  const [minute, setMinute] = useState(parsed.minute);
  const [period, setPeriod] = useState<TimePeriod>(parsed.period);

  const updatePanelPosition = () => {
    const rect = containerRef.current?.getBoundingClientRect();

    if (!rect) {
      return;
    }

    setPanelStyle({
      top: rect.bottom + 8,
      left: rect.left,
      width: rect.width,
    });
  };

  useEffect(() => {
    const next = parseTime24(value);
    setHour12(next.hour12);
    setMinute(next.minute);
    setPeriod(next.period);
  }, [value]);

  useEffect(() => {
    if (!open) {
      return;
    }

    updatePanelPosition();

    const handlePointerDown = (event: MouseEvent) => {
      const target = event.target as Node;

      if (
        !containerRef.current?.contains(target) &&
        !panelRef.current?.contains(target)
      ) {
        setOpen(false);
      }
    };

    const handleReposition = () => {
      updatePanelPosition();
    };

    document.addEventListener("mousedown", handlePointerDown);
    window.addEventListener("resize", handleReposition);
    window.addEventListener("scroll", handleReposition, true);

    return () => {
      document.removeEventListener("mousedown", handlePointerDown);
      window.removeEventListener("resize", handleReposition);
      window.removeEventListener("scroll", handleReposition, true);
    };
  }, [open]);

  const togglePicker = () => {
    if (disabled) {
      return;
    }

    if (open) {
      setOpen(false);
      return;
    }

    const current = parseTime24(value);
    setHour12(current.hour12);
    setMinute(current.minute);
    setPeriod(current.period);
    updatePanelPosition();
    setOpen(true);
  };

  const applyTime = (
    nextHour12: number,
    nextMinute: number,
    nextPeriod: TimePeriod,
  ) => {
    setHour12(nextHour12);
    setMinute(nextMinute);
    setPeriod(nextPeriod);
    onChange(toTime24(nextHour12, nextMinute, nextPeriod));
  };

  return (
    <>
      <div ref={containerRef} className={`relative ${className}`}>
        <button
          id={inputId}
          type="button"
          disabled={disabled}
          aria-haspopup="dialog"
          aria-expanded={open}
          onClick={togglePicker}
          className="flex h-12 w-full items-center justify-between gap-3 rounded-2xl bg-input px-4 text-sm shadow-soft-sm ring-1 ring-border outline-none transition-shadow focus:ring-2 focus:ring-primary disabled:cursor-not-allowed disabled:opacity-60"
        >
          <span dir="ltr" className="text-foreground">
            {formatTimeDisplay(value)}
          </span>
          <svg
            aria-hidden="true"
            className="size-4 shrink-0 text-muted-foreground"
            fill="none"
            viewBox="0 0 24 24"
            stroke="currentColor"
            strokeWidth={2}
          >
            <circle cx="12" cy="12" r="8" />
            <path d="M12 8v4l2 2" />
          </svg>
        </button>
      </div>

      {open ? (
        <div
          ref={panelRef}
          role="dialog"
          aria-label={timePickerDict.placeholder}
          style={panelStyle}
          className="fixed z-[105] overflow-hidden rounded-2xl border border-border bg-popover shadow-soft"
        >
          <div className="grid grid-cols-3 gap-2 p-3">
            <div className="space-y-2">
              <p className="px-1 text-xs font-medium text-muted-foreground">
                {timePickerDict.hour}
              </p>
              <div className="max-h-44 space-y-1 overflow-y-auto">
                {hourOptions.map((hour) => {
                  const selected = hour === hour12;

                  return (
                    <button
                      key={hour}
                      type="button"
                      onClick={() => applyTime(hour, minute, period)}
                      className={`flex h-9 w-full items-center justify-center rounded-xl text-sm transition-colors ${
                        selected
                          ? "bg-primary text-primary-foreground"
                          : "hover:bg-accent hover:text-accent-foreground"
                      }`}
                    >
                      {formatOptionNumber(hour)}
                    </button>
                  );
                })}
              </div>
            </div>

            <div className="space-y-2">
              <p className="px-1 text-xs font-medium text-muted-foreground">
                {timePickerDict.minute}
              </p>
              <div className="max-h-44 space-y-1 overflow-y-auto">
                {minuteOptions.map((minuteOption) => {
                  const selected = minuteOption === minute;

                  return (
                    <button
                      key={minuteOption}
                      type="button"
                      onClick={() => applyTime(hour12, minuteOption, period)}
                      className={`flex h-9 w-full items-center justify-center rounded-xl text-sm transition-colors ${
                        selected
                          ? "bg-primary text-primary-foreground"
                          : "hover:bg-accent hover:text-accent-foreground"
                      }`}
                    >
                      {formatOptionNumber(minuteOption, true)}
                    </button>
                  );
                })}
              </div>
            </div>

            <div className="space-y-2">
              <p className="px-1 text-xs font-medium text-muted-foreground">
                {timePickerDict.period}
              </p>
              <div className="space-y-2">
                {(["am", "pm"] as const).map((option) => {
                  const selected = option === period;
                  const label =
                    option === "am" ? timePickerDict.am : timePickerDict.pm;

                  return (
                    <button
                      key={option}
                      type="button"
                      title={
                        option === "am"
                          ? timePickerDict.amFull
                          : timePickerDict.pmFull
                      }
                      onClick={() => applyTime(hour12, minute, option)}
                      className={`flex h-9 w-full items-center justify-center rounded-xl text-sm font-medium transition-colors ${
                        selected
                          ? "bg-primary text-primary-foreground"
                          : "hover:bg-accent hover:text-accent-foreground"
                      }`}
                    >
                      {label}
                    </button>
                  );
                })}
              </div>
            </div>
          </div>
        </div>
      ) : null}
    </>
  );
}

export type { TimePickerProps };
