<script lang="ts">
  import { onMount } from 'svelte';
  import IconButton from '../iconbutton/IconButton.svelte';
  import { Cross20 } from '@mozaic-ds/icons-svelte';

  /**
   * A popover is a small overlay that appears above other content, typically triggered by a user interaction such as clicking or hovering over an element. It is used to display contextual information, additional actions, or interactive content without navigating away from the main interface. Popovers often include a title, description, and action buttons, and they automatically close when clicking outside or selecting an action.
   *
   * @slot default - Main content of the popover.
   * @slot footer - Use this slot to insert buttons or link in the footer.
   * @slot activator - Activator element that triggers the popover.
   */

  interface Props {
    [key: string]: any;
    /**
     * If `true`, display the popover.
     */
    open: boolean;
    /**
     * Allows to define the popover appearance.
     */
    appearance?: 'standard' | 'inverse';
    /**
     * Defines the preferred position of the popover relative to its activator.
     */
    position?: 'top' | 'right' | 'bottom' | 'left';
    /**
     * Controls the visibility of the popover pointer (arrow).
     */
    pointer?: boolean;
    /**
     * Determines the size of the popover.
     */
    size?: 's' | 'm' | 'l';
    /**
     * if `true`, display the close button.
     */
    closable?: boolean;
    /**
     * Title displayed at the top of the popover.
     */
    title?: string;
    /**
     * Supplementary text displayed below the title.
     */
    description?: string;
  }

  let {
    open = $bindable(),
    appearance = 'standard',
    position = 'top',
    pointer = true,
    size = 's',
    closable = true,
    title,
    description,
    class: className,
    ...attrs
  }: Props = $props();

  // TODO: Remove when typescript is up to date
  type PopoverOptions = {
    source: HTMLElement;
  };

  type Popover = {
    showPopover: (options?: PopoverOptions) => void;
    hidePopover: (options?: PopoverOptions) => void;
  };

  const id = crypto.randomUUID();

  let element: HTMLElement;
  let popover: HTMLElement;
  let activator: HTMLElement;

  function togglePopover() {
    if (!popover || !activator) return;

    if (open) {
      (popover as Popover).showPopover({ source: activator });
      popover.focus();
    } else {
      (popover as Popover).hidePopover({ source: activator });
    }
  }

  function handleClickOutside(event: MouseEvent) {
    const path = event.composedPath ? event.composedPath() : [];
    if (!path.includes(element) && !path.includes(activator)) {
      open = false;
    }
  }

  function onKeydown(event: KeyboardEvent) {
    if (event.key === 'Escape') {
      open = false;
    }
  }

  $effect(togglePopover);

  onMount(() => {
    document.addEventListener('mousedown', handleClickOutside);

    return () => {
      document.removeEventListener('mousedown', handleClickOutside);
    };
  });
</script>

<div
  bind:this={element}
  class={[
    'mc-popover',
    `mc-popover--${appearance}`,
    `mc-popover--${position}`,
    !pointer && 'mc-popover--no-pointer',
    `mc-popover--${size}`,
    className,
  ]}
  {...attrs}
>
  <div bind:this={activator}>
    <slot name="activator" />
  </div>

  <div
    bind:this={popover}
    id={`popover-${id}`}
    role="dialog"
    tabindex="0"
    class="mc-popover__wrapper"
    popover="manual"
    aria-labelledby={title ? `${id}-title` : undefined}
    aria-describedby={description ? `${id}-description` : undefined}
    onkeydown={onKeydown}
  >
    <div class="mc-popover__content">
      {#if title || description}
        <div class="mc-popover__headings">
          {#if title}
            <p id={`${id}-title`} class="mc-popover__title">
              {title}
            </p>
          {/if}

          {#if description}
            <p id={`${id}-description`} class="mc-popover__description">
              {description}
            </p>
          {/if}
        </div>
      {/if}

      <div>
        <slot />
      </div>

      {#if closable}
        {#snippet icon()}
          <Cross20 />
        {/snippet}
        <div class="mc-popover__close">
          <IconButton
            ghost
            {icon}
            {appearance}
            iconposition="only"
            aria-label="Close button"
            onclick={() => (open = false)}
          />
        </div>
      {/if}

      <footer class="mc-popover__footer">
        <slot name="footer" />
      </footer>
    </div>
  </div>
</div>

<style>/**
 * Do not edit directly, this file was auto-generated.
 */
.mc-popover__wrapper {
  border-radius: var(--border-radius-m, 0.5rem);
}
.mc-popover__wrapper:focus-visible {
  box-shadow: 0 0 0 0.125rem var(--focus-color-mid, var(--focus-color-outline-mid, #ffffff)), 0 0 0 0.25rem var(--focus-color-outer, var(--focus-color-outline-outer, #000000));
  outline: 0.125rem solid transparent;
  outline-offset: 0.125rem;
}
.mc-popover__wrapper {
  position: relative;
  padding: 1rem;
  background-color: var(--popover-color-background-standard, #ffffff);
  box-sizing: border-box;
  overflow: visible;
  border: var(--border-width-s, 0.0625rem) solid var(--popover-color-border-standard, #cccccc);
  box-shadow: var(--shadow-bottom-s-x, 0px) var(--shadow-bottom-s-y, 5px) var(--shadow-bottom-s-blur, 10px) var(--shadow-bottom-s-spread, -2px) rgba(0, 0, 0, var(--shadow-bottom-s-opacity, 20%));
}
@supports (width: max-content) {
  .mc-popover__wrapper {
    width: max-content;
  }
}
.mc-popover__wrapper::before {
  background-color: var(--popover-color-border-standard, #cccccc);
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' aria-hidden='true' height='0.5rem' width='0.5rem' viewBox='0 0 8 8'%3E%3Cpath d='M1.79 3.11l6.21-3.11v8l-6.21-3.11a1 1 0 0 1-.45-1.34 1 1 0 0 1 .45-.44z'/%3E%3C/svg%3E") no-repeat center/contain;
  content: "";
  height: 0.625rem;
  position: absolute;
  width: 0.625rem;
}
.mc-popover__wrapper::after {
  background-color: var(--popover-color-background-standard, #ffffff);
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' aria-hidden='true' height='0.5rem' width='0.5rem' viewBox='0 0 8 8'%3E%3Cpath d='M1.79 3.11l6.21-3.11v8l-6.21-3.11a1 1 0 0 1-.45-1.34 1 1 0 0 1 .45-.44z'/%3E%3C/svg%3E") no-repeat center/contain;
  content: "";
  height: 0.5rem;
  position: absolute;
  width: 0.5rem;
}
.mc-popover__content {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}
.mc-popover__headings {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}
.mc-popover__close {
  position: absolute;
  top: 4px;
  right: 4px;
}
.mc-popover__title {
  font-size: var(--font-body-s, 0.875rem);
  line-height: var(--line-height-s, 1.3);
  font-weight: var(--font-weight-semi-bold, 600);
  color: var(--popover-color-text-standard, #000000);
  margin: 0;
}
.mc-popover__description {
  font-size: var(--font-body-s, 0.875rem);
  line-height: var(--line-height-s, 1.3);
  font-weight: var(--font-weight-regular, 400);
  color: var(--popover-color-text-standard, #000000);
  margin: 0;
}
.mc-popover__footer {
  display: flex;
  justify-content: end;
  gap: 1rem;
}
.mc-popover--inverse .mc-popover__wrapper {
  background-color: var(--popover-color-background-inverse, #242938);
  border-color: var(--popover-color-border-inverse, #636d88);
}
.mc-popover--inverse .mc-popover__wrapper::before {
  background-color: var(--popover-color-border-inverse, #636d88);
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' aria-hidden='true' height='0.5rem' width='0.5rem' viewBox='0 0 8 8'%3E%3Cpath d='M1.79 3.11l6.21-3.11v8l-6.21-3.11a1 1 0 0 1-.45-1.34 1 1 0 0 1 .45-.44z'/%3E%3C/svg%3E") no-repeat center/contain;
}
.mc-popover--inverse .mc-popover__wrapper::after {
  background-color: var(--popover-color-background-inverse, #242938);
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' aria-hidden='true' height='0.5rem' width='0.5rem' viewBox='0 0 8 8'%3E%3Cpath d='M1.79 3.11l6.21-3.11v8l-6.21-3.11a1 1 0 0 1-.45-1.34 1 1 0 0 1 .45-.44z'/%3E%3C/svg%3E") no-repeat center/contain;
}
.mc-popover--inverse .mc-popover__title, .mc-popover--inverse .mc-popover__description {
  color: var(--popover-color-text-inverse, #ffffff);
}
.mc-popover--s .mc-popover__wrapper {
  width: 18rem;
}
.mc-popover--m .mc-popover__wrapper {
  width: 27.75rem;
}
.mc-popover--l .mc-popover__wrapper {
  width: 37.5rem;
}
.mc-popover--top .mc-popover__wrapper {
  margin: 0 0 10px;
  inset: auto;
  position-area: top;
}
.mc-popover--top .mc-popover__wrapper::after, .mc-popover--top .mc-popover__wrapper::before {
  bottom: 0;
  left: 50%;
  transform: translate(-50%, 100%) rotate(-90deg);
}
.mc-popover--top .mc-popover__wrapper::before {
  bottom: -1px;
}
.mc-popover--right .mc-popover__wrapper {
  margin: 0 0 0 10px;
  inset: auto;
  position-area: right;
}
.mc-popover--right .mc-popover__wrapper::after, .mc-popover--right .mc-popover__wrapper::before {
  top: 50%;
  left: 0;
  transform: translate(-99%, -50%);
}
.mc-popover--right .mc-popover__wrapper::before {
  left: -1px;
}
.mc-popover--left .mc-popover__wrapper {
  margin: 0 10px 0 0;
  inset: auto;
  position-area: left;
}
.mc-popover--left .mc-popover__wrapper::after, .mc-popover--left .mc-popover__wrapper::before {
  top: 50%;
  right: 0;
  transform: translate(99%, -50%) rotate(180deg);
}
.mc-popover--left .mc-popover__wrapper::before {
  right: -1px;
}
.mc-popover--bottom .mc-popover__wrapper {
  margin: 10px 0 0;
  inset: auto;
  position-area: bottom;
}
.mc-popover--bottom .mc-popover__wrapper::after, .mc-popover--bottom .mc-popover__wrapper::before {
  top: 0;
  left: 50%;
  transform: translate(-50%, -100%) rotate(90deg);
}
.mc-popover--bottom .mc-popover__wrapper::before {
  top: -1px;
}
.mc-popover--no-pointer .mc-popover__wrapper::after, .mc-popover--no-pointer .mc-popover__wrapper::before {
  background: none;
}</style>
