// ── Auto-dispatch composable: autoDistribute + optimizeRoute ─────────────────
import { localDateStr } from './useHelpers'
import { updateJob } from 'src/api/dispatch'
import * as roster from 'src/api/roster' // TSP via NOTRE OSRM (plus de Mapbox optimized-trips)

export function useAutoDispatch (deps) {
  const { store, MAPBOX_TOKEN, filteredResources, periodStart, getJobDate, unscheduledJobs, bottomSelected, dispatchCriteria, pushUndo, invalidateRoutes } = deps

  async function autoDistribute () {
    const techs = filteredResources.value
    if (!techs.length) return
    const today = localDateStr(new Date())
    let pool
    if (bottomSelected.value.size) {
      pool = [...bottomSelected.value].map(id => store.jobs.find(j => j.id === id)).filter(Boolean)
    } else {
      pool = unscheduledJobs.value.filter(j => !j.scheduledDate || j.scheduledDate === today)
    }
    if (!pool.length) return
    // Jobs with coords get proximity-based assignment, jobs without get load-balanced only
    const withCoords = pool.filter(j => j.coords && (j.coords[0] !== 0 || j.coords[1] !== 0))
    const noCoords = pool.filter(j => !j.coords || (j.coords[0] === 0 && j.coords[1] === 0))
    const unassigned = [...withCoords, ...noCoords]
    if (!unassigned.length) return

    const prevQueues = {}
    techs.forEach(t => { prevQueues[t.id] = [...t.queue] })
    const prevAssignments = unassigned.map(j => ({ jobId: j.id, techId: j.assignedTech, scheduledDate: j.scheduledDate }))

    function techLoadForDay (tech, dayStr) {
      return tech.queue.filter(j => getJobDate(j.id) === dayStr).reduce((s, j) => s + (parseFloat(j.duration) || 1), 0)
    }
    function dist (a, b) {
      if (!a || !b) return 999
      const dx = (a[0] - b[0]) * 80, dy = (a[1] - b[1]) * 111
      return Math.sqrt(dx * dx + dy * dy)
    }
    function techLastPosForDay (tech, dayStr) {
      const dj = tech.queue.filter(j => getJobDate(j.id) === dayStr)
      if (dj.length) { const last = dj[dj.length - 1]; if (last.coords && last.coords[0] !== 0) return last.coords }
      return tech.coords
    }

    const criteria = dispatchCriteria.value.filter(c => c.enabled)
    const sorted = [...unassigned].sort((a, b) => {
      for (const c of criteria) {
        if (c.id === 'urgency') {
          const p = { high: 0, medium: 1, low: 2 }
          const diff = (p[a.priority] ?? 2) - (p[b.priority] ?? 2)
          if (diff !== 0) return diff
        }
      }
      return 0
    })

    const useSkills = criteria.some(c => c.id === 'skills')
    const weights = {}
    criteria.forEach((c, i) => { weights[c.id] = criteria.length - i })

    sorted.forEach(job => {
      const assignDay = job.scheduledDate || today
      let bestTech = null, bestScore = Infinity
      techs.forEach(tech => {
        let score = 0
        if (weights.balance) score += techLoadForDay(tech, assignDay) * (weights.balance || 1)
        if (weights.proximity && job.coords && (job.coords[0] !== 0 || job.coords[1] !== 0)) score += dist(techLastPosForDay(tech, assignDay), job.coords) / 60 * (weights.proximity || 1)
        if (weights.skills && useSkills) {
          const jt = job.tags || [], tt = tech.tags || []
          score += (jt.length > 0 ? (jt.length - jt.filter(t => tt.includes(t)).length) * 2 : 0) * (weights.skills || 1)
        }
        if (score < bestScore) { bestScore = score; bestTech = tech }
      })
      if (bestTech) store.smartAssign(job.id, bestTech.id, assignDay)
    })

    pushUndo({ type: 'autoDistribute', assignments: prevAssignments, prevQueues })
    bottomSelected.value = new Set()
    invalidateRoutes()
  }

  async function optimizeRoute (tech) {
    const dayStr = localDateStr(periodStart.value)
    const dayJobs = tech.queue.filter(j => getJobDate(j.id) === dayStr)
    if (dayJobs.length < 2) return
    const jobsWithCoords = dayJobs.filter(j => j.coords && (j.coords[0] !== 0 || j.coords[1] !== 0))
    if (jobsWithCoords.length < 2) return

    const urgent = jobsWithCoords.filter(j => j.priority === 'high')
    const normal = jobsWithCoords.filter(j => j.priority !== 'high')

    function nearestNeighbor (start, jobs) {
      const result = [], remaining = [...jobs]
      let cur = start
      while (remaining.length) {
        let bi = 0, bd = Infinity
        remaining.forEach((j, i) => {
          const dx = j.coords[0] - cur[0], dy = j.coords[1] - cur[1], d = dx * dx + dy * dy
          if (d < bd) { bd = d; bi = i }
        })
        result.push(remaining.splice(bi, 1)[0])
        cur = result.at(-1).coords
      }
      return result
    }

    const home = (tech.coords?.[0] && tech.coords?.[1]) ? tech.coords : jobsWithCoords[0].coords
    const orderedUrgent = nearestNeighbor(home, urgent)
    const orderedNormal = nearestNeighbor(orderedUrgent.length ? orderedUrgent.at(-1).coords : home, normal)
    const reordered = [...orderedUrgent, ...orderedNormal]

    try {
      const hasHome = !!(tech.coords?.[0] && tech.coords?.[1])
      const coords = []
      if (hasHome) coords.push([tech.coords[0], tech.coords[1]])
      reordered.forEach(j => coords.push([j.coords[0], j.coords[1]]))
      if (coords.length >= 2 && coords.length <= 12) {
        const data = await roster.osrmTrip(coords) // NOTRE OSRM /trip (via hub) — même forme que Mapbox optimized-trips
        if (data.code === 'Ok' && data.waypoints) {
          const off = hasHome ? 1 : 0, uc = orderedUrgent.length
          const mu = reordered.slice(0, uc).map((j, i) => ({ job: j, o: data.waypoints[i + off].waypoint_index })).sort((a, b) => a.o - b.o).map(x => x.job)
          const mn = reordered.slice(uc).map((j, i) => ({ job: j, o: data.waypoints[i + uc + off].waypoint_index })).sort((a, b) => a.o - b.o).map(x => x.job)
          reordered.length = 0
          reordered.push(...mu, ...mn)
        }
      }
    } catch (_) {}

    pushUndo({ type: 'optimizeRoute', techId: tech.id, prevQueue: [...tech.queue] })
    const otherJobs = tech.queue.filter(j => getJobDate(j.id) !== dayStr)
    tech.queue = [...reordered, ...otherJobs]
    tech.queue.forEach((j, i) => {
      j.routeOrder = i
      updateJob(j.name || j.id, { route_order: i, start_time: '' }).catch(() => {})
    })
    invalidateRoutes()
  }

  return { autoDistribute, optimizeRoute }
}
