import { defineStore } from 'pinia'
import { ref, watch } from 'vue'
import * as api from '../api/client.js'
import { useAuthStore } from './auth.js'

/**
 * uploadToMinIO — XHR PUT helper for presigned MinIO uploads.
 *
 * Security: NO Authorization header is set — the presigned URL is self-authenticating (T-03-22).
 * Progress events are mapped to onProgress(0–100) for the XHR PUT phase.
 */
function uploadToMinIO(url, file, onProgress) {
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest()
    xhr.upload.addEventListener('progress', (e) => {
      if (e.lengthComputable) onProgress(Math.round((e.loaded / e.total) * 100))
    })
    xhr.addEventListener('load', () => {
      if (xhr.status < 400) resolve()
      else reject(new Error(`PUT failed: ${xhr.status}`))
    })
    xhr.addEventListener('error', () => reject(new Error('Network error during upload')))
    xhr.open('PUT', url)
    xhr.setRequestHeader('Content-Type', file.type || 'application/octet-stream')
    // NOTE: no Authorization header — presigned URL is self-authenticating (T-03-22, CLAUDE.md)
    xhr.send(file)
  })
}

export const useDocumentsStore = defineStore('documents', () => {
  const documents = ref([])
  const total = ref(0)
  const loading = ref(false)
  const error = ref(null)
  // uploadProgress: keyed by "${file.name}__${Date.now()}" to prevent collision (T-03-25)
  const uploadProgress = ref({})
  const currentFolderId = ref(null)
  const searchQuery = ref('')
  const sortField = ref('date')
  const sortOrder = ref('desc')

  async function fetchDocuments({ topic, page = 1, perPage = 20, folderId = null, q = null, sort = null, order = null } = {}) {
    loading.value = true
    error.value = null
    try {
      const data = await api.listDocuments({ topic, page, perPage, folderId, q, sort, order })
      documents.value = data.items
      total.value = data.total
    } catch (e) {
      error.value = e.message
    } finally {
      loading.value = false
    }
  }

  /**
   * Three-step upload with optional folder placement:
   *   Step 1: POST /api/documents/upload-url → {upload_url, document_id} (0% → 5%)
   *   Step 2: XHR PUT bytes directly to MinIO presigned URL (5% → 90%)
   *   Step 3: POST /api/documents/{id}/confirm → {id, size_bytes, used_bytes, status} (92% → 96%)
   *   Step 3b: PATCH /api/documents/{id}/folder if folderId is non-null (96% → 100%)
   *
   * On 413 quota exceeded: err.payload = {used_bytes, limit_bytes, rejected_bytes} from confirm step.
   * On success: authStore.fetchQuota() is called to refresh sidebar quota bar (STORE-04).
   * Returns { rowKey, doc } on success so callers can clear the progress entry.
   */
  async function upload(file, autoClassify = true, folderId = null) {
    const authStore = useAuthStore()
    // Composite key prevents collision when same filename uploaded twice (T-03-25)
    const rowKey = `${file.name}__${Date.now()}`
    uploadProgress.value[rowKey] = 0
    try {
      // Step 1: get presigned PUT URL (UI-SPEC: 0% → 5%, status "Preparing upload…")
      const { upload_url, document_id } = await api.getUploadUrl(
        file.name,
        file.type || 'application/octet-stream',
      )
      uploadProgress.value[rowKey] = 5

      // Step 2: XHR PUT to MinIO (UI-SPEC: 5% → 90%, status "Uploading…")
      await uploadToMinIO(upload_url, file, (pct) => {
        // Map XHR progress 0–100 into visual range 5–90
        uploadProgress.value[rowKey] = 5 + Math.round(pct * 0.85)
      })
      uploadProgress.value[rowKey] = 92

      // Step 3: confirm (UI-SPEC: 92% → 96%, status "Processing…" → "Done — classifying…")
      const doc = await api.confirmUpload(document_id)
      uploadProgress.value[rowKey] = 96

      // Step 3b: move to target folder if the upload was initiated inside a folder
      if (folderId != null) {
        await api.moveDocument(doc.id, folderId)
      }
      uploadProgress.value[rowKey] = 100

      documents.value.unshift({
        id: doc.id,
        original_name: file.name,
        filename: file.name,
        mime_type: file.type,
        size_bytes: doc.size_bytes,
        topics: [],
        folder_id: folderId,
        created_at: new Date().toISOString(),
        classified_at: null,
      })
      total.value++

      // Refresh quota after successful upload (STORE-04, UI-SPEC Data Source)
      await authStore.fetchQuota()

      return { rowKey, doc }
    } catch (e) {
      error.value = e.message
      // Propagate rowKey so the DropZone/parent can target the correct progress row
      throw Object.assign(e, { rowKey })
    }
    // NOTE: uploadProgress[rowKey] is intentionally left in place after throw/return —
    // the parent component reads it to render the bar or quota error block; the parent
    // is responsible for clearing the entry when the row is dismissed.
  }

  async function remove(id) {
    const authStore = useAuthStore()
    await api.deleteDocument(id)
    documents.value = documents.value.filter(d => d.id !== id)
    total.value--
    // Refresh quota after document delete (STORE-06, UI-SPEC Data Source)
    await authStore.fetchQuota()
  }

  async function reclassify(id, topics = null) {
    const result = await api.classifyDocument(id, topics)
    const idx = documents.value.findIndex(d => d.id === id)
    if (idx !== -1) documents.value[idx].topics = result.topics
    return result.topics
  }

  // Debounced search watcher: fires after 300 ms; ignores inputs shorter than 2 chars (T-04-08-03)
  let _searchTimer = null
  watch(searchQuery, (newVal) => {
    clearTimeout(_searchTimer)
    if (newVal.length < 2) {
      fetchDocuments({ folderId: currentFolderId.value })
      return
    }
    _searchTimer = setTimeout(() => {
      fetchDocuments({ q: newVal, folderId: currentFolderId.value, sort: sortField.value, order: sortOrder.value })
    }, 300)
  })

  async function moveToFolder(docId, folderId) {
    await api.moveDocument(docId, folderId)
    documents.value = documents.value.filter(d => d.id !== docId)
    total.value = Math.max(0, total.value - 1)
  }

  async function shareDocument(docId, recipientHandle, permission = 'view') {
    const result = await api.createShare(docId, recipientHandle, permission)
    const doc = documents.value.find(d => d.id === docId)
    if (doc) doc.is_shared = true
    return result
  }

  async function revokeShare(shareId) {
    try { await api.deleteShare(shareId) } catch (e) { throw e }
  }

  async function listShares(docId) {
    try { return await api.listShares(docId) } catch (e) { throw e }
  }

  async function updateSharePermission(shareId, permission) {
    try { return await api.updateSharePermission(shareId, permission) } catch (e) { throw e }
  }

  return { documents, total, loading, error, uploadProgress, currentFolderId, searchQuery, sortField, sortOrder, fetchDocuments, upload, remove, reclassify, moveToFolder, shareDocument, revokeShare, listShares, updateSharePermission }
})
