<svelte:options
  customElement={{
    tag: 'm-star-rating',
    props: {
      readonly: { reflect: true, type: 'Boolean', attribute: 'readonly' },
      compact: { reflect: true, type: 'Boolean', attribute: 'compact' },
    },
    extend: customElementForwardEvents,
  }}
/>

<script lang="ts">
  import { customElementForwardEvents } from '../../utils';
  import { Star24, StarFilled24, StarHalf24 } from '@mozaic-ds/icons-svelte';
  /**
   * A Star rating visually represents a score or evaluation and can be used to display a rating or allow users to rate an item, such as a product or service. It serves two main purposes: collecting user feedback by enabling individuals to express their experience and providing social proof by displaying ratings from other users to assist decision-making. Rating Stars are commonly found in e-commerce, review systems, and feedback interfaces, offering a quick and intuitive way to assess quality or satisfaction.
   */
  interface Props {
    [key: string]: any;
    /**
     * The current rating value of the component.
     */
    rating: number;
    /**
     * Determines whether the rating is interactive or read-only.
     * When true, all user interactions (click, hover, keyboard) are disabled.
     * Automatically set to true when `compact`, `href`, or `information` are provided.
     */
    readonly?: boolean;
    /**
     * Defines the visual size of the star icons and the accompanying text.
     */
    size?: 's' | 'm' | 'l';
    /**
     * Enables a compact display mode that shows only one star instead of five.
     * Typically used for summaries or quick visual cues.
     * When enabled, the component automatically becomes read-only.
     */
    compact?: boolean;
    /**
     * Specifies the color scheme of the stars.
     */
    appearance?: 'standard' | 'accent';
    /**
     * Optional text displayed next to the star rating.
     * If provided, the component automatically becomes read-only.
     */
    text?: string;
    /**
     * URL for the link.
     */
    href?: string;
    /**
     * Where to open the link.
     */
    target?: '_self' | '_blank' | '_parent' | '_top';
  }

  let {
    rating = $bindable(),
    readonly,
    size = 'm',
    compact,
    appearance = 'standard',
    text,
    href,
    target,
  }: Props = $props();

  let hoverValue: number | null = $state(null);
  const rootTag = $derived(href ? 'a' : 'div');

  const isReadonly = $derived([readonly, compact, href, text].some(Boolean));

  const classObject = $derived({
    'mc-star-rating': true,
    'mc-star-rating--link': href,
    'mc-star-rating--slider': !isReadonly,
    [`mc-star-rating--${size}`]: size,
    [`mc-star-rating--${appearance}`]: appearance,
  });

  const displayValue = $derived(hoverValue ?? rating);
  const maxValue = $derived(compact ? 1 : 5);

  function getStarComponent(index: number) {
    if (compact || displayValue >= index + 1) {
      return StarFilled24;
    } else if (isReadonly && displayValue >= index + 0.5) {
      return StarHalf24;
    } else {
      return Star24;
    }
  }

  function onHover(index: number) {
    hoverValue = index + 1;
  }

  function clearHover() {
    hoverValue = null;
  }

  function onClick(index: number) {
    rating = index + 1;
  }

  function onKeydown(e: KeyboardEvent) {
    const key = e.key;
    let newValue = Math.floor(rating);

    if (key === 'ArrowRight') {
      newValue = Math.min(maxValue, newValue + 1);
    } else if (key === 'ArrowLeft') {
      newValue = Math.max(1, newValue - 1);
    } else return;

    rating = newValue;

    e.preventDefault();
  }

  const wrapperAttrs = $derived(
    isReadonly
      ? {
          tabindex: -1,
        }
      : {
          onkeydown: onKeydown,
          onmouseleave: clearHover,
          onblur: clearHover,
          tabindex: 0,
          'aria-valuemin': 0,
          'aria-valuemax': maxValue,
          'aria-valuenow': rating,
          'aria-readonly': false,
        },
  );
</script>

<svelte:element this={rootTag} {href} {target} class={classObject}>
  <div
    class="mc-star-rating__wrapper"
    role={isReadonly ? 'img' : 'slider'}
    aria-label={`Note ${displayValue} sur ${maxValue}`}
    {...wrapperAttrs}
  >
    {#each Array.from({ length: maxValue }).keys() as index (index)}
      {@const Star = getStarComponent(index)}

      <span
        class="mc-star-rating__icon"
        {...!isReadonly
          ? {
              onmousemove: () => onHover(index),
              onclick: () => onClick(index),
            }
          : {}}
      >
        <Star />
      </span>
    {/each}
  </div>

  {#if text || href}
    <span class="mc-star-rating__info">
      {text || href}
    </span>
  {/if}
</svelte:element>

<style>/**
 * Do not edit directly, this file was auto-generated.
 */
.mc-star-rating {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
}
.mc-star-rating--standard .mc-star-rating__icon {
  fill: var(--star-rating-color-icon-standard, #000000);
}
.mc-star-rating--accent .mc-star-rating__icon {
  fill: var(--star-rating-color-icon-accent, #ea7315);
}
.mc-star-rating--slider {
  cursor: pointer;
}
.mc-star-rating--link {
  text-decoration: none;
  cursor: pointer;
}
.mc-star-rating--link:not(:hover) .mc-star-rating__info {
  text-decoration: underline;
}
.mc-star-rating--s .mc-star-rating__icon {
  width: 1.25rem;
  height: 1.25rem;
}
.mc-star-rating--s .mc-star-rating__info {
  font-size: var(--font-size-100, 0.875rem);
}
.mc-star-rating--m .mc-star-rating__icon {
  width: 1.5rem;
  height: 1.5rem;
}
.mc-star-rating--m .mc-star-rating__info {
  font-size: var(--font-size-150, 1rem);
}
.mc-star-rating--l .mc-star-rating__icon {
  width: 2rem;
  height: 2rem;
}
.mc-star-rating--l .mc-star-rating__info {
  font-size: var(--font-size-200, 1.125rem);
}
.mc-star-rating__wrapper {
  display: flex;
  align-items: center;
}
.mc-star-rating__info {
  font-weight: var(--font-weight-medium, 600);
  line-height: var(--line-height-s, 1.3);
  color: var(--star-rating-color-text, #000000);
}

.mc-star-rating__icon :global(svg) {
  height: 100%;
  width: 100%;
}</style>
