<script setup lang="ts">
import { computed, ref } from 'vue'
import { cn } from '@/lib/utils'

interface Props {
  sent: boolean
  isFirst: boolean
  isLast: boolean
  content: string
  timestamp: number
  showTimestamp?: boolean
}

const props = withDefaults(defineProps<Props>(), {
  showTimestamp: true
})

const copiedValues = ref(new Set<string>())

const bubbleClasses = computed(() => {
  return cn(
    'relative flex flex-col break-words min-w-[120px] max-w-[90%] md:max-w-[75%] text-sm shadow-sm',
    props.sent
      ? 'bg-gradient-to-br from-primary/90 via-primary/80 to-primary/70 text-primary-foreground ring-1 ring-primary/10'
      : 'bg-gradient-to-br from-muted/90 via-muted/80 to-muted/70 text-muted-foreground ring-1 ring-border/10',
    // First message in group
    props.isFirst && (props.sent ? 'rounded-t-xl rounded-l-xl' : 'rounded-t-xl rounded-r-xl'),
    // Last message in group
    props.isLast && (props.sent ? 'rounded-b-xl rounded-l-xl' : 'rounded-b-xl rounded-r-xl'),
    // Single message
    props.isFirst && props.isLast && 'rounded-xl',
    // Middle messages
    !props.isFirst && !props.isLast && (props.sent ? 'rounded-l-xl' : 'rounded-r-xl')
  )
})

const formatTime = (timestamp: number) => {
  return new Date(timestamp * 1000).toLocaleTimeString([], {
    hour: '2-digit',
    minute: '2-digit'
  })
}

// Regular expressions for detecting special content
const BITCOIN_ADDRESS_REGEX = /\b([13][a-km-zA-HJ-NP-Z1-9]{25,34}|bc1[ac-hj-np-zAC-HJ-NP-Z02-9]{11,71})\b/g
const TXID_REGEX = /\b[a-fA-F0-9]{64}\b/g
const LIGHTNING_INVOICE_REGEX = /lnbc[a-zA-Z0-9]+/g

const copyToClipboard = async (text: string) => {
  try {
    await navigator.clipboard.writeText(text)
    copiedValues.value.add(text)
    setTimeout(() => {
      copiedValues.value.delete(text)
    }, 2000)
  } catch (err) {
    console.error('Failed to copy:', err)
  }
}

const formatSpecialContent = (type: 'address' | 'txid' | 'invoice', value: string) => {
  const isCopied = copiedValues.value.has(value)
  const buttonClasses = 'inline-flex items-center gap-1 px-2 h-[22px] text-[11px] font-medium rounded bg-background/10 hover:bg-background/20 transition-colors ring-1 ring-border/5'
  
  if (type === 'txid') {
    return `<div class="font-mono text-[11px] leading-normal break-all opacity-90">${value}</div><div class="flex flex-wrap items-center gap-1.5 mt-1.5"><button data-copy="${value}" class="${buttonClasses}"><svg class="h-3 w-3 mr-0.5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">${isCopied ? '<path d="M20 6 9 17l-5-5"/>' : '<path d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2"/><path d="M15 2H9a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1Z"/>'}</svg>Copy txid</button><a href="https://mempool.space/tx/${value}" target="_blank" rel="noopener noreferrer" class="${buttonClasses}"><svg class="h-3 w-3 mr-0.5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M7 7h10v10M7 17 17 7"/></svg>mempool.space</a></div>`
  }
  
  if (type === 'address') {
    return `<div class="font-mono text-[11px] leading-normal break-all opacity-90">${value}</div><div class="flex flex-wrap items-center gap-1.5 mt-1.5"><button data-copy="${value}" class="${buttonClasses}"><svg class="h-3 w-3 mr-0.5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">${isCopied ? '<path d="M20 6 9 17l-5-5"/>' : '<path d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2"/><path d="M15 2H9a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1Z"/>'}</svg>Copy wallet</button><a href="https://mempool.space/address/${value}" target="_blank" rel="noopener noreferrer" class="${buttonClasses}"><svg class="h-3 w-3 mr-0.5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M7 7h10v10M7 17 17 7"/></svg>mempool.space</a></div>`
  }

  if (type === 'invoice') {
    return `<div class="font-mono text-[11px] leading-normal break-all opacity-90">${value}</div><div class="flex flex-wrap items-center gap-1.5 mt-1.5"><button data-copy="${value}" class="${buttonClasses}"><svg class="h-3 w-3 mr-0.5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">${isCopied ? '<path d="M20 6 9 17l-5-5"/>' : '<path d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2"/><path d="M15 2H9a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1Z"/>'}</svg>Copy invoice</button><a href="lightning:${value}" class="${buttonClasses}"><svg class="h-3 w-3 mr-0.5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m13 2-2 2.5h3L12 7"/><path d="M12 22v-3"/><path d="M12 17v-2"/><path d="M12 12V9"/></svg>Pay</a></div>`
  }

  return value
}

const formattedContent = computed(() => {
  let processedText = props.content

  // Check if the content is JSON
  try {
    const jsonContent = JSON.parse(processedText)
    if (typeof jsonContent === 'object') {
      return JSON.stringify(jsonContent, null, 2)
    }
  } catch {
    // Not JSON, continue with normal processing
  }

  // Replace Bitcoin addresses with formatted content
  processedText = processedText.replace(BITCOIN_ADDRESS_REGEX, (address) => 
    formatSpecialContent('address', address)
  )

  // Replace transaction IDs with formatted content
  processedText = processedText.replace(TXID_REGEX, (txid) => 
    formatSpecialContent('txid', txid)
  )

  // Replace Lightning invoices with formatted content
  processedText = processedText.replace(LIGHTNING_INVOICE_REGEX, (invoice) => 
    formatSpecialContent('invoice', invoice)
  )

  return processedText
})

const isJson = computed(() => {
  try {
    JSON.parse(props.content)
    return true
  } catch {
    return false
  }
})

const handleClick = async (event: MouseEvent) => {
  const target = event.target as HTMLElement
  const copyButton = target.closest('button[data-copy]')
  if (copyButton) {
    const textToCopy = copyButton.getAttribute('data-copy')
    if (textToCopy) {
      await copyToClipboard(textToCopy)
    }
  }
}
</script>

<template>
  <div :class="bubbleClasses" @click="handleClick">
    <div class="px-3 py-2 break-words whitespace-pre-wrap">
      <span v-if="isJson" class="font-mono text-[11px]">
        <pre class="select-text p-2 rounded bg-background/10">{{ JSON.stringify(JSON.parse(content), null, 2) }}</pre>
      </span>
      <span v-else class="select-text text-[13px] leading-relaxed" v-html="formattedContent"></span>
    </div>
    <span v-if="showTimestamp && isLast" 
      class="text-[10px] px-3 pb-1 select-none opacity-70"
      :class="{ 'self-end': sent }">
      {{ formatTime(timestamp) }}
    </span>
  </div>
</template>

<style scoped>
.break-words {
  word-break: break-word;
  overflow-wrap: break-word;
  hyphens: auto;
}

.select-text {
  user-select: text;
  -webkit-user-select: text;
}

.select-none {
  user-select: none;
  -webkit-user-select: none;
}

:deep(a) {
  transition: all 0.2s ease-in-out;
}

:deep(pre) {
  margin: 0;
  font-size: 11px;
  line-height: 1.4;
}

:deep(button) {
  cursor: pointer;
  outline: none;
}

:deep(button:focus-visible),
:deep(a:focus-visible) {
  outline: 2px solid currentColor;
  outline-offset: 2px;
}

/* Special content container styles */
:deep(.special-content) {
  margin: 0.5rem 0;
  border-radius: 0.5rem;
  overflow: hidden;
}
</style> 