<template>
  <div class="comment-attachment column full-width shadow-1 q-pa-sm  bg-white" :data-id="id">
    <div>{{ title || label }}</div>
    <div class="row col q-px-md">
    <q-input
      class="full-width"
      type="textarea"
      v-model="comments"
      @blur="onCommentsBlur"
      :label="t('commenti')"
      autogrow
      dense
    />
</div>

    <div class="row q-ml-md full-width items-center no-wrap">
      <div class="col q-ml-md">
        <q-file
          ref="fileRef"
          :model-value="files"
          @update:model-value="updateFiles"
          accept=".pdf,.docx,.txt,.md"
          dense
          borderless
          hide-bottom-space
          :clearable="false"
          input-style="display: none"
          style="max-width: 400px"
        >
          <template v-slot:prepend>
            <div class="row items-center no-wrap full-width">
              <template v-if="!files">
                <q-btn
                  round
                  dense
                  flat
                  color="primary"
                  icon="attach_file"
                  :disable="isUploading"
                  @click.stop="fileRef?.pickFiles()"
                >
                  <q-tooltip>{{ t('pickFiles') }}</q-tooltip>
                </q-btn>
              </template>

              <template v-else>
                <q-btn
                  round
                  dense
                  flat
                  color="primary"
                  icon="cloud_upload"
                  :disable="!canUpload || isUploading"
                  :loading="isUploading"
                  @click.stop="upload"
                />
                <q-btn
                  v-if="!isUploading"
                  round
                  dense
                  flat
                  color="primary"
                  icon="delete"
                  :disable="!files"
                  @click.stop.prevent="cancelSelection"
                />
              </template>

              <div class="comment-attachment__file-name q-px-sm"  v-if="fileLabel">
                {{ fileLabel }}
              </div>
            </div>
          </template>

        </q-file>
      </div>
    </div>

    <div class="row items-start q-gutter-sm q-ml-md q-mt-xs q-mb-none full-width">
      <div class="row col q-pa-none q-ma-none q-ml-md">
        <div  class="text-caption q-mb-sm q-mt-none ">
          {{ t('attachments')}}
        </div>
        <div  class="column items-center q-gutter-sm full-width">
          <q-chip class="full-width" v-for="(f, i) in local.attachments" :key="i" removable @remove="removeFile(i)">{{ f }}</q-chip>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { computed, onMounted, reactive, ref, watch } from 'vue'
import { useI18n } from 'vue-i18n'
import { useQuasar, type QFile } from 'quasar'
import { useUserstore } from '../stores/userstore'

export interface CommentAttachmentData {
  comments: string
  attachments: string[]
}

type Payload = CommentAttachmentData

const props = defineProps<{
  modelValue?: Partial<Payload> | null
  label?: string
  title?: string
  id?: string
}>()
const emit = defineEmits<{
  (e: 'update:modelValue', v: Payload | null): void
}>()

const { t } = useI18n()
const $q = useQuasar()
const userStore = useUserstore()
const fileRef = ref<QFile | null>(null)
const initialAttachments = props.modelValue?.attachments

const local = reactive<Payload>({
  comments: props.modelValue?.comments || '',
  attachments: Array.isArray(initialAttachments) ? [...initialAttachments] : [],
})

const comments = ref(local.comments)

type UploadProgressItem = {
  percent: number
  color: string
  icon: string
  xhr?: XMLHttpRequest
}

const files = ref<File | null>(null)
const isUploading = ref(false)
const uploadProgress = ref<UploadProgressItem[]>([])

const allowedExtensions = new Set(['pdf', 'docx', 'txt', 'md'])

function isAllowedFile(file: File): boolean {
  const name = (file.name || '').trim().toLowerCase()
  const ext = name.includes('.') ? name.split('.').pop() : ''
  return !!ext && allowedExtensions.has(ext)
}

const canUpload = computed(() => !!files.value)

const fileLabel = computed(() => {
  const current = files.value
  return current?.name || ''
})

// const emptyProgress: UploadProgressItem = { percent: 0, color: 'primary', icon: 'attach_file' }

function ensureProgress(index: number): UploadProgressItem {
  while (uploadProgress.value.length <= index) {
    uploadProgress.value.push({ percent: 0, color: 'primary', icon: 'attach_file' })
  }
  const item = uploadProgress.value[index]
  if (!item) {
    const fallback = { percent: 0, color: 'primary', icon: 'attach_file' } satisfies UploadProgressItem
    uploadProgress.value[index] = fallback
    return fallback
  }
  return item
}

function emitUpdated() {
  emit('update:modelValue', {
    comments: local.comments || '',
    attachments: [...local.attachments],
  })
}

function updateFiles(val: File | null) {
  if (val && !isAllowedFile(val)) {
    files.value = null
    isUploading.value = false
    uploadProgress.value = []
    return
  }

  files.value = val
  isUploading.value = false

  uploadProgress.value = val
    ? [{ percent: 0, color: 'primary', icon: 'attach_file' }]
    : []
}

function cancelFile(index: number) {
  const currentProgress = uploadProgress.value
  const progress = currentProgress[index]
  if (progress?.xhr && progress.percent < 1) {
    try {
      progress.xhr.abort()
    } catch {
      // ignore
    }
  }

  // single file selection
  files.value = null

  const nextProgress = [...currentProgress]
  nextProgress.splice(index, 1)
  uploadProgress.value = nextProgress
}

function cancelSelection() {
  cancelFile(0)
}

async function upload() {
  const file = files.value
  if (!file) return
  if (!isAllowedFile(file)) return

  isUploading.value = true

  const uploadUrl = 'http://localhost:8082/upload'
  await new Promise<void>((resolve) => {
    const xhr = new XMLHttpRequest()
    const p = ensureProgress(0)
    p.xhr = xhr

    xhr.upload.onprogress = (e) => {
      if (!e.lengthComputable) return
      const prog = e.total > 0 ? e.loaded / e.total : 0
      ensureProgress(0).percent = Math.max(0, Math.min(1, prog))
    }

    xhr.onload = () => {
      const ok = xhr.status >= 200 && xhr.status < 300
      const p = ensureProgress(0)
      p.percent = ok ? 1 : p.percent
      p.color = ok ? 'positive' : 'negative'
      p.icon = ok ? 'check' : 'error'

      if (ok) {
        try {
          const parsed = JSON.parse(xhr.responseText) as {
            files?: Array<{ storedName?: string; originalName?: string; name?: string }>
          }
          const first = Array.isArray(parsed.files) ? parsed.files[0] : undefined
          const stored = first?.storedName || first?.originalName || first?.name
          local.attachments.push(stored || file.name)
        } catch {
          local.attachments.push(file.name)
        }
        emitUpdated()
      }

      resolve()
    }

    xhr.onerror = () => {
      const p = ensureProgress(0)
      p.color = 'negative'
      p.icon = 'error'
      resolve()
    }

    xhr.onabort = () => {
      const p = ensureProgress(0)
      p.color = 'warning'
      p.icon = 'close'
      resolve()
    }

    const fd = new FormData()
    fd.append('session', props.id ?? '')
    fd.append('user', userStore.id)
    fd.append('documents', file)
    xhr.open('POST', uploadUrl)
    xhr.send(fd)
  })

  // Clear selection after upload; keep uploaded names in local.attachments
  files.value = null
  uploadProgress.value = []
  isUploading.value = false
}

watch(
  () => props.modelValue,
  (v) => {
    if (v && typeof v.comments === 'string') {
      local.comments = v.comments
    } else if (v === null) {
      local.comments = ''
    }

    // modelValue is Partial<Payload>: don't wipe local attachments if the parent omits the field
    if (v && Array.isArray(v.attachments)) {
      local.attachments = [...v.attachments]
    } else if (v === null) {
      local.attachments = []
    }

    comments.value = local.comments
  }
)

function onCommentsBlur() {
  local.comments = comments.value || ''
  emitUpdated()
}



async function confirmDeleteAttachment(filename: string): Promise<boolean> {
  return new Promise((resolve) => {
    $q.dialog({
      message: "<h6 class='q-my-sm' >" + t('confirmDeleteAttachment') + " </h6>   " + filename,
      cancel: true,
      persistent: true,
      html: true
    })
      .onOk(() => resolve(true))
      .onCancel(() => resolve(false))
      .onDismiss(() => resolve(false))
  })
}

async function removeFile(index: number) {
  const filename = local.attachments[index]
  if (!filename) return

  const confirmed = await confirmDeleteAttachment(filename)
  if (!confirmed) return

  const id = userStore.id
  const session = props.id

  // If we don't have enough context to delete on the server, just remove locally.
  if (!id || !session) {
    local.attachments.splice(index, 1)
    emitUpdated()
    return
  }

  try {
    const res = await fetch('http://localhost:8082/deleteattachment', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ id, session, filename }),
    })
    if (!res.ok) return
  } catch {
    return
  }

  local.attachments.splice(index, 1)
  emitUpdated()
}

function isStringArray(value: unknown): value is string[] {
  return Array.isArray(value) && value.every((x) => typeof x === 'string')
}

onMounted(async () => {
  // session comes from component prop id; user id comes from userstore
  const session = props.id
  const id = userStore.id
  if (!session || !id) return

  try {
    const res = await fetch('http://localhost:8082/loadattachments', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ id, session }),
    })
    if (!res.ok) return
    const files: unknown = await res.json()
    if (isStringArray(files)) {
      local.attachments = files
      emitUpdated()
    }
  } catch {
    // ignore network errors
  }
})
</script>

<style scoped>
.comment-attachment { font-size: 14px; }
.comment-attachment__file-name { font-size: 14px !important; width: 100%; background-color: rgba(0,0,0,0.1)}
.text-grey { color: rgba(0,0,0,0.45); }
</style>
