import { cn } from "~/lib/utils";
import { createSignal, createEffect, onCleanup, Show } from "solid-js";
import { Portal } from "solid-js/web";
import type { JSX } from "solid-js";

type ModalSize = "sm" | "md" | "lg";

interface ModalProps {
  isOpen: boolean;
  onClose: () => void;
  title?: string;
  children: JSX.Element;
  size?: ModalSize;
  class?: string;
}

const sizeClasses: Record<ModalSize, string> = {
  sm: "max-w-sm",
  md: "max-w-md",
  lg: "max-w-lg",
};

export default function Modal(props: ModalProps) {
  const [visible, setVisible] = createSignal(false);
  const [animating, setAnimating] = createSignal(false);
  let contentRef!: HTMLDivElement;

  createEffect(() => {
    if (props.isOpen) {
      setVisible(true);
      requestAnimationFrame(() => setAnimating(true));
    } else if (visible()) {
      setAnimating(false);
      const timer = setTimeout(() => setVisible(false), 200);
      onCleanup(() => clearTimeout(timer));
    }
  });

  createEffect(() => {
    if (props.isOpen) {
      const prev = document.body.style.overflow;
      document.body.style.overflow = "hidden";
      onCleanup(() => {
        document.body.style.overflow = prev;
      });
    }
  });

  const handleBackdropClick = (e: MouseEvent) => {
    if (e.target === e.currentTarget) {
      props.onClose();
    }
  };

  const handleKeyDown = (e: KeyboardEvent) => {
    if (e.key === "Escape") {
      props.onClose();
      return;
    }
    if (e.key === "Tab" && contentRef) {
      const focusable = contentRef.querySelectorAll<HTMLElement>(
        'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])',
      );
      const first = focusable[0];
      const last = focusable[focusable.length - 1];
      if (e.shiftKey && document.activeElement === first) {
        e.preventDefault();
        last?.focus();
      } else if (!e.shiftKey && document.activeElement === last) {
        e.preventDefault();
        first?.focus();
      }
    }
  };

  createEffect(() => {
    if (props.isOpen && visible() && contentRef) {
      const focusable = contentRef.querySelectorAll<HTMLElement>(
        'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])',
      );
      focusable[0]?.focus();
    }
  });

  return (
    <Show when={visible()}>
      <Portal mount={document.body}>
        <div
          class={cn(
            "fixed inset-0 z-50 flex items-center justify-center p-4 transition-colors duration-200",
            animating()
              ? "bg-black/50 backdrop-blur-sm"
              : "bg-transparent",
          )}
          onClick={handleBackdropClick}
          onKeyDown={handleKeyDown}
        >
          <div
            ref={contentRef}
            role="dialog"
            aria-modal="true"
            aria-label={props.title}
            class={cn(
              "gradient-card border border-[var(--color-border)]/50 rounded-xl w-full shadow-xl transition-all duration-200",
              animating()
                ? "scale-100 opacity-100"
                : "scale-95 opacity-0",
              sizeClasses[props.size ?? "md"],
              props.class,
            )}
          >
            {props.title && (
              <div class="flex items-center justify-between px-6 py-4 border-b border-[var(--color-border)]/50">
                <h2 class="text-lg font-semibold text-[var(--color-text-primary)]">
                  {props.title}
                </h2>
                <button
                  type="button"
                  onClick={props.onClose}
                  class="text-[var(--color-text-tertiary)] hover:text-[var(--color-text-primary)] transition-colors cursor-pointer"
                  aria-label="Close"
                >
                  <svg
                    xmlns="http://www.w3.org/2000/svg"
                    class="h-5 w-5"
                    viewBox="0 0 20 20"
                    fill="currentColor"
                  >
                    <path
                      fill-rule="evenodd"
                      d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z"
                      clip-rule="evenodd"
                    />
                  </svg>
                </button>
              </div>
            )}
            <div class="px-6 py-4">{props.children}</div>
          </div>
        </div>
      </Portal>
    </Show>
  );
}
