component Confetti {
  outputs {
    start(payload: { sourceEvent?: Event; duration: number })
    complete(payload: { sourceEvent?: Event; duration: number })
  }

  props {
    label: string = "Celebrate"
    duration: number = 1200
    count: number = 24
    autoStart: boolean = false
    disabled: boolean = false
    size: string = "default"
    color: string = "primary"
    class: string = ""
  }

  state running = false

  functions {
    shared function pieces() { return Array.from({ length: Math.max(1, Math.min(60, count)) }) }
    shared function pieceStyle(index) {
      return "--wrn-confetti-index:" + index + ";--wrn-confetti-x:" + ((index * 37) % 100) + ";--wrn-confetti-delay:" + ((index * 29) % 240) + "ms;"
    }
    client function finish(sourceEvent) {
      running = false
      output.complete({ sourceEvent: sourceEvent, duration: duration })
    }
    client function start(sourceEvent) {
      if (disabled || running) {
        return
      }
      running = true
      output.start({ sourceEvent: sourceEvent, duration: duration })
      setTimeout(finish, duration, sourceEvent)
    }
  }

  lifecycle {
    mount { if (autoStart) { start(null) } }
  }

  view {
    <div {...attrs} data-ui-component="Confetti" data-running='{running ? "true" : "false"}' class='wrn-confetti {class}' style='--wrn-confetti-duration:{duration}ms'>
      <button type="button" class="wrn-confetti__trigger" disabled='{disabled}' @click='start(event)'>
        <span class="icon-[lucide--party-popper]" aria-hidden="true"></span><span>{label}</span>
      </button>
      <div class="wrn-confetti__burst" aria-hidden="true">
        {#each pieces() as piece, index}<i style='{pieceStyle(index)}'></i>{/each}
      </div>
      <slot />
    </div>
  }

  style {
    .wrn-confetti { position: relative; display: inline-flex; }
    .wrn-confetti__trigger { display: inline-flex; min-height: 2.5rem; align-items: center; gap: 0.5rem; padding: 0.55rem 0.85rem; border: 1px solid var(--wrn-color-primary); border-radius: var(--wrn-radius); color: var(--wrn-color-on-primary); background: var(--wrn-color-primary); font: inherit; font-weight: 700; cursor: pointer; }
    .wrn-confetti__trigger > span:first-child { width: 1rem; height: 1rem; }
    .wrn-confetti__trigger:focus-visible { outline: 2px solid var(--wrn-color-focus); outline-offset: 2px; }
    .wrn-confetti__trigger:disabled { cursor: not-allowed; opacity: 0.55; }
    .wrn-confetti__burst { position: absolute; inset: 50% 0 auto; height: 0; pointer-events: none; }
    .wrn-confetti__burst > i { position: absolute; left: calc(var(--wrn-confetti-x) * 1%); width: 0.45rem; height: 0.7rem; border-radius: 0.1rem; opacity: 0; background: hsl(calc(var(--wrn-confetti-index) * 47deg) 80% 55%); transform: translate(-50%, 0) rotate(calc(var(--wrn-confetti-index) * 23deg)); }
    .wrn-confetti[data-running="true"] .wrn-confetti__burst > i { animation: wrn-confetti-burst var(--wrn-confetti-duration) cubic-bezier(0.2, 0.7, 0.2, 1) var(--wrn-confetti-delay) both; }
    @keyframes wrn-confetti-burst {
      0% { opacity: 1; transform: translate(-50%, 0) rotate(0); }
      100% { opacity: 0; transform: translate(calc(-50% + (var(--wrn-confetti-x) - 50) * 0.9px), 9rem) rotate(540deg); }
    }
    @media (prefers-reduced-motion: reduce) {
      .wrn-confetti[data-running="true"] .wrn-confetti__burst > i { animation-duration: 1ms; animation-delay: 0ms; }
    }
  }
}
