import {
  createContext,
  useContext,
  useEffect,
  useRef,
  useState,
  type ReactNode,
} from "react";
import { Outlet, matchPath, useLocation } from "react-router-dom";

type TwoPaneLayoutConfig = {
  left?: ReactNode;
  rightTop?: ReactNode;
  leftWidthClassName?: string;
  leftCollapsedWidthClassName?: string;
};

const TwoPaneLayoutContext = createContext<TwoPaneLayoutConfig | null>(null);
const DEFAULT_LEFT_WIDTH_PX = 300;
const LEFT_RAIL_WIDTH_PX = 32;
const AUTO_HIDE_MS = 5000;

export function useTwoPaneLayout() {
  const ctx = useContext(TwoPaneLayoutContext);
  if (!ctx) throw new Error("TwoPaneLayoutContext missing");
  return ctx;
}

export default function TwoPaneLayout({ value }: { value: TwoPaneLayoutConfig }) {
  const {
    left,
    rightTop,
    leftWidthClassName = "md:grid-cols-[300px_minmax(0,1fr)]",
    leftCollapsedWidthClassName = "md:grid-cols-[10px_minmax(0,1fr)]",
  } = value;
  const location = useLocation();
  const isContestsIndex = !!matchPath({ path: "/contests", end: true }, location.pathname);
  const isContestDetail = !!matchPath({ path: "/contests/:contestId", end: true }, location.pathname);
  const isRoundDetail = !!matchPath(
    { path: "/contests/:contestId/rounds/:roundId", end: true },
    location.pathname,
  );
  const [leftCollapsed, setLeftCollapsed] = useState(!isContestsIndex);
  const [leftPaneWidth, setLeftPaneWidth] = useState(DEFAULT_LEFT_WIDTH_PX);
  const leftPaneRef = useRef<HTMLDivElement | null>(null);
  const autoHideTimerRef = useRef<number | null>(null);

  useEffect(() => {
    setLeftCollapsed(!(isContestsIndex || isContestDetail));
  }, [isContestsIndex, isContestDetail]);

  useEffect(() => {
    if (!leftPaneRef.current || leftCollapsed) return;
    const width = leftPaneRef.current.getBoundingClientRect().width;
    if (width > 0 && width !== leftPaneWidth) {
      setLeftPaneWidth(width);
    }
  }, [leftCollapsed, leftPaneWidth, leftWidthClassName]);

  const clearAutoHide = () => {
    if (autoHideTimerRef.current) {
      window.clearTimeout(autoHideTimerRef.current);
      autoHideTimerRef.current = null;
    }
  };

  const scheduleAutoHide = () => {
    if (!isRoundDetail || leftCollapsed) return;
    clearAutoHide();
    autoHideTimerRef.current = window.setTimeout(() => {
      setLeftCollapsed(true);
    }, AUTO_HIDE_MS);
  };

  useEffect(() => {
    if (!isRoundDetail || leftCollapsed) {
      clearAutoHide();
      return;
    }
    scheduleAutoHide();
    return clearAutoHide;
  }, [isRoundDetail, leftCollapsed]);

  const handlePaneMouseEnter = () => {
    clearAutoHide();
  };

  const handlePaneMouseLeave = () => {
    scheduleAutoHide();
  };

  const translateX = leftCollapsed
    ? -(Math.max(0, leftPaneWidth - LEFT_RAIL_WIDTH_PX))
    : 0;
  const gridClassName = leftCollapsed ? leftCollapsedWidthClassName : leftWidthClassName;

  return (
    <TwoPaneLayoutContext.Provider value={value}>
      <div className={`w-full grid grid-cols-1 ${gridClassName} gap-6`}>
        <aside
          className="min-w-0 relative"
          onMouseEnter={handlePaneMouseEnter}
          onMouseLeave={handlePaneMouseLeave}
        >
          <button
            type="button"
            onClick={() => setLeftCollapsed((prev) => !prev)}
            className="absolute left-0 top-0 h-10 w-8 rounded-r bg-slate-200 text-slate-700 shadow hover:bg-slate-300 z-10"
            aria-label="Toggle left panel"
            onFocus={handlePaneMouseEnter}
            onBlur={handlePaneMouseLeave}
          >
            {leftCollapsed ? ">" : "<"}
          </button>
          <div className="overflow-hidden pt-10">
            <div
              ref={leftPaneRef}
              className={`min-w-0 transition-transform duration-300 ease-in-out${leftCollapsed ? " pointer-events-none" : ""}`}
              style={{
                width: leftCollapsed ? leftPaneWidth : undefined,
                transform: `translateX(${translateX}px)`,
              }}
              aria-hidden={leftCollapsed || undefined}
              onFocus={handlePaneMouseEnter}
              onBlur={handlePaneMouseLeave}
            >
              {left}
            </div>
          </div>
        </aside>

        <section className="min-w-0 space-y-4">
          {rightTop}
          <Outlet />
        </section>
      </div>
    </TwoPaneLayoutContext.Provider>
  );
}
