component ChatBubble {
  outputs {
    action(payload: { action: boolean; item: string | number | boolean | null | object; index: number })
    messageClick(payload: { item: string | number | boolean | null | object; index: number; direction: string })
    avatarClick(payload: { item: string | number | boolean | null | object; index: number; direction: string })
    linkClick(payload: { link: string | number | boolean | null | object; item: string | number | boolean | null | object; index: number })
  }

  props {
    size: string = "default"
    color: string = "primary"
    title: string = ""
    description: string = ""
    items: unknown[] = []
    oneSided: boolean = false
    showAvatars: boolean = false
    showMetadata: boolean = false
    ariaLabel: string = "Conversation"
    variant: string = "default"
    class: string = ""
  }

  functions {
    shared function messageDirection(item) {
      return item.direction === "outgoing" ? "outgoing" : "incoming"
    }

    client function selectMessage(item, index) {
      output.messageClick({
        item: item,
        index: index,
        direction: messageDirection(item)
      })
    }

    client function selectAvatar(sourceEvent, item, index) {
      sourceEvent.stopPropagation()
      output.avatarClick({
        item: item,
        index: index,
        direction: messageDirection(item)
      })
    }

    client function selectLink(sourceEvent, link, item, index) {
      sourceEvent.stopPropagation()
      output.linkClick({
        link: link,
        item: item,
        index: index
      })
    }

    client function selectAction(sourceEvent, item, index) {
      sourceEvent.stopPropagation()
      output.action({
        action: item.action || "retry",
        item: item,
        index: index
      })
    }
  }

  view {
    <section
      {...attrs}
      class="wrn-component wrn-component--color-{color} wrn-component--size-{size} wrn-next--chat-bubble wrn-next--variant-{variant} {class}"
      data-one-sided="{oneSided}"
      role="log"
      aria-label="{ariaLabel}"
      aria-live="polite"
    >
      {#if title || description}
        <header class="wrn-next__chat-header">
          {#if title}<h3>{title}</h3>{/if}
          {#if description}<p>{description}</p>{/if}
        </header>
      {/if}

      {#if items.length}
        <div class="wrn-next__chat-thread">
          {#each items as item, index}
            <article
              class="wrn-next__chat-message"
              data-direction="{messageDirection(item)}"
              aria-label="{messageDirection(item) === 'outgoing' ? 'Sent message' : 'Received message'}"
            >
              <div class="wrn-next__chat-row">
                {#if showAvatars && (item.avatarSrc || item.avatarFallback)}
                  <button
                    class="wrn-next__chat-avatar"
                    type="button"
                    aria-label="{item.avatarLabel || item.author || 'Message author'}"
                    @click="selectAvatar(event, item, index)"
                  >
                    {#if item.avatarSrc}
                      <img src="{item.avatarSrc}" alt="{item.avatarAlt || ''}" />
                    {:else}
                      <span>{item.avatarFallback}</span>
                    {/if}
                  </button>
                {/if}

                <div
                  class="wrn-next__chat-content"
                  role="button"
                  tabindex="0"
                  @click="selectMessage(item, index)"
                  @keydown="if (event.key === 'Enter' || event.key === ' ') { event.preventDefault(); selectMessage(item, index) }"
                >
                  {#if item.title}<h4>{item.title}</h4>{/if}
                  {#if item.text}<p>{item.text}</p>{/if}
                  {#if item.bullets && item.bullets.length}
                    <ul>
                      {#each item.bullets as bullet}<li>{bullet}</li>{/each}
                    </ul>
                  {/if}
                  {#if item.links && item.links.length}
                    <nav aria-label="Message links">
                      {#each item.links as link}
                        <a
                          href="{link.href || '#'}"
                          @click="selectLink(event, link, item, index)"
                        >{link.label}</a>
                      {/each}
                    </nav>
                  {/if}
                </div>
              </div>

              {#if showMetadata && (item.timestamp || item.status || item.actionLabel)}
                <footer class="wrn-next__chat-meta" data-tone="{item.statusTone || 'muted'}">
                  {#if item.statusIcon}<span class="{item.statusIcon}" aria-hidden="true"></span>{/if}
                  {#if item.status}<span>{item.status}</span>{/if}
                  {#if item.timestamp}<time datetime="{item.datetime || ''}">{item.timestamp}</time>{/if}
                  {#if item.actionLabel}
                    <button type="button" @click="selectAction(event, item, index)">
                      {item.actionLabel}
                    </button>
                  {/if}
                </footer>
              {/if}
            </article>
          {/each}
        </div>
      {/if}
      <slot />
    </section>
  }

  style {
    .wrn-next--chat-bubble.wrn-component--size-sm {
      --wrn-chat-padding: 0.75rem;
      font-size: 0.875rem;
    }
    .wrn-next--chat-bubble.wrn-component--size-lg {
      --wrn-chat-padding: 1.25rem;
      font-size: 1.0625rem;
    }

    .wrn-next--chat-bubble {
      --wrn-chat-color: var(--wrn-component-color, var(--wrn-color-primary));
      --wrn-chat-padding: 1rem;
      display: grid;
      width: 100%;
      min-width: 0;
      gap: 1rem;
      color: var(--wrn-color-text);
    }

    .wrn-next__chat-header h3,
    .wrn-next__chat-header p,
    .wrn-next__chat-content h4,
    .wrn-next__chat-content p {
      margin: 0;
    }

    .wrn-next__chat-header p {
      margin-top: 0.35rem;
      color: var(--wrn-color-text-muted);
    }

    .wrn-next__chat-thread {
      display: grid;
      min-width: 0;
      gap: 1.25rem;
    }

    .wrn-next__chat-message {
      display: grid;
      width: min(78%, 34rem);
      min-width: 0;
      justify-self: start;
      gap: 0.4rem;
    }

    .wrn-next__chat-message[data-direction="outgoing"] {
      justify-self: end;
    }

    .wrn-next--chat-bubble[data-one-sided="true"] .wrn-next__chat-message {
      justify-self: start;
    }

    .wrn-next__chat-row {
      display: flex;
      min-width: 0;
      align-items: flex-start;
      gap: 0.75rem;
    }

    .wrn-next__chat-message[data-direction="outgoing"] .wrn-next__chat-row {
      flex-direction: row-reverse;
    }

    .wrn-next--chat-bubble[data-one-sided="true"]
      .wrn-next__chat-message[data-direction="outgoing"]
      .wrn-next__chat-row {
      flex-direction: row;
    }

    .wrn-next__chat-content {
      min-width: 0;
      padding: var(--wrn-chat-padding);
      border: 1px solid var(--wrn-color-border);
      border-radius: 1rem;
      background: var(--wrn-color-surface-raised, var(--wrn-color-surface));
      color: var(--wrn-color-text);
      cursor: pointer;
    }

    .wrn-next__chat-content:focus-visible {
      outline: 2px solid var(--wrn-chat-color);
      outline-offset: 2px;
    }

    .wrn-next__chat-message[data-direction="outgoing"] .wrn-next__chat-content {
      border-color: var(--wrn-chat-color);
      background: var(--wrn-chat-color);
      color: var(--wrn-color-primary-contrast, #fff);
    }

    .wrn-next__chat-message[data-direction="outgoing"] .wrn-next__chat-content :is(h4, p, li, span) {
      color: inherit;
    }

    .wrn-next__chat-content h4 {
      margin-bottom: 0.65rem;
      font-size: 1em;
    }

    .wrn-next__chat-content p + p,
    .wrn-next__chat-content p + nav {
      margin-top: 0.75rem;
    }

    .wrn-next__chat-content ul {
      display: grid;
      margin: 0.55rem 0 0;
      padding-inline-start: 1.25rem;
      gap: 0.35rem;
    }

    .wrn-next__chat-content nav {
      display: grid;
      margin-top: 0.75rem;
      gap: 0.3rem;
    }

    .wrn-next__chat-content a {
      color: var(--wrn-chat-color);
      font-weight: 650;
      text-decoration: none;
    }

    .wrn-next__chat-message[data-direction="outgoing"] .wrn-next__chat-content a {
      color: inherit;
      text-decoration: underline;
    }

    .wrn-next__chat-avatar {
      display: grid;
      flex: 0 0 2.5rem;
      width: 2.5rem;
      min-height: 2.5rem;
      overflow: hidden;
      padding: 0;
      border: 1px solid var(--wrn-color-border);
      border-radius: 999px;
      background: var(--wrn-color-surface-raised, var(--wrn-color-surface));
      color: var(--wrn-color-text);
      cursor: pointer;
      place-items: center;
    }

    .wrn-next__chat-avatar img {
      width: 100%;
      height: 100%;
      object-fit: cover;
    }

    .wrn-next__chat-avatar:focus-visible {
      outline: 2px solid var(--wrn-chat-color);
      outline-offset: 2px;
    }

    .wrn-next__chat-meta {
      display: flex;
      align-items: center;
      gap: 0.3rem;
      padding-inline: calc(2.5rem + 0.75rem);
      color: var(--wrn-color-text-muted);
      font-size: 0.78em;
    }

    .wrn-next__chat-message[data-direction="outgoing"] .wrn-next__chat-meta {
      justify-content: flex-end;
    }

    .wrn-next__chat-meta[data-tone="danger"] {
      color: var(--wrn-color-danger);
    }

    .wrn-next__chat-meta button {
      padding: 0;
      border: 0;
      background: transparent;
      color: inherit;
      font: inherit;
      font-weight: 700;
      cursor: pointer;
      text-decoration: underline;
    }

    @media (max-width: 640px) {
    .wrn-next__chat-message {
        width: min(92%, 34rem);
      }
    .wrn-next__chat-avatar {
        flex-basis: 2rem;
        width: 2rem;
        min-height: 2rem;
      }
    .wrn-next__chat-meta {
        padding-inline: 0;
      }
    }

    /* Shared component foundation. */

        .wrn-component {
          --wrn-component-color: var(--wrn-color-primary);
          --wrn-component-scale: 1;
          margin: 0;
          color: var(--wrn-color-text);
          font-family: var(--wrn-font-sans, inherit);
        }

        .wrn-component--color-primary {
          --wrn-component-color: var(--wrn-color-primary);
        }

        .wrn-component--color-secondary {
          --wrn-component-color: var(--wrn-color-secondary);
        }

        .wrn-component--color-success {
          --wrn-component-color: var(--wrn-color-success);
        }

        .wrn-component--color-warning {
          --wrn-component-color: var(--wrn-color-warning);
        }

        .wrn-component--color-danger {
          --wrn-component-color: var(--wrn-color-danger);
        }

        .wrn-component--color-info {
          --wrn-component-color: var(--wrn-color-info);
        }

        .wrn-component--size-xs {
          --wrn-component-scale: 0.78;
        }

        .wrn-component--size-sm {
          --wrn-component-scale: 0.88;
        }

        .wrn-component--size-default,
        .wrn-component--size-md {
          --wrn-component-scale: 1;
        }

        .wrn-component--size-lg {
          --wrn-component-scale: 1.14;
        }

        .wrn-component--size-xl {
          --wrn-component-scale: 1.28;
        }

        .wrn-component:not(.wrn-btn) {
          font-size: calc(1em * var(--wrn-component-scale));
        }

        .wrn-component :is(a, button, input, select, textarea):focus-visible {
          outline-color: var(--wrn-component-color);
        }

        .wrn-component p {
          margin: 0;
          color: var(--wrn-color-muted);
          line-height: 1.6;
        }
  }
}
