"use client";

import { createContext, useContext, useEffect, useMemo, useState } from "react";

import { useSessionContext } from "./session-provider";
import { safeStorageGet, safeStorageSet } from "../../lib/client-storage";

export type TimelineViewSettings = {
  dayWidth: number;
  rowHeight: number;
  bookingBarHeight: number;
};

export const desktopViewLimits = {
  dayWidth: { min: 26, max: 64 },
  rowHeight: { min: 25, max: 45 },
  bookingBarHeight: { min: 12, max: 30 }
} as const;

export const mobileViewLimits = {
  dayWidth: { min: 56, max: 168 },
  rowHeight: { min: 53, max: 121 },
  bookingBarHeight: { min: 24, max: 88 }
} as const;

type ViewSettingsContextValue = {
  settings: TimelineViewSettings;
  updateSettings: (patch: Partial<TimelineViewSettings>) => void;
  resetSettings: () => void;
};

const desktopDefaults: TimelineViewSettings = {
  dayWidth: 40,
  rowHeight: 29,
  bookingBarHeight: 16
};

const mobileDefaults: TimelineViewSettings = {
  dayWidth: 76,
  rowHeight: 63,
  bookingBarHeight: 46
};

const ViewSettingsContext = createContext<ViewSettingsContextValue | undefined>(undefined);

const clamp = (value: number, min: number, max: number) => Math.min(Math.max(value, min), max);

const getViewLimits = () => {
  if (typeof window !== "undefined" && window.matchMedia("(max-width: 767px)").matches) {
    return mobileViewLimits;
  }

  return desktopViewLimits;
};

const getDefaultSettings = (): TimelineViewSettings => {
  if (typeof window !== "undefined" && window.matchMedia("(max-width: 767px)").matches) {
    return mobileDefaults;
  }

  return desktopDefaults;
};

const normalizeSettings = (
  candidate: Partial<TimelineViewSettings> | null | undefined,
  fallback: TimelineViewSettings
): TimelineViewSettings => {
  const limits = getViewLimits();
  const dayWidth = clamp(Number(candidate?.dayWidth ?? fallback.dayWidth), limits.dayWidth.min, limits.dayWidth.max);
  const rowHeight = clamp(Number(candidate?.rowHeight ?? fallback.rowHeight), limits.rowHeight.min, limits.rowHeight.max);
  const bookingBarHeight = clamp(
    Number(candidate?.bookingBarHeight ?? fallback.bookingBarHeight),
    limits.bookingBarHeight.min,
    Math.min(limits.bookingBarHeight.max, rowHeight - 2)
  );

  return {
    dayWidth,
    rowHeight,
    bookingBarHeight
  };
};

const getStorageKey = (userId: string) => `rental.timeline-view.v3.${userId}`;

export const ViewSettingsProvider = ({ children }: { children: React.ReactNode }) => {
  const { session } = useSessionContext();
  const [settings, setSettings] = useState<TimelineViewSettings>(desktopDefaults);
  const [hydratedUserId, setHydratedUserId] = useState<string | null>(null);

  useEffect(() => {
    if (!session?.user.id) {
      setHydratedUserId(null);
      return;
    }

    const fallback = getDefaultSettings();

    if (typeof window === "undefined") {
      setSettings(fallback);
      setHydratedUserId(session.user.id);
      return;
    }

    const raw = safeStorageGet(getStorageKey(session.user.id));

    if (!raw) {
      setSettings(fallback);
      setHydratedUserId(session.user.id);
      return;
    }

    try {
      setSettings(normalizeSettings(JSON.parse(raw) as Partial<TimelineViewSettings>, fallback));
    } catch {
      setSettings(fallback);
    }

    setHydratedUserId(session.user.id);
  }, [session?.user.id]);

  useEffect(() => {
    if (!session?.user.id || hydratedUserId !== session.user.id || typeof window === "undefined") {
      return;
    }

    safeStorageSet(getStorageKey(session.user.id), JSON.stringify(settings));
  }, [hydratedUserId, session?.user.id, settings]);

  const value = useMemo<ViewSettingsContextValue>(
    () => ({
      settings,
      updateSettings: (patch) => {
        setSettings((current) => normalizeSettings({ ...current, ...patch }, current));
      },
      resetSettings: () => {
        setSettings(getDefaultSettings());
      }
    }),
    [settings]
  );

  return <ViewSettingsContext.Provider value={value}>{children}</ViewSettingsContext.Provider>;
};

export const useViewSettings = () => {
  const context = useContext(ViewSettingsContext);

  if (!context) {
    throw new Error("useViewSettings must be used within ViewSettingsProvider");
  }

  return context;
};
