"use client";

import { useEffect, useState } from "react";
import "./styles.css";

/* eslint-disable */
// Create a type for an enumeration of positive integers starting from 1 to N - 1
type BuildPositiveRange<
  N extends number,
  T extends any[] = [1],
  R = T["length"],
> = T["length"] extends N
  ? R
  : BuildPositiveRange<N, [...T, 1], R | T["length"]>;
/* eslint-enable */

// Positive numbers from 1 to 40 for columns
type PositiveColumnNumber = BuildPositiveRange<41>;

type BreakpointEntry = {
  columns: PositiveColumnNumber;
  gutter?: number;
};

type BreakpointName<T extends number> = `${T}x`;

type Breakpoint<T extends number> = {
  [K in BreakpointName<T>]: BreakpointEntry;
};

// Ensure at least one breakpoint using a required property
export type Breakpoints = Breakpoint<0> & Breakpoint<number>;

const defaultBreakpoints: Breakpoints = {
  "0x": {
    columns: 24,
    gutter: 0,
  },
  "320x": {
    columns: 24,
    gutter: 0,
  },
  "400x": {
    columns: 24,
    gutter: 0,
  },
  "480x": {
    columns: 24,
    gutter: 0,
  },
  "576x": {
    columns: 24,
    gutter: 0,
  },
  "672x": {
    columns: 24,
    gutter: 0,
  },
  "768x": {
    columns: 24,
    gutter: 0,
  },
  "896x": {
    columns: 24,
    gutter: 0,
  },
  "1024x": {
    columns: 24,
    gutter: 0,
  },
  "1152x": {
    columns: 24,
    gutter: 0,
  },
  "1280x": {
    columns: 24,
    gutter: 0,
  },
  "1408x": {
    columns: 24,
    gutter: 0,
  },
  "1536x": {
    columns: 24,
    gutter: 0,
  },
  "1920x": {
    columns: 24,
    gutter: 0,
  },
};

type Color = "blue" | "teal" | "green" | "amber" | "red" | "purple";

const colors: Array<Color> = [
  "blue",
  "teal",
  "green",
  "amber",
  "red",
  "purple",
];

type HUDPosition = "top" | "bottom";

export interface GridOverlayProps {
  breakpoints?: Breakpoints;
  active?: boolean;
  maxWidth?: "last-breakpoint" | "none";
}

function GridOverlay({
  breakpoints = defaultBreakpoints,
  active = true,
  maxWidth = "last-breakpoint",
}: GridOverlayProps) {
  const [isActive, setIsActive] = useState(active);
  const [columnsNumber, setColumnsNumber] = useState(breakpoints["0x"].columns);
  const [gutterSize, setGutterSize] = useState(0);
  const [selectedBreakpoint, setSelectedBreakpoint] = useState("");
  const [color, setColor] = useState(colors[0] as Color);
  const [HUDPosition, setHUDPosition] = useState("top" as HUDPosition);

  const breakpointValues = Object.entries(breakpoints).map(
    ([key, value], index) => ({
      name: key,
      width: parseInt(key.replace("x", ""), 10),
      columns: value.columns,
      gutter: (value.gutter ?? 0) >= 0 ? (value.gutter ?? 0) : 0,
      color: colors[index % colors.length] as Color,
    }),
  );

  const computeColumns = () => {
    if (!breakpointValues[0]) return;

    const width = window.innerWidth;

    const breakpoint = breakpointValues.reduce(
      (previousBreakpoint, currentBreakpoint) => {
        return width >= currentBreakpoint.width &&
          currentBreakpoint.width > previousBreakpoint.width
          ? currentBreakpoint
          : previousBreakpoint;
      },
      breakpointValues[0],
    );

    setColumnsNumber(breakpoint.columns);
    setGutterSize(breakpoint.gutter);
    setSelectedBreakpoint(breakpoint.name);
    setColor(breakpoint.color);
  };

  useEffect(() => {
    computeColumns();
    window.addEventListener("resize", computeColumns);

    return () => {
      window.removeEventListener("resize", computeColumns);
    };
  }, []);

  const toggleGrid = ({ isComposing, key }: KeyboardEvent) => {
    // !key => return when form autocomplete triggers a keydown event because of undefined key
    if (isComposing || !key || key.toLowerCase() !== "g") return;
    setIsActive((prevState) => !prevState);
  };

  useEffect(() => {
    document.addEventListener("keydown", toggleGrid);
    return () => {
      document.removeEventListener("keydown", toggleGrid);
    };
  }, []);

  const changeHUDPosition = () => {
    if (HUDPosition === "top") {
      setHUDPosition("bottom");
    } else {
      setHUDPosition("top");
    }
  };

  return (
    <div
      data-active={isActive}
      className="gd-pointer-events-none gd-relative gd-z-[9999] data-[active=false]:gd-hidden"
    >
      <div
        className={[
          "gd-fixed gd-inset-x-0 gd-inset-y-0 gd-z-50 gd-flex gd-h-full",
          "data-[color=blue]:gd-bg-blue-700/[0.1] data-[color=blue]:gd-text-blue-400",
          "data-[color=teal]:gd-bg-teal-700/[0.1] data-[color=teal]:gd-text-teal-400",
          "data-[color=green]:gd-bg-green-700/[0.1] data-[color=green]:gd-text-green-400",
          "data-[color=amber]:gd-bg-amber-700/[0.1] data-[color=amber]:gd-text-amber-400",
          "data-[color=red]:gd-bg-red-700/[0.1] data-[color=red]:gd-text-red-400",
          "data-[color=purple]:gd-bg-purple-700/[0.1] data-[color=purple]:gd-text-purple-400",
        ].join(" ")}
        data-color={color}
        style={{
          maxWidth:
            maxWidth === "last-breakpoint"
              ? (breakpointValues.slice(-1)[0]?.width ?? undefined)
              : undefined,
          marginLeft: maxWidth === "last-breakpoint" ? "auto" : undefined,
          marginRight: maxWidth === "last-breakpoint" ? "auto" : undefined,
        }}
      >
        <button
          type="button"
          className="gd-pointer-events-auto gd-absolute gd-left-1/2 gd--translate-x-1/2 gd-overflow-hidden gd-rounded-[999px] gd-border-[1px] gd-border-current gd-bg-[black] gd-shadow-[0_0_5px_0_rgba(0,0,0,1)] data-[hud-position=bottom]:gd-bottom-[16px] data-[hud-position=top]:gd-top-[16px]"
          onClick={changeHUDPosition}
          data-hud-position={HUDPosition}
        >
          <p className="gd-font-medium gd-px-[12px] gd-py-[4px] gd-font-sans gd-text-[white]/[0.9]">
            {selectedBreakpoint}
          </p>
        </button>
        {Array.from({ length: columnsNumber }).map((_, index) => (
          <div
            key={index}
            className="gd-h-full gd-w-full gd-border-l-[1px] gd-border-l-current last:gd-border-r-[1px] last:gd-border-r-current"
            style={{ paddingLeft: gutterSize, paddingRight: gutterSize }}
          >
            {gutterSize > 0 && (
              <div className="gd-h-full gd-w-full gd-border-l-[1px] gd-border-l-current last:gd-border-r-[1px] last:gd-border-r-current" />
            )}
          </div>
        ))}
      </div>
    </div>
  );
}
GridOverlay.displayName = "GridOverlay";

export { GridOverlay };
