<!-- eslint-disable @angular-eslint/template/button-has-type, @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus, @angular-eslint/template/cyclomatic-complexity, @angular-eslint/template/prefer-ngsrc -->
@let msg = message();
@let attachmentsList = attachmentViewModels();
<div
  appThemeNode="chatMessageBubble"
  [attr.data-message-id]="msg.id"
  class="group relative flex gap-3 rounded-lg p-2 transition-colors hover:bg-secondary/30"
  [class.opacity-50]="msg.isDeleted"
  (touchstart)="onMessageTouchStart($event)"
  (touchend)="onMessageTouchEnd()"
  (touchmove)="onMessageTouchEnd()"
  (touchcancel)="onMessageTouchEnd()"
>
  <div
    appThemeNode="chatMessageAvatar"
    class="flex-shrink-0 cursor-pointer"
    (click)="openSenderProfileCard($event); $event.stopPropagation()"
  >
    <app-user-avatar
      [name]="senderUser().displayName || msg.senderName"
      [avatarUrl]="senderUser().avatarUrl"
      size="md"
    />
  </div>

  <div
    appThemeNode="chatMessageContent"
    class="min-w-0 flex-1"
  >
    @if (msg.replyToId) {
      @let reply = repliedMessage();
      <div
        class="mb-1 flex cursor-pointer items-center gap-1.5 text-xs text-muted-foreground transition-colors hover:text-foreground"
        (click)="requestReferenceScroll(msg.replyToId)"
      >
        <div class="h-3 w-4 rounded-tl-md border-l-2 border-t-2 border-muted-foreground/50"></div>
        <ng-icon
          name="lucideReply"
          class="h-3 w-3"
        />
        @if (reply) {
          <span class="font-medium">{{ reply.senderName }}</span>
          <span class="max-w-[200px] truncate">{{ reply.isDeleted ? deletedMessageContent : reply.content }}</span>
        } @else {
          <span class="italic">Original message not found</span>
        }
      </div>
    }

    <div class="flex items-baseline gap-2">
      <span
        class="font-semibold text-foreground cursor-pointer hover:underline"
        (click)="openSenderProfileCard($event); $event.stopPropagation()"
        >{{ msg.senderName }}</span
      >
      <span class="text-xs text-muted-foreground">{{ formatTimestamp(msg.timestamp) }}</span>
      @if (msg.editedAt && !msg.isDeleted) {
        <span class="text-xs text-muted-foreground">(edited)</span>
      }
    </div>

    @if (isEditing()) {
      <div class="mt-1 flex items-start gap-2">
        <textarea
          #editTextareaRef
          rows="1"
          [(ngModel)]="editContent"
          (keydown.enter)="onEditEnter($event)"
          (keydown.escape)="cancelEdit()"
          (input)="autoResizeEditTextarea()"
          class="edit-textarea flex-1 rounded border border-border bg-secondary px-3 py-2 text-foreground focus:outline-none focus:ring-2 focus:ring-primary"
        ></textarea>
        <div class="flex flex-col gap-2">
          <button
            (click)="saveEdit()"
            class="grid h-6 w-6 place-items-center rounded text-primary transition-colors hover:bg-primary/10"
          >
            <ng-icon
              name="lucideCheck"
              class="h-4 w-4"
            />
          </button>
          <button
            (click)="cancelEdit()"
            class="grid h-6 w-6 place-items-center rounded text-muted-foreground transition-colors hover:bg-secondary"
          >
            <ng-icon
              name="lucideX"
              class="h-4 w-4"
            />
          </button>
        </div>
      </div>
    } @else {
      @if (msg.isDeleted) {
        <div class="mt-1 text-sm italic text-muted-foreground">{{ deletedMessageContent }}</div>
      } @else {
        @if (!pluginEmbedToken()) {
          @if (requiresRichMarkdown(msg.content)) {
            @defer {
              <div class="chat-markdown mt-1 break-words">
                <app-chat-message-markdown [content]="msg.content" />
              </div>
            } @placeholder {
              <div class="mt-1 whitespace-pre-wrap break-words text-sm text-foreground">{{ msg.content }}</div>
            }
          } @else {
            <div class="mt-1 whitespace-pre-wrap break-words text-sm text-foreground">{{ msg.content }}</div>
          }
        }

        @if (missingPluginEmbed(); as missingEmbed) {
          <article class="mt-2 max-w-lg rounded-md border border-border bg-secondary/30 p-3 text-sm text-muted-foreground">
            Required plugin is not installed to view this content, visit the
            <button
              type="button"
              class="font-semibold text-primary underline-offset-4 hover:underline"
              (click)="openMissingPluginStore(missingEmbed)"
            >
              store</button
            >.
          </article>
        }

        @if (msg.linkMetadata?.length) {
          @for (meta of msg.linkMetadata; track meta.url) {
            @if (shouldShowLinkEmbed(meta.url)) {
              <app-chat-link-embed
                [metadata]="meta"
                [canRemove]="isOwnMessage() || isAdmin()"
                (removed)="removeEmbed(meta.url)"
              />
            }
          }
        }

        @if (pluginEmbeds().length > 0) {
          <div
            class="mt-2 space-y-2"
            data-testid="plugin-message-embeds"
          >
            @for (embed of pluginEmbeds(); track embed.id) {
              <article class="rounded-md border border-border bg-secondary/30 p-3">
                <div class="mb-2 flex items-center justify-between gap-2 text-xs text-muted-foreground">
                  <span>{{ embed.contribution.embedType }}</span>
                  <span>{{ embed.pluginId }}</span>
                </div>
                <app-plugin-render-host [render]="embed.render" />
              </article>
            }
          </div>
        }

        @if (attachmentsList.length > 0) {
          <div class="mt-2 space-y-2">
            @for (att of attachmentsList; track att.id) {
              @if (att.isImage) {
                @if (att.available && att.objectUrl) {
                  <div
                    class="group/img relative inline-block"
                    (contextmenu)="openImageContextMenu($event, att)"
                  >
                    <img
                      [src]="att.objectUrl"
                      [alt]="att.filename"
                      class="max-h-80 w-auto cursor-pointer rounded-md"
                      (click)="openLightbox(att)"
                    />
                    <div class="pointer-events-none absolute inset-0 rounded-md bg-black/0 transition-colors group-hover/img:bg-black/20"></div>
                    <div class="absolute right-2 top-2 flex gap-1 opacity-0 transition-opacity group-hover/img:opacity-100">
                      <button
                        (click)="openLightbox(att); $event.stopPropagation()"
                        class="grid h-7 w-7 place-items-center rounded-md bg-black/60 text-white backdrop-blur-sm transition-colors hover:bg-black/80"
                        title="View full size"
                      >
                        <ng-icon
                          name="lucideExpand"
                          class="h-4 w-4"
                        />
                      </button>
                      <button
                        (click)="downloadAttachment(att); $event.stopPropagation()"
                        class="grid h-7 w-7 place-items-center rounded-md bg-black/60 text-white backdrop-blur-sm transition-colors hover:bg-black/80"
                        title="Download"
                      >
                        <ng-icon
                          name="lucideDownload"
                          class="h-4 w-4"
                        />
                      </button>
                    </div>
                  </div>
                } @else if ((att.receivedBytes || 0) > 0) {
                  <div
                    appThemeNode="chatAttachmentCard"
                    class="max-w-xs rounded-md border border-border bg-secondary/40 p-3"
                  >
                    <div class="flex items-center gap-3">
                      <div class="flex h-10 w-10 flex-shrink-0 items-center justify-center rounded-md bg-primary/10">
                        <ng-icon
                          name="lucideImage"
                          class="h-5 w-5 text-primary"
                        />
                      </div>
                      <div class="min-w-0 flex-1">
                        <div class="truncate text-sm font-medium">{{ att.filename }}</div>
                        <div class="text-xs text-muted-foreground">{{ formatBytes(att.receivedBytes || 0) }} / {{ formatBytes(att.size) }}</div>
                      </div>
                      <div class="text-xs font-medium text-primary">{{ ((att.receivedBytes || 0) * 100) / att.size | number: '1.0-0' }}%</div>
                    </div>
                    <div class="mt-2 h-1.5 overflow-hidden rounded-full bg-muted">
                      <div
                        class="h-full rounded-full bg-primary transition-all duration-300"
                        [style.width.%]="((att.receivedBytes || 0) * 100) / att.size"
                      ></div>
                    </div>
                  </div>
                } @else {
                  <div
                    appThemeNode="chatAttachmentCard"
                    class="max-w-xs rounded-md border border-dashed border-border bg-secondary/20 p-4"
                  >
                    <div class="flex items-center gap-3">
                      <div class="flex h-10 w-10 flex-shrink-0 items-center justify-center rounded-md bg-muted">
                        <ng-icon
                          name="lucideImage"
                          class="h-5 w-5 text-muted-foreground"
                        />
                      </div>
                      <div class="min-w-0 flex-1">
                        <div class="truncate text-sm font-medium text-foreground">{{ att.filename }}</div>
                        <div class="text-xs text-muted-foreground">{{ formatBytes(att.size) }}</div>
                        <div
                          class="mt-0.5 text-xs"
                          [class.italic]="!att.requestError"
                          [class.opacity-70]="!att.requestError"
                          [class.text-destructive]="!!att.requestError"
                          [class.text-muted-foreground]="!att.requestError"
                        >
                          {{ att.requestError || 'Waiting for image source...' }}
                        </div>
                      </div>
                    </div>
                    <button
                      (click)="retryImageRequest(att)"
                      class="mt-2 w-full rounded-md bg-secondary px-3 py-1.5 text-xs text-foreground transition-colors hover:bg-secondary/80"
                    >
                      Retry
                    </button>
                  </div>
                }
              } @else if (att.isVideo || att.isAudio) {
                @if (att.available && att.objectUrl) {
                  @if (att.isVideo) {
                    <app-chat-video-player
                      [src]="att.objectUrl"
                      [filename]="att.filename"
                      [sizeLabel]="formatBytes(att.size)"
                      (downloadRequested)="downloadAttachment(att)"
                    />
                  } @else {
                    <app-chat-audio-player
                      [src]="att.objectUrl"
                      [filename]="att.filename"
                      [sizeLabel]="formatBytes(att.size)"
                      (downloadRequested)="downloadAttachment(att)"
                    />
                  }
                } @else if ((att.receivedBytes || 0) > 0) {
                  <div
                    appThemeNode="chatAttachmentCard"
                    class="max-w-xl rounded-md border border-border bg-secondary/40 p-3"
                  >
                    <div class="flex items-start justify-between gap-3">
                      <div class="min-w-0 flex-1">
                        <div class="truncate text-sm font-medium">{{ att.filename }}</div>
                        <div class="text-xs text-muted-foreground">{{ formatBytes(att.receivedBytes || 0) }} / {{ formatBytes(att.size) }}</div>
                      </div>
                      <button
                        class="rounded bg-destructive px-2 py-1 text-xs text-destructive-foreground"
                        (click)="cancelAttachment(att)"
                      >
                        Cancel
                      </button>
                    </div>
                    <div class="mt-2 h-1.5 overflow-hidden rounded-full bg-muted">
                      <div
                        class="h-full rounded-full bg-primary transition-all duration-300"
                        [style.width.%]="att.progressPercent"
                      ></div>
                    </div>
                    <div class="mt-2 flex items-center justify-between text-xs text-muted-foreground">
                      <span>{{ att.progressPercent | number: '1.0-0' }}%</span>
                      @if (att.speedBps) {
                        <span>{{ formatSpeed(att.speedBps) }}</span>
                      }
                    </div>
                  </div>
                } @else {
                  <div
                    appThemeNode="chatAttachmentCard"
                    class="max-w-xl rounded-md border border-dashed border-border bg-secondary/20 p-4"
                  >
                    <div class="flex items-start justify-between gap-3">
                      <div class="min-w-0 flex-1">
                        <div class="truncate text-sm font-medium text-foreground">{{ att.filename }}</div>
                        <div class="text-xs text-muted-foreground">{{ formatBytes(att.size) }}</div>
                        <div
                          class="mt-1 text-xs leading-relaxed"
                          [class.opacity-80]="!att.requestError"
                          [class.text-destructive]="!!att.requestError"
                          [class.text-muted-foreground]="!att.requestError"
                        >
                          {{ att.mediaStatusText }}
                        </div>
                      </div>
                      <button
                        (click)="requestAttachment(att)"
                        class="shrink-0 rounded-md bg-secondary px-3 py-1.5 text-xs text-foreground transition-colors hover:bg-secondary/80"
                      >
                        {{ att.mediaActionLabel }}
                      </button>
                    </div>
                  </div>
                }
              } @else {
                <div
                  appThemeNode="chatAttachmentCard"
                  class="rounded-md border border-border bg-secondary/40 p-2"
                >
                  <div class="flex items-center justify-between">
                    <div class="min-w-0">
                      <div class="truncate text-sm font-medium">{{ att.filename }}</div>
                      <div class="text-xs text-muted-foreground">{{ formatBytes(att.size) }}</div>
                    </div>
                    <div class="flex items-center gap-2">
                      @if (!att.isUploader) {
                        @if (!att.available) {
                          <div class="h-1.5 w-24 rounded bg-muted">
                            <div
                              class="h-1.5 rounded bg-primary"
                              [style.width.%]="att.progressPercent"
                            ></div>
                          </div>
                          <div class="flex items-center gap-2 text-xs text-muted-foreground">
                            <span>{{ att.progressPercent | number: '1.0-0' }}%</span>
                            @if (att.speedBps) {
                              <span>• {{ formatSpeed(att.speedBps) }}</span>
                            }
                          </div>
                          @if (!(att.receivedBytes || 0)) {
                            <button
                              class="rounded bg-secondary px-2 py-1 text-xs text-foreground"
                              (click)="requestAttachment(att)"
                            >
                              {{ att.requestError ? 'Retry' : 'Request' }}
                            </button>
                          } @else {
                            <button
                              class="rounded bg-destructive px-2 py-1 text-xs text-destructive-foreground"
                              (click)="cancelAttachment(att)"
                            >
                              Cancel
                            </button>
                          }
                        } @else {
                          @if (att.canOpenExternally) {
                            <button
                              class="inline-flex items-center gap-1.5 rounded bg-secondary px-2 py-1 text-xs text-foreground transition-colors hover:bg-secondary/80"
                              (click)="openAttachmentExternally(att)"
                            >
                              <ng-icon
                                name="lucideExternalLink"
                                class="h-3.5 w-3.5"
                              />
                              Open
                            </button>
                          }
                          @if (att.canUseExperimentalPlayer) {
                            <button
                              class="inline-flex items-center gap-1.5 rounded bg-secondary px-2 py-1 text-xs text-foreground transition-colors hover:bg-secondary/80"
                              (click)="openExperimentalPlayer(att)"
                            >
                              <ng-icon
                                name="lucidePlay"
                                class="h-3.5 w-3.5"
                              />
                              Play
                            </button>
                          }
                          <button
                            class="rounded bg-primary px-2 py-1 text-xs text-primary-foreground"
                            (click)="downloadAttachment(att)"
                          >
                            Download
                          </button>
                        }
                      } @else {
                        <div class="text-xs text-muted-foreground">Shared from your device</div>
                        @if (att.canOpenExternally) {
                          <button
                            class="inline-flex items-center gap-1.5 rounded bg-secondary px-2 py-1 text-xs text-foreground transition-colors hover:bg-secondary/80"
                            (click)="openAttachmentExternally(att)"
                          >
                            <ng-icon
                              name="lucideExternalLink"
                              class="h-3.5 w-3.5"
                            />
                            Open
                          </button>
                        }
                        @if (att.canUseExperimentalPlayer) {
                          <button
                            class="inline-flex items-center gap-1.5 rounded bg-secondary px-2 py-1 text-xs text-foreground transition-colors hover:bg-secondary/80"
                            (click)="openExperimentalPlayer(att)"
                          >
                            <ng-icon
                              name="lucidePlay"
                              class="h-3.5 w-3.5"
                            />
                            Play
                          </button>
                        }
                      }
                    </div>
                  </div>
                  @if (!att.available && att.requestError) {
                    <div
                      class="mt-2 w-full rounded-md border border-destructive/20 bg-destructive/5 px-2.5 py-1.5 text-xs leading-relaxed text-destructive"
                    >
                      {{ att.requestError }}
                    </div>
                  }
                </div>
                @if (att.experimentalPlayerActive && att.objectUrl) {
                  @defer {
                    <app-experimental-vlc-player
                      [src]="att.objectUrl"
                      [filename]="att.filename"
                      [mime]="att.mime"
                      [sizeLabel]="formatBytes(att.size)"
                      (closed)="closeExperimentalPlayer()"
                      (downloadRequested)="downloadAttachment(att)"
                    />
                  } @loading {
                    <div class="mt-2 max-w-xl rounded-md border border-border bg-secondary/20 p-3 text-xs text-muted-foreground">
                      Loading experimental player...
                    </div>
                  }
                }
              }
            }
          </div>
        }
      }
    }

    @if (!msg.isDeleted && msg.reactions.length > 0) {
      <div class="mt-2 flex flex-wrap gap-1">
        @for (reaction of getGroupedReactions(); track reaction.emoji) {
          <button
            appThemeNode="chatReactionPill"
            (click)="toggleReaction(reaction.emoji)"
            class="flex items-center gap-1 rounded-full bg-secondary px-2 py-0.5 text-xs transition-colors hover:bg-secondary/80"
            [class.ring-1]="reaction.hasCurrentUser"
            [class.ring-primary]="reaction.hasCurrentUser"
          >
            <span>{{ reaction.emoji }}</span>
            <span class="text-muted-foreground">{{ reaction.count }}</span>
          </button>
        }
      </div>
    }
  </div>

  @if (!msg.isDeleted && !isMobile()) {
    <div
      appThemeNode="chatMessageActions"
      class="absolute right-2 top-2 flex items-center gap-1 rounded-lg border border-border bg-card shadow-lg opacity-0 transition-opacity group-hover:opacity-100"
    >
      <div class="relative">
        <button
          (click)="toggleEmojiPicker()"
          class="grid h-8 w-8 place-items-center rounded-l-lg transition-colors hover:bg-secondary"
        >
          <ng-icon
            name="lucideSmile"
            class="h-4 w-4 text-muted-foreground"
          />
        </button>

        @if (showEmojiPicker()) {
          <div class="absolute bottom-full right-0 z-10 mb-2 flex gap-1 rounded-lg border border-border bg-card p-2 shadow-lg">
            @for (emoji of commonEmojis; track emoji) {
              <button
                (click)="addReaction(emoji)"
                class="rounded p-1 text-lg transition-colors hover:bg-secondary"
              >
                {{ emoji }}
              </button>
            }
          </div>
        }
      </div>

      <button
        (click)="requestReply()"
        class="grid h-8 w-8 place-items-center transition-colors hover:bg-secondary"
      >
        <ng-icon
          name="lucideReply"
          class="h-4 w-4 text-muted-foreground"
        />
      </button>

      @if (isOwnMessage()) {
        <button
          (click)="startEdit()"
          class="grid h-8 w-8 place-items-center transition-colors hover:bg-secondary"
        >
          <ng-icon
            name="lucideEdit"
            class="h-4 w-4 text-muted-foreground"
          />
        </button>
      }

      @if (isOwnMessage() || isAdmin()) {
        <button
          (click)="requestDelete()"
          class="grid h-8 w-8 place-items-center rounded-r-lg transition-colors hover:bg-destructive/10"
        >
          <ng-icon
            name="lucideTrash2"
            class="h-4 w-4 text-destructive"
          />
        </button>
      }
    </div>
  }

  <ng-template #mobileSheetTpl>
    <app-bottom-sheet
      title="Message"
      ariaLabel="Message actions"
      (dismissed)="closeMobileActions()"
    >
      <div class="flex flex-col py-1">
        <div class="px-3 pb-2 pt-1">
          <p class="text-xs font-medium uppercase tracking-wide text-muted-foreground">React</p>
          <div class="mt-2 grid grid-cols-8 gap-1">
            @for (emoji of commonEmojis; track emoji) {
              <button
                type="button"
                class="rounded p-1 text-xl transition-colors hover:bg-secondary"
                (click)="onMobileReact(emoji)"
              >
                {{ emoji }}
              </button>
            }
          </div>
        </div>

        <div class="my-1 h-px bg-border"></div>

        <button
          type="button"
          class="flex w-full items-center gap-3 px-4 py-3 text-left text-sm text-foreground transition-colors hover:bg-secondary"
          (click)="onMobileReply()"
        >
          <ng-icon
            name="lucideReply"
            class="h-5 w-5 text-muted-foreground"
          />
          <span>Reply</span>
        </button>

        <button
          type="button"
          class="flex w-full items-center gap-3 px-4 py-3 text-left text-sm text-foreground transition-colors hover:bg-secondary"
          (click)="onMobileCopy()"
        >
          <ng-icon
            name="lucideCopy"
            class="h-5 w-5 text-muted-foreground"
          />
          <span>Copy message content</span>
        </button>

        @if (isOwnMessage()) {
          <button
            type="button"
            class="flex w-full items-center gap-3 px-4 py-3 text-left text-sm text-foreground transition-colors hover:bg-secondary"
            (click)="onMobileEdit()"
          >
            <ng-icon
              name="lucideEdit"
              class="h-5 w-5 text-muted-foreground"
            />
            <span>Edit</span>
          </button>
        }

        @if (isOwnMessage() || isAdmin()) {
          <button
            type="button"
            class="flex w-full items-center gap-3 px-4 py-3 text-left text-sm text-destructive transition-colors hover:bg-destructive/10"
            (click)="onMobileDelete()"
          >
            <ng-icon
              name="lucideTrash2"
              class="h-5 w-5"
            />
            <span>Delete</span>
          </button>
        }
      </div>
    </app-bottom-sheet>
  </ng-template>
</div>
