<script lang="ts">
  import Code from './Code.svelte'
  import { createEventDispatcher, onMount } from 'svelte'
  import { deleteMessage, chatsStorage, deleteSummaryMessage, truncateFromMessage, submitExitingPromptsNow } from './Storage.svelte'
  import { getPrice } from './Stats.svelte'
  import SvelteMarkdown from 'svelte-markdown'
  import type { Message, Model, Chat } from './Types.svelte'
  import Fa from 'svelte-fa/src/fa.svelte'
  import { faTrash, faDiagramPredecessor, faDiagramNext, faCircleCheck, faPaperPlane } from '@fortawesome/free-solid-svg-icons/index'
  import { scrollIntoViewWithOffset } from './Util.svelte'

  export let message:Message
  export let chatId:number


  $: chat = $chatsStorage.find((chat) => chat.id === chatId) as Chat
  $: chatSettings = chat.settings

  // Marked options
  const markdownOptions = {
    gfm: true, // Use GitHub Flavored Markdown
    breaks: true, // Enable line breaks in markdown
    mangle: false // Do not mangle email addresses
  }

  const dispatch = createEventDispatcher()
  let editing = false
  let original:string
  let defaultModel:Model
  let noEdit:boolean

  onMount(() => {
    original = message.content
    defaultModel = chatSettings.model as any
    noEdit = !!message.summarized
  })

  const edit = () => {
    if (noEdit) return
    editing = true
    setTimeout(() => {
      const el = document.getElementById('edit-' + message.uuid)
      el && el.focus()
    }, 0)
  }

  let dbnc
  const update = () => {
    clearTimeout(dbnc)
    dbnc = setTimeout(() => { doChange() }, 250)
  }

  const doChange = () => {
    if (message.content !== original) {
      dispatch('change', message)
    }
  }

  const exit = () => {
    doChange()
    editing = false
  }

  const keydown = (event:KeyboardEvent) => {
    if (event.key === 'Escape') {
      event.preventDefault()
      message.content = original
      editing = false
    }
  }

  const scrollToMessage = (uuid:string | string[] | undefined) => {
    if (Array.isArray(uuid)) {
      uuid = uuid[0]
    }
    if (!uuid) {
      console.error('Not a valid uuid', uuid)
      return
    }
    const el = document.getElementById('message-' + uuid)
    if (el) {
      scrollIntoViewWithOffset(el, 80)
    } else {
      console.error("Can't find element with message ID", uuid)
    }
  }

  // Double click for mobile support
  let lastTap: number = 0
  const editOnDoubleTap = () => {
    const now: number = new Date().getTime()
    const timesince: number = now - lastTap
    if ((timesince < 400) && (timesince > 0)) {
      edit()
    }
    lastTap = new Date().getTime()
  }

  let waitingForDeleteConfirm:any = 0

  const checkDelete = () => {
    clearTimeout(waitingForTruncateConfirm); waitingForTruncateConfirm = 0
    if (!waitingForDeleteConfirm) {
      // wait a second for another click to avoid accidental deletes
      waitingForDeleteConfirm = setTimeout(() => { waitingForDeleteConfirm = 0 }, 1000)
      return
    }
    clearTimeout(waitingForDeleteConfirm)
    waitingForDeleteConfirm = 0
    if (message.summarized) {
      // is in a summary, so we're summarized
      window.alert('Sorry, you can\'t delete a summarized message')
      return
    }
    if (message.summary) {
      // We're linked to messages we're a summary of
      if (window.confirm('Are you sure you want to delete this summary?\nYour session may be too long to submit again after you do.')) {
        try {
          deleteSummaryMessage(chatId, message.uuid)
        } catch (e) {
          window.alert('Unable to delete summary:\n' + e.message)
        }
      }
      return
    }
    try {
      deleteMessage(chatId, message.uuid)
    } catch (e) {
      window.alert('Unable to delete:\n' + e.message)
    }
  }


  let waitingForTruncateConfirm:any = 0

  const checkTruncate = () => {
    clearTimeout(waitingForDeleteConfirm); waitingForDeleteConfirm = 0
    if (!waitingForTruncateConfirm) {
      // wait a second for another click to avoid accidental deletes
      waitingForTruncateConfirm = setTimeout(() => { waitingForTruncateConfirm = 0 }, 1000)
      return
    }
    clearTimeout(waitingForTruncateConfirm)
    waitingForTruncateConfirm = 0
    if (message.summarized) {
      // is in a summary, so we're summarized
      window.alert('Sorry, you can\'t truncate a summarized message')
      return
    }
    try {
      truncateFromMessage(chatId, message.uuid)
      $submitExitingPromptsNow = true
    } catch (e) {
      window.alert('Unable to delete:\n' + e.message)
    }
  }

</script>

{#key message.uuid}
<article
  id="{'message-' + message.uuid}"
  class="message chat-message" 
  class:is-info={message.role === 'user'}
  class:is-success={message.role === 'assistant'}
  class:is-warning={message.role === 'system'}
  class:is-danger={message.role === 'error'}
  class:user-message={message.role === 'user' || message.role === 'system'}
  class:assistant-message={message.role === 'error' || message.role === 'assistant'}
  class:summarized={message.summarized} 
  class:editing={editing}
>
  <div class="message-body content">
 
    {#if editing && !noEdit}
      <form class="message-edit" on:submit|preventDefault={update} on:keydown={keydown}>
        <div id={'edit-' + message.uuid} class="message-editor" bind:innerText={message.content} contenteditable
        on:input={update} on:blur={exit} />
      </form>
    {:else}
      <div 
        class="message-display" 
         
        on:touchend={editOnDoubleTap}
          on:dblclick|preventDefault={() => edit()}
        >
        <SvelteMarkdown 
          source={message.content} 
          options={markdownOptions} 
          renderers={{ code: Code, html: Code }}
        />
    </div>
    {/if}
    {#if message.role === 'system'}
      <p class="is-size-7 message-note">System Prompt</p>
    {:else if message.usage}
      <p class="is-size-7 message-note">
        <em>{message.model || defaultModel}</em> using <span class="has-text-weight-bold">{message.usage.total_tokens}</span>
        tokens ~= <span class="has-text-weight-bold">${getPrice(message.usage, message.model || defaultModel).toFixed(6)}</span>
      </p>
    {/if}
  </div>
  <div class="tool-drawer-mask"></div>
  <div class="tool-drawer">
    <div class="button-pack">
      {#if message.summarized}
      <a
        href={'#'}
        title="Jump to summary"
        class="msg-summary-button button is-small is-info"
        on:click|preventDefault={() => {
          scrollToMessage(message.summarized)
        }}
      >
      <span class="icon"><Fa icon={faDiagramNext} /></span>
      </a>
      {/if}
      {#if message.summary}
      <a
        href={'#'}
        title="Jump to summarized"
        class="msg-summarized-button button is-small is-info"
        on:click|preventDefault={() => {
          scrollToMessage(message.summary)
        }}
      >
      <span class="icon"><Fa icon={faDiagramPredecessor} /></span>
      </a>
      {/if}
      {#if !message.summarized}
      <a
        href={'#'}
        title="Delete this message"
        class=" msg-delete-button button is-small is-warning"
        on:click|preventDefault={() => {
          checkDelete()
        }}
      >
      {#if waitingForDeleteConfirm}
      <span class="icon"><Fa icon={faCircleCheck} /></span>
      {:else}
      <span class="icon"><Fa icon={faTrash} /></span>
      {/if}
      </a>
      {/if}
      {#if !message.summarized}
      <a
        href={'#'}
        title="Truncate all and submit"
        class=" msg-delete-button button is-small is-danger"
        on:click|preventDefault={() => {
          checkTruncate()
        }}
      >
      {#if waitingForTruncateConfirm}
      <span class="icon"><Fa icon={faCircleCheck} /></span>
      {:else}
      <span class="icon"><Fa icon={faPaperPlane} /></span>
      {/if}
      </a>
      {/if}
      </div>

  </div>
</article>
{/key}

