<template>
  <div
    class="group/msg flex animate-fade-up-fast"
    :class="isUser ? 'justify-end' : 'justify-start'"
    :style="{ animationDelay: `${index * 30}ms` }"
  >
    <div class="relative max-w-[85%] md:max-w-[75%]">
      <!-- Action buttons (hover on desktop, always visible on touch) -->
      <div
        v-if="!isEditing"
        class="absolute -top-3 opacity-0 group-hover/msg:opacity-100 transition-opacity duration-200 z-10 flex gap-1"
        :class="isUser ? 'right-1' : 'left-1'"
      >
        <button
          v-if="isUser"
          class="glass-button-sm !h-7 !min-h-0 !w-7 !min-w-0 !px-0 flex items-center justify-center text-white/60 hover:text-white/90"
          title="Edit message"
          @click.stop="startEditing"
        >
          <svg xmlns="http://www.w3.org/2000/svg" class="w-3.5 h-3.5" viewBox="0 0 20 20" fill="currentColor"><path d="M13.586 3.586a2 2 0 112.828 2.828l-.793.793-2.828-2.828.793-.793zM11.379 5.793L3 14.172V17h2.828l8.38-8.379-2.83-2.828z" /></svg>
        </button>
        <button
          v-if="!isUser"
          class="glass-button-sm !h-7 !min-h-0 !w-7 !min-w-0 !px-0 flex items-center justify-center text-white/60 hover:text-white/90"
          title="Regenerate response"
          @click.stop="$emit('regenerate')"
        >
          <svg xmlns="http://www.w3.org/2000/svg" class="w-3.5 h-3.5" viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M4 2a1 1 0 011 1v2.101a7.002 7.002 0 0111.601 2.566 1 1 0 11-1.885.666A5.002 5.002 0 005.999 7H9a1 1 0 010 2H4a1 1 0 01-1-1V3a1 1 0 011-1zm.008 9.057a1 1 0 011.276.61A5.002 5.002 0 0014.001 13H11a1 1 0 110-2h5a1 1 0 011 1v5a1 1 0 11-2 0v-2.101a7.002 7.002 0 01-11.601-2.566 1 1 0 01.61-1.276z" clip-rule="evenodd" /></svg>
        </button>
      </div>

      <div
        class="rounded-2xl px-4 py-3 transition-all duration-300"
        :class="[bubbleClasses, { 'cursor-pointer': hasContext }]"
        @click="handleBubbleClick"
      >
        <!-- Edit mode -->
        <div v-if="isEditing" class="space-y-2" @click.stop>
          <textarea
            ref="editTextareaRef"
            v-model="editContent"
            class="w-full bg-white/5 border border-white/10 rounded-lg px-3 py-2 text-sm text-white/90 resize-none focus:outline-none focus:border-accent/50"
            rows="3"
            @keydown.enter.exact="submitEdit"
            @keydown.escape="cancelEdit"
          />
          <div class="flex gap-2 justify-end">
            <button
              class="glass-button-sm !h-7 !min-h-0 text-xs text-white/60 hover:text-white/90 px-3"
              @click="cancelEdit"
            >Cancel</button>
            <button
              class="glass-button-sm !h-7 !min-h-0 text-xs bg-accent/20 text-accent hover:bg-accent/30 px-3"
              @click="submitEdit"
            >Save & Resend</button>
          </div>
        </div>

        <!-- Normal display -->
        <template v-else>
          <div
            v-if="!isUser"
            class="chat-markdown text-sm leading-relaxed break-words text-white/90"
            v-html="renderedMarkdown"
          />
          <p
            v-else
            class="text-sm leading-relaxed whitespace-pre-wrap break-words text-white/90"
          >{{ displayText }}</p>
        </template>

      <div v-if="inlineFilms.length > 0" class="mt-3 space-y-1" @click.stop>
        <FilmCard
          v-for="film in inlineFilms"
          :key="film.id"
          :film="film"
          @select="handleFilmSelect"
        />
      </div>

      <div v-if="inlineBooks.length > 0" class="mt-3 space-y-1" @click.stop>
        <BookCard
          v-for="book in inlineBooks"
          :key="book.id"
          :book="book"
          @select="handleBookSelect"
        />
      </div>

      <div v-if="inlineTVSeries.length > 0" class="mt-3 space-y-1" @click.stop>
        <TVSeriesCard
          v-for="series in inlineTVSeries"
          :key="series.id"
          :series="series"
          @select="handleTVSeriesSelect"
        />
      </div>

      <div v-if="inlineSongs.length > 0" class="mt-3 space-y-1" @click.stop>
        <SongCard
          v-for="song in inlineSongs"
          :key="song.id"
          :song="song"
          @select="handleSongSelect"
        />
      </div>

      <div v-if="inlinePodcasts.length > 0" class="mt-3 space-y-1" @click.stop>
        <PodcastCard
          v-for="podcast in inlinePodcasts"
          :key="podcast.id"
          :podcast="podcast"
          @select="handlePodcastSelect"
        />
      </div>

      <div v-if="inlinePlaces.length > 0" class="mt-3 space-y-1" @click.stop>
        <PlaceCard
          v-for="place in inlinePlaces"
          :key="place.id"
          :place="place"
          @select="handlePlaceSelect"
        />
      </div>

      <div v-if="nostrUris.length > 0" class="mt-3 space-y-1.5" @click.stop>
        <NostrEmbed
          v-for="uri in nostrUris"
          :key="uri"
          :uri="uri"
        />
      </div>

      <div v-if="cashuTokens.length > 0" class="mt-3 space-y-1.5" @click.stop>
        <CashuToken
          v-for="token in cashuTokens"
          :key="token"
          :token="token"
        />
      </div>

      <div v-if="inlineNewsLinks.length > 0" class="mt-3 space-y-1" @click.stop>
        <NewsCard
          v-for="(link, i) in inlineNewsLinks"
          :key="i"
          :article="link"
          @select-article="handleArticleSelect"
        />
      </div>

      <div v-if="inlineWebsitesLinks.length > 0" class="mt-3 space-y-1" @click.stop>
        <NewsCard
          v-for="(link, i) in inlineWebsitesLinks"
          :key="`web-${i}`"
          :article="link"
          @select-article="handleWebsiteSelect"
        />
      </div>

      <div v-if="!isEditing" class="flex items-center gap-2 mt-1.5">
        <span class="text-[10px] select-none text-white/30">{{ formattedTime }}</span>
        <span v-if="message.editedAt" class="text-[10px] text-white/25 select-none">(edited)</span>
        <button
          v-if="inlineFilms.length > 1"
          class="text-[10px] text-accent/70 hover:text-accent transition-colors"
          @click.stop="openPanel"
        >
          View all {{ inlineFilms.length }} films →
        </button>
        <button
          v-else-if="inlineBooks.length > 1"
          class="text-[10px] text-accent/70 hover:text-accent transition-colors"
          @click.stop="openPanel"
        >
          View all {{ inlineBooks.length }} books →
        </button>
        <button
          v-else-if="inlineTVSeries.length > 1"
          class="text-[10px] text-accent/70 hover:text-accent transition-colors"
          @click.stop="openPanel"
        >
          View all {{ inlineTVSeries.length }} series →
        </button>
        <button
          v-else-if="inlineImages.length > 1"
          class="text-[10px] text-accent/70 hover:text-accent transition-colors"
          @click.stop="openPanel"
        >
          View all {{ inlineImages.length }} images →
        </button>
        <button
          v-else-if="inlinePlaces.length > 1"
          class="text-[10px] text-accent/70 hover:text-accent transition-colors"
          @click.stop="openPanel"
        >
          View all {{ inlinePlaces.length }} places →
        </button>
        <button
          v-else-if="inlineSongs.length > 1"
          class="text-[10px] text-accent/70 hover:text-accent transition-colors"
          @click.stop="openPanel"
        >
          View all {{ inlineSongs.length }} songs →
        </button>
        <button
          v-else-if="inlinePodcasts.length > 1"
          class="text-[10px] text-accent/70 hover:text-accent transition-colors"
          @click.stop="openPanel"
        >
          View all {{ inlinePodcasts.length }} podcasts →
        </button>
        <button
          v-else-if="inlineNewsLinks.length > 1"
          class="text-[10px] text-accent/70 hover:text-accent transition-colors"
          @click.stop="openPanel"
        >
          View all {{ inlineNewsLinks.length }} articles →
        </button>
        <button
          v-else-if="inlineWebsitesLinks.length > 1"
          class="text-[10px] text-accent/70 hover:text-accent transition-colors"
          @click.stop="openPanel"
        >
          View all {{ inlineWebsitesLinks.length }} websites →
        </button>
        <button
          v-else-if="inlineMagazineSections.length > 0"
          class="text-[10px] text-accent/70 hover:text-accent transition-colors"
          @click.stop="openPanel"
        >
          View brief →
        </button>
      </div>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { computed, ref, nextTick } from 'vue'
import MarkdownIt from 'markdown-it'
import type { Message, WebSearchResult } from '@aiui/core/types/message'
import type { Film, Song, Podcast, Book, TVSeries, ImageItem, Place } from '@aiui/core/types/content'
import { useTheme } from '@/composables/useTheme'
import { useContentPanel, type MagazineSection } from '@/composables/useContentPanel'
import { useCodeContext } from '@/composables/useCodeContext'
import FilmCard from '@/components/content/FilmCard.vue'
import BookCard from '@/components/content/BookCard.vue'
import TVSeriesCard from '@/components/content/TVSeriesCard.vue'
import SongCard from '@/components/content/SongCard.vue'
import PodcastCard from '@/components/content/PodcastCard.vue'
import PlaceCard from '@/components/content/PlaceCard.vue'
import NewsCard from '@/components/content/NewsCard.vue'
import NostrEmbed from '@/components/chat/NostrEmbed.vue'
import CashuToken from '@/components/chat/CashuToken.vue'
import { extractCashuTokens } from '@/utils/cashu'

const props = withDefaults(
  defineProps<{
    message: Message
    index: number
    triggeringQuery?: string
  }>(),
  { triggeringQuery: '' }
)

const emit = defineEmits<{
  edit: [messageId: string, newContent: string]
  regenerate: []
}>()

const { isDark } = useTheme()

// Editing state
const isEditing = ref(false)
const editContent = ref('')
const editTextareaRef = ref<HTMLTextAreaElement | null>(null)

function startEditing() {
  editContent.value = props.message.content
  isEditing.value = true
  nextTick(() => {
    editTextareaRef.value?.focus()
    // Auto-size textarea
    if (editTextareaRef.value) {
      editTextareaRef.value.style.height = 'auto'
      editTextareaRef.value.style.height = editTextareaRef.value.scrollHeight + 'px'
    }
  })
}

function cancelEdit() {
  isEditing.value = false
  editContent.value = ''
}

function submitEdit() {
  const trimmed = editContent.value.trim()
  if (!trimmed) return
  emit('edit', props.message.id, trimmed)
  isEditing.value = false
  editContent.value = ''
}
const { getContextualInlineContent, stripContentTags, stripMarkdownLinks, updatePanelFromText, panelOpen, availableTabs, setActiveTab, openFilmDetail, openBookDetail, openTVSeriesDetail, openImageDetail, openPlaceDetail, openSongDetail, openPodcastDetail, openArticleDetail, openWebsiteDetail, closeFilmDetail, closeBookDetail, closeTVSeriesDetail, closeImageDetail, closePlaceDetail, closeSongDetail, closePodcastDetail } = useContentPanel()
const codeContext = useCodeContext()

const isUser = computed(() => props.message.role === 'user')

const inlineContent = computed(() => {
  if (isUser.value) return { films: [] as Film[], books: [] as Book[], tvSeries: [] as TVSeries[], images: [] as ImageItem[], places: [] as Place[], songs: [] as Song[], podcasts: [] as Podcast[], newsLinks: [] as WebSearchResult[], websitesLinks: [] as WebSearchResult[], magazineSections: [] as MagazineSection[] }
  return getContextualInlineContent(props.message.content, props.triggeringQuery, props.message.webResults ?? [])
})

const bubbleClasses = computed(() =>
  isUser.value
    ? 'path-glass-bubble-user rounded-br-md rounded-2xl'
    : 'path-glass-bubble rounded-bl-md rounded-2xl'
)

const inlineFilms = computed(() => inlineContent.value.films)
const inlineBooks = computed(() => inlineContent.value.books ?? [])
const inlineTVSeries = computed(() => inlineContent.value.tvSeries ?? [])
const inlineImages = computed(() => inlineContent.value.images ?? [])
const inlinePlaces = computed(() => inlineContent.value.places ?? [])
const inlineSongs = computed(() => inlineContent.value.songs)
const inlinePodcasts = computed(() => inlineContent.value.podcasts)
const inlineNewsLinks = computed(() => inlineContent.value.newsLinks ?? [])
const inlineWebsitesLinks = computed(() => inlineContent.value.websitesLinks ?? [])
const inlineMagazineSections = computed(() => inlineContent.value.magazineSections ?? [])

const NOSTR_URI_RE = /nostr:(note1[a-z0-9]{58}|npub1[a-z0-9]{58}|nevent1[a-z0-9]+|nprofile1[a-z0-9]+)/g
const nostrUris = computed(() => {
  if (isUser.value) return []
  const matches = props.message.content.match(NOSTR_URI_RE)
  return matches ? [...new Set(matches)] : []
})

const cashuTokens = computed(() => {
  if (isUser.value) return []
  return extractCashuTokens(props.message.content)
})

const isCodeResponse = computed(() =>
  !isUser.value && props.triggeringQuery.trim().toLowerCase() === '/code'
)

const hasContext = computed(() => !isUser.value && (
  isCodeResponse.value ||
  inlineFilms.value.length > 0 ||
  inlineBooks.value.length > 0 ||
  inlineTVSeries.value.length > 0 ||
  inlineImages.value.length > 0 ||
  inlineSongs.value.length > 0 ||
  inlinePodcasts.value.length > 0 ||
  inlineNewsLinks.value.length > 0 ||
  inlineWebsitesLinks.value.length > 0 ||
  inlineMagazineSections.value.length > 0
))

const md = new MarkdownIt({
  html: false,
  linkify: true,
  breaks: true,
})

// Open links in new tab
const defaultRender = md.renderer.rules.link_open || function (tokens, idx, options, _env, self) {
  return self.renderToken(tokens, idx, options)
}
md.renderer.rules.link_open = function (tokens, idx, options, env, self) {
  tokens[idx].attrSet('target', '_blank')
  tokens[idx].attrSet('rel', 'noopener noreferrer')
  return defaultRender(tokens, idx, options, env, self)
}

const displayText = computed(() => {
  if (isUser.value) return props.message.content
  let text = stripContentTags(props.message.content)
  if (inlineNewsLinks.value.length > 0 || inlineWebsitesLinks.value.length > 0) text = stripMarkdownLinks(text)
  if (nostrUris.value.length > 0) text = text.replace(NOSTR_URI_RE, '').replace(/\n{3,}/g, '\n\n').trim()
  if (cashuTokens.value.length > 0) {
    for (const token of cashuTokens.value) {
      text = text.replace(token, '')
    }
    text = text.replace(/\n{3,}/g, '\n\n').trim()
  }
  return text
})

const renderedMarkdown = computed(() => {
  return md.render(displayText.value)
})

const formattedTime = computed(() => {
  const d = new Date(props.message.timestamp)
  return d.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })
})

function openPanelWithContext() {
  updatePanelFromText(props.message.content, props.triggeringQuery, props.message.webResults ?? [])
}

function handleFilmSelect(film: Film) {
  openPanelWithContext()
  closeSongDetail()
  closePodcastDetail()
  openFilmDetail(film)
}

function handleBookSelect(book: Book) {
  openPanelWithContext()
  closeFilmDetail()
  closeTVSeriesDetail()
  closeSongDetail()
  closePodcastDetail()
  openBookDetail(book)
}

function handleTVSeriesSelect(series: TVSeries) {
  openPanelWithContext()
  closeFilmDetail()
  closeBookDetail()
  closeSongDetail()
  closePodcastDetail()
  openTVSeriesDetail(series)
}

function handleSongSelect(song: Song) {
  openPanelWithContext()
  closeFilmDetail()
  closeBookDetail()
  closePodcastDetail()
  openSongDetail(song)
}

function handlePlaceSelect(place: Place) {
  openPanelWithContext()
  closeFilmDetail()
  closeBookDetail()
  closePlaceDetail()
  openPlaceDetail(place)
}

function handlePodcastSelect(podcast: Podcast) {
  openPanelWithContext()
  closeFilmDetail()
  closeSongDetail()
  openPodcastDetail(podcast)
}

function openPanel() {
  closeFilmDetail()
  closeBookDetail()
  closeTVSeriesDetail()
  closeSongDetail()
  closePodcastDetail()
  openPanelWithContext()
}

function handleArticleSelect(article: WebSearchResult) {
  openPanelWithContext()
  openArticleDetail(article)
}

function handleWebsiteSelect(article: WebSearchResult) {
  openPanelWithContext()
  openWebsiteDetail(article)
}

function activateCodeMode() {
  codeContext.enterCodeMode()
  panelOpen.value = true
  if (!availableTabs.value.includes('code')) {
    availableTabs.value = [...availableTabs.value, 'code']
  }
  setActiveTab('code')
}

function handleBubbleClick() {
  if (isCodeResponse.value) {
    activateCodeMode()
    return
  }
  if (hasContext.value) openPanel()
}
</script>
