import { reactive, ref, computed } from 'vue'
import { Notify } from 'quasar'
import { createDoc, listDocs } from 'src/api/erp'
import { createJob, fetchTags, createTag, updateTag, renameTag, deleteTag } from 'src/api/dispatch'

import { HUB_URL } from 'src/config/hub'

/**
 * Composable for unified ticket/task/work-order creation.
 *
 * @param {import('vue').Ref<string>} mode - 'ticket' | 'task' | 'work-order'
 * @param {Object} opts - Optional: { technicians, allTags, getTagColor }
 */
function nextWeekday () {
  const d = new Date()
  const day = d.getDay()
  if (day === 6) d.setDate(d.getDate() + 2) // Sat → Mon
  else if (day === 0) d.setDate(d.getDate() + 1) // Sun → Mon
  return d.toISOString().slice(0, 10)
}

// Numéro de job standardisé YYYYMMDD-XXX, frappé côté hub (compteur par jour). Repli local si le hub ne répond pas.
async function fetchNextRef () {
  try {
    const r = await fetch(`${HUB_URL}/dispatch/next-ref`)
    if (r.ok) { const d = await r.json(); if (d && d.ref) return d.ref }
  } catch (e) { /* repli ci-dessous */ }
  return 'DJ-' + Date.now().toString(36).toUpperCase()
}

export function useUnifiedCreate (mode, opts = {}) {
  // ── Form state ────────────────────────────────────────────────────────────
  const form = reactive({
    subject: '',
    priority: 'medium',
    description: '',
    issue_type: null,
    service_location: null,
    job_type: 'Autre',
    duration_h: 1,
    address: '',
    assigned_tech: null,
    scheduled_date: '',
    start_time: '',       // heure du créneau (réservation « Trouver un créneau ») — optionnel
    depends_on: null,     // parent dependency (ticket/task/job name)
    tags: [],             // [{ tag, level?, required? }] or ['label', ...]
    _latitude: null,
    _longitude: null,
    _customer: '',
    _source_issue: '',
    _subscription: '',
  })

  const submitting = ref(false)

  // ── Field visibility by mode ──────────────────────────────────────────────
  const fields = computed(() => {
    const m = typeof mode === 'string' ? mode : mode.value
    return {
      showIssueType:       m === 'ticket',
      showServiceLocation: m === 'ticket',
      showJobType:         m === 'work-order',
      showAddress:         m === 'work-order',
      showDuration:        m === 'work-order' || m === 'task',
      showTags:            m === 'work-order' || m === 'task',
      showTech:            m === 'work-order',
      showScheduledDate:   m === 'work-order' || m === 'task',
      showParent:          true,
    }
  })

  // ── Tags (standalone mode — used when not injected from dispatch) ─────────
  const internalTags = ref([])
  const tagsLoaded = ref(false)

  async function loadTags () {
    if (tagsLoaded.value) return
    try {
      internalTags.value = await fetchTags()
      tagsLoaded.value = true
    } catch { /* tags optional */ }
  }

  function allTags () {
    return opts.allTags?.value || opts.allTags || internalTags.value
  }

  function getTagColor (label) {
    if (opts.getTagColor) return opts.getTagColor(label)
    const t = allTags().find(t => t.label === label || t.name === label)
    return t?.color || '#6b7280'
  }

  async function onCreateTag ({ label, color }) {
    try {
      const doc = await createTag(label, 'Custom', color)
      internalTags.value.push({ name: doc.name || label, label, color, category: 'Custom' })
    } catch (e) {
      Notify.create({ type: 'negative', message: 'Erreur création tag: ' + e.message })
    }
  }

  async function onUpdateTag ({ name, color }) {
    try {
      await updateTag(name, { color })
      const t = internalTags.value.find(t => t.name === name || t.label === name)
      if (t) t.color = color
    } catch { /* silent */ }
  }

  async function onRenameTag ({ oldName, newName }) {
    try {
      await renameTag(oldName, newName)
      const t = internalTags.value.find(t => t.name === oldName || t.label === oldName)
      if (t) { t.name = newName; t.label = newName }
    } catch { /* silent */ }
  }

  async function onDeleteTag (label) {
    try {
      await deleteTag(label)
      internalTags.value = internalTags.value.filter(t => t.label !== label && t.name !== label)
    } catch { /* silent */ }
  }

  // ── Parent dependency search ──────────────────────────────────────────────
  const parentOptions = ref([])
  let parentDebounce = null
  let recentLoaded = false

  // Load recent tickets on first open (no query needed)
  async function loadRecentParents () {
    if (recentLoaded && parentOptions.value.length) return
    try {
      const issues = await listDocs('Issue', {
        fields: ['name', 'subject', 'status'],
        limit: 15,
        orderBy: 'creation desc',
      })
      parentOptions.value = issues.map(i => ({
        label: `${i.name}: ${i.subject || ''}`,
        value: i.name,
        type: 'Issue',
        status: i.status,
      }))
      recentLoaded = true
    } catch { /* silent */ }
  }

  function searchParent (query, done) {
    clearTimeout(parentDebounce)
    // No query → show recent tickets
    if (!query || query.length < 2) {
      loadRecentParents().then(() => done?.(parentOptions.value))
      return
    }
    parentDebounce = setTimeout(async () => {
      try {
        const [issues, tasks] = await Promise.all([
          listDocs('Issue', {
            or_filters: { subject: ['like', `%${query}%`], name: ['like', `%${query}%`] },
            fields: ['name', 'subject', 'status'],
            limit: 10,
            orderBy: 'creation desc',
          }),
          listDocs('Task', {
            or_filters: { subject: ['like', `%${query}%`], name: ['like', `%${query}%`] },
            fields: ['name', 'subject', 'status'],
            limit: 10,
            orderBy: 'creation desc',
          }),
        ])
        const results = [
          ...issues.map(i => ({ label: `${i.name}: ${i.subject || ''}`, value: i.name, type: 'Issue', status: i.status })),
          ...tasks.map(t => ({ label: `${t.name}: ${t.subject || ''}`, value: t.name, type: 'Task', status: t.status })),
        ]
        parentOptions.value = results
        done?.(results)
      } catch { done?.([]) }
    }, 300)
  }

  // ── Best tech ranking ─────────────────────────────────────────────────────
  const findingBest = ref(false)
  const ranking = ref([])

  async function findBestTech () {
    findingBest.value = true
    try {
      const res = await fetch(HUB_URL + '/dispatch/best-tech', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          latitude: form._latitude,
          longitude: form._longitude,
          duration_h: form.duration_h,
          date: form.scheduled_date || new Date().toISOString().slice(0, 10),
        }),
      })
      const data = await res.json()
      ranking.value = data.ranking || []
    } catch (e) {
      Notify.create({ type: 'negative', message: 'Erreur calcul optimal' })
    } finally {
      findingBest.value = false
    }
  }

  // ── Reset form from context ───────────────────────────────────────────────
  function resetForm (ctx = {}) {
    form.subject = ctx.subject || ''
    form.priority = ctx.priority || 'medium'
    form.description = ctx.description || ''
    form.issue_type = ctx.issue_type || null
    form.service_location = ctx.service_location || null
    form.job_type = ctx.job_type || 'Autre'
    form.duration_h = ctx.duration_h || 1
    form.address = ctx.address || ''
    form.assigned_tech = ctx.assigned_tech || null
    form.tags = Array.isArray(ctx.tags) ? ctx.tags.slice() : [] // compétence/type pré-rempli (ex. chip du « Trouver un créneau »)
    form.scheduled_date = ctx.scheduled_date || ''
    form.start_time = ctx.start_time || ''
    form._latitude = ctx._latitude != null ? ctx._latitude : (ctx.latitude != null ? ctx.latitude : null) // coords pré-remplies (réservation par créneau)
    form._longitude = ctx._longitude != null ? ctx._longitude : (ctx.longitude != null ? ctx.longitude : null)
    form.depends_on = ctx.depends_on || null
    form.tags = ctx.tags || []
    form._latitude = ctx.latitude || null
    form._longitude = ctx.longitude || null
    form._customer = ctx.customer || ''
    form._source_issue = ctx.source_issue || ''
    form._subscription = ctx.subscription || ''
    ranking.value = []
  }

  // ── Submit — routes to correct backend ────────────────────────────────────
  async function submit () {
    if (!form.subject?.trim()) {
      Notify.create({ type: 'warning', message: 'Le sujet est requis' })
      return null
    }
    submitting.value = true
    try {
      const m = typeof mode === 'string' ? mode : mode.value
      let result

      if (m === 'ticket') {
        const data = {
          customer: form._customer,
          subject: form.subject.trim(),
          priority: capitalize(form.priority),
          status: 'Open',
          description: form.description || '',
        }
        if (form.issue_type) data.issue_type = form.issue_type
        if (form.service_location) data.service_location = form.service_location
        if (form.depends_on) data.depends_on = form.depends_on
        result = await createDoc('Issue', data)
        Notify.create({ type: 'positive', message: 'Ticket créé' })

      } else if (m === 'task') {
        const data = {
          subject: form.subject.trim(),
          priority: capitalize(form.priority),
          status: 'Open',
          description: form.description || '',
        }
        if (form.duration_h) data.expected_time = form.duration_h
        if (form.scheduled_date) data.exp_start_date = form.scheduled_date
        if (form.depends_on) data.parent_task = form.depends_on
        result = await createDoc('Task', data)
        Notify.create({ type: 'positive', message: 'Tâche créée' })

      } else if (m === 'work-order') {
        const ticketId = await fetchNextRef() // numéro standardisé YYYYMMDD-XXX (hub)
        const payload = {
          ticket_id: ticketId,
          subject: form.subject.trim(),
          address: form.address,
          duration_h: form.duration_h,
          priority: form.priority,
          status: form.assigned_tech ? 'assigned' : 'open',
          job_type: form.job_type,
          source_issue: form._source_issue,
          customer: form._customer,
          service_location: form.service_location || '',
          depends_on: form.depends_on || '',
          scheduled_date: form.scheduled_date || (form.assigned_tech ? nextWeekday() : ''),
          start_time: form.start_time || '', // heure du créneau réservé (sinon vide = non planifié à l'heure)
          notes: form.description || '',
          assigned_tech: form.assigned_tech || '',
          latitude: form._latitude || '',
          longitude: form._longitude || '',
          tags: form.tags.map(t => typeof t === 'string' ? t : t.tag).join(','),
        }
        result = await createJob(payload)
        Notify.create({ type: 'positive', message: form.assigned_tech ? 'Travail créé et assigné' : 'Travail créé' })
      }

      return result
    } catch (err) {
      Notify.create({ type: 'negative', message: `Erreur: ${err.message || err}` })
      return null
    } finally {
      submitting.value = false
    }
  }

  return {
    form,
    fields,
    submitting,
    resetForm,
    submit,
    // Tags
    loadTags,
    allTagsList: computed(() => allTags()),
    getTagColor,
    onCreateTag,
    onUpdateTag,
    onRenameTag,
    onDeleteTag,
    // Parent
    parentOptions,
    searchParent,
    // Best tech
    findingBest,
    ranking,
    findBestTech,
  }
}

function capitalize (s) {
  if (!s) return s
  return s.charAt(0).toUpperCase() + s.slice(1).toLowerCase()
}
