// packages/core/src/components/popover/popover-content.tsx
import type { JSX } from "solid-js";
import { Show, createEffect, onCleanup, splitProps } from "solid-js";
import { createDismiss } from "../../utilities/dismiss/create-dismiss";
import { createFocusTrap } from "../../utilities/focus-trap/create-focus-trap";
import { createScrollLock } from "../../utilities/scroll-lock/create-scroll-lock";
import { useInternalPopoverContext } from "./popover-context";

export interface PopoverContentProps extends JSX.HTMLAttributes<HTMLDivElement> {
  /** Keep mounted even when closed (for animation control). */
  forceMount?: boolean | undefined;
  children?: JSX.Element;
}

/**
 * Popover content panel with `role="dialog"`. Uses floating positioning.
 * When modal: focus trap + scroll lock. When non-modal: Tab closes popover.
 * Wrap with Popover.Portal to render outside the DOM tree.
 */
export function PopoverContent(props: PopoverContentProps): JSX.Element {
  const [local, rest] = splitProps(props, ["children", "forceMount", "style"]);
  const ctx = useInternalPopoverContext();

  const focusTrap = createFocusTrap(() => ctx.contentRef());
  const scrollLock = createScrollLock();
  const dismiss = createDismiss({
    getContainer: () => ctx.contentRef(),
    onDismiss: () => ctx.setOpen(false),
  });

  /** Non-modal Tab handler: Tab closes popover instead of trapping focus. */
  const handleKeyDown: JSX.EventHandler<HTMLDivElement, KeyboardEvent> = (e) => {
    if (!ctx.modal() && e.key === "Tab") {
      ctx.setOpen(false);
    }
  };

  createEffect(() => {
    if (ctx.isOpen()) {
      dismiss.attach();
      if (ctx.modal()) {
        focusTrap.activate();
        scrollLock.lock();
      }
    } else {
      focusTrap.deactivate();
      scrollLock.unlock();
      dismiss.detach();
    }
    onCleanup(() => {
      focusTrap.deactivate();
      scrollLock.unlock();
      dismiss.detach();
    });
  });

  return (
    <Show when={local.forceMount || ctx.isOpen()}>
      <div
        ref={(el) => ctx.setContentRef(el)}
        id={ctx.contentId()}
        role="dialog"
        aria-modal={ctx.modal() || undefined}
        data-state={ctx.isOpen() ? "open" : "closed"}
        style={
          typeof local.style === "string"
            ? `${styleToString(ctx.floatingStyle())};${local.style}`
            : { ...ctx.floatingStyle(), ...(local.style as JSX.CSSProperties) }
        }
        onKeyDown={handleKeyDown}
        {...rest}
      >
        {local.children}
      </div>
    </Show>
  );
}

/** Convert a JSX.CSSProperties object to an inline CSS string. */
function styleToString(style: JSX.CSSProperties): string {
  return Object.entries(style)
    .map(([k, v]) => `${k}:${v}`)
    .join(";");
}
