<!-- Tablero de Tareas -->
<script src="https://cdn.jsdelivr.net/npm/sortablejs@1.15.3/Sortable.min.js"></script>
<div x-data="tareasApp()" x-init="init()" @keydown.escape.window="cerrarDetalle(); cerrarModal()">

  <!-- Header -->
  <div class="mb-6 flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4">
    <div>
      <h1 class="text-2xl font-bold text-slate-800">Tablero de Tareas</h1>
      <p class="text-sm text-slate-500 mt-0.5">Organiza y asigna tareas al equipo.</p>
    </div>
    <div class="flex items-center gap-2">
      <!-- Filtro asignado -->
      <select x-model="filtroUsuario"
        class="border border-slate-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-1 focus:ring-[#8eb02f]">
        <option value="">Todos los usuarios</option>
        <template x-for="u in usuarios" :key="u.ID">
          <option :value="u.ID" x-text="u.name"></option>
        </template>
      </select>
      <button @click="abrirNueva()"
        class="flex items-center gap-2 text-white text-sm font-medium px-4 py-2 rounded-lg shrink-0"
        style="background-color:#8eb02f"
        onmouseover="this.style.backgroundColor='#6d8c24'"
        onmouseout="this.style.backgroundColor='#8eb02f'">
        <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
          <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4"/>
        </svg>
        Nueva tarea
      </button>
    </div>
  </div>

  <!-- Alertas -->
  <div x-show="errorMsg" x-cloak class="mb-4 p-3 bg-red-50 border border-red-200 rounded-lg text-sm text-red-700" x-text="errorMsg"></div>
  <div x-show="successMsg" x-cloak class="mb-4 p-3 bg-green-50 border border-green-200 rounded-lg text-sm text-green-700" x-text="successMsg"></div>

  <!-- Loading -->
  <div x-show="cargando" class="flex items-center justify-center py-20 text-slate-400 gap-2">
    <svg class="w-5 h-5 animate-spin" fill="none" stroke="currentColor" viewBox="0 0 24 24">
      <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"/>
    </svg>
    Cargando tablero...
  </div>

  <!-- Kanban Board -->
  <div x-show="!cargando" class="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-4 gap-4">
    <template x-for="col in columnas" :key="col.id">
      <div class="flex flex-col min-h-[200px]">
        <!-- Column header -->
        <div class="flex items-center justify-between mb-3">
          <div class="flex items-center gap-2">
            <span x-text="col.icon" class="text-base"></span>
            <h2 class="text-sm font-bold text-slate-700" x-text="col.label"></h2>
            <span class="bg-slate-200 text-slate-600 text-xs font-bold px-2 py-0.5 rounded-full"
              x-text="tareasFiltradas(col.id).length"></span>
          </div>
          <button @click="abrirNueva(col.id)" title="Agregar en esta columna"
            class="text-slate-400 hover:text-[#8eb02f] transition p-1">
            <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
              <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4"/>
            </svg>
          </button>
        </div>

        <!-- Column drop zone -->
        <div :id="'col-' + col.id"
          class="flex-1 rounded-xl p-2 space-y-2 min-h-[120px] transition-colors"
          :class="col.bg"
          data-estado="">
          <template x-for="t in tareasFiltradas(col.id)" :key="t.ID">
            <div :data-id="t.ID" @click="abrirDetalle(t)"
              class="bg-white rounded-xl border border-slate-200 shadow-sm p-3 cursor-grab active:cursor-grabbing hover:shadow-md transition-all group">

              <!-- Prioridad strip -->
              <div class="h-1 rounded-full mb-2 -mt-1 -mx-1"
                :class="prioBg(t.prioridad)"></div>

              <!-- Título -->
              <p class="text-sm font-semibold text-slate-800 leading-snug mb-2" x-text="t.titulo"></p>

              <!-- Tags row -->
              <div class="flex flex-wrap gap-1 mb-2">
                <span class="px-1.5 py-0.5 rounded text-xs font-semibold"
                  :class="prioClass(t.prioridad)" x-text="prioLabel(t.prioridad)"></span>
                <template x-if="t.fecha_limite">
                  <span class="px-1.5 py-0.5 rounded text-xs font-semibold"
                    :class="fechaClass(t.fecha_limite)"
                    x-text="formatFecha(t.fecha_limite)"></span>
                </template>
              </div>

              <!-- Footer -->
              <div class="flex items-center justify-between">
                <div class="flex items-center gap-1.5">
                  <template x-if="t.asignado">
                    <div class="flex items-center gap-1">
                      <div class="w-6 h-6 rounded-full bg-[#8eb02f] flex items-center justify-center text-white text-xs font-bold"
                        x-text="iniciales(t.asignado.name)"></div>
                      <span class="text-xs text-slate-400" x-text="t.asignado.name"></span>
                    </div>
                  </template>
                  <template x-if="!t.asignado">
                    <span class="text-xs text-slate-300">Sin asignar</span>
                  </template>
                </div>
                <!-- Acciones rápidas (aparecen al hover) -->
                <div class="flex gap-1 opacity-0 group-hover:opacity-100 transition-opacity" @click.stop>
                  <button @click.stop="abrirEditar(t)" title="Editar"
                    class="p-1 rounded text-slate-400 hover:text-[#8eb02f] hover:bg-[#f5f8e8] transition">
                    <svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                      <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"/>
                    </svg>
                  </button>
                  <button @click.stop="eliminar(t)" title="Eliminar"
                    class="p-1 rounded text-slate-400 hover:text-red-500 hover:bg-red-50 transition">
                    <svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                      <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"/>
                    </svg>
                  </button>
                </div>
              </div>
            </div>
          </template>

          <!-- Empty column placeholder -->
          <div x-show="tareasFiltradas(col.id).length === 0"
            class="text-center py-8 text-slate-300 text-xs select-none pointer-events-none">
            Sin tareas
          </div>
        </div>
      </div>
    </template>
  </div>

  <!-- ═══════════════════════════════════════════════════ -->
  <!-- Modal Crear / Editar                               -->
  <!-- ═══════════════════════════════════════════════════ -->
  <div x-show="modal.open" x-cloak class="fixed inset-0 z-50 flex items-center justify-center p-4 bg-black/50">
    <div @click.outside="cerrarModal()" class="bg-white rounded-2xl shadow-2xl w-full max-w-lg">
      <div class="flex items-center justify-between px-6 py-4 border-b border-slate-200">
        <h2 class="text-lg font-bold text-slate-800"
          x-text="modal.modo === 'crear' ? 'Nueva tarea' : 'Editar tarea'"></h2>
        <button @click="cerrarModal()" class="text-slate-400 hover:text-slate-600">
          <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
            <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
          </svg>
        </button>
      </div>

      <div class="px-6 py-5 space-y-4">
        <div>
          <label class="block text-xs font-semibold text-slate-600 mb-1">Título</label>
          <input x-model="modal.form.titulo" type="text" placeholder="¿Qué hay que hacer?"
            class="w-full border border-slate-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-[#8eb02f]"/>
        </div>
        <div>
          <label class="block text-xs font-semibold text-slate-600 mb-1">Descripción</label>
          <textarea x-model="modal.form.descripcion" rows="3" placeholder="Detalles opcionales..."
            class="w-full border border-slate-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-[#8eb02f] resize-none"></textarea>
        </div>
        <div class="grid grid-cols-2 gap-3">
          <div>
            <label class="block text-xs font-semibold text-slate-600 mb-1">Prioridad</label>
            <select x-model="modal.form.prioridad"
              class="w-full border border-slate-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-[#8eb02f]">
              <option value="baja">🟢 Baja</option>
              <option value="media">🟡 Media</option>
              <option value="alta">🟠 Alta</option>
              <option value="urgente">🔴 Urgente</option>
            </select>
          </div>
          <div>
            <label class="block text-xs font-semibold text-slate-600 mb-1">Fecha límite</label>
            <input x-model="modal.form.fecha_limite" type="date"
              class="w-full border border-slate-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-[#8eb02f]"/>
          </div>
        </div>
        <div>
          <label class="block text-xs font-semibold text-slate-600 mb-1">Asignar a</label>
          <select x-model.number="modal.form.asignado_id"
            class="w-full border border-slate-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-[#8eb02f]">
            <option :value="null">Sin asignar</option>
            <template x-for="u in usuarios" :key="u.ID">
              <option :value="u.ID" x-text="u.name"></option>
            </template>
          </select>
        </div>
        <template x-if="modal.modo === 'crear'">
          <div>
            <label class="block text-xs font-semibold text-slate-600 mb-1">Estado inicial</label>
            <select x-model="modal.form.estado"
              class="w-full border border-slate-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-[#8eb02f]">
              <option value="por_hacer">📥 Por hacer</option>
              <option value="en_progreso">🔄 En progreso</option>
              <option value="revision">🔍 En revisión</option>
              <option value="hecho">✅ Hecho</option>
            </select>
          </div>
        </template>
      </div>

      <div class="px-6 py-4 border-t border-slate-100 flex justify-end gap-3">
        <button @click="cerrarModal()"
          class="px-4 py-2 text-sm rounded-lg border border-slate-300 text-slate-600 hover:bg-slate-50 transition">
          Cancelar
        </button>
        <button @click="guardar()" :disabled="guardando"
          class="px-4 py-2 text-sm rounded-lg text-white font-medium transition disabled:opacity-50"
          style="background-color:#8eb02f"
          onmouseover="if(!this.disabled)this.style.backgroundColor='#6d8c24'"
          onmouseout="this.style.backgroundColor='#8eb02f'">
          <span x-text="guardando ? 'Guardando...' : 'Guardar'"></span>
        </button>
      </div>
    </div>
  </div>

  <!-- ═══════════════════════════════════════════════════ -->
  <!-- Panel de Detalle / Comentarios (slide-in)          -->
  <!-- ═══════════════════════════════════════════════════ -->
  <div x-show="detalle.open" x-cloak class="fixed inset-0 z-50 flex justify-end bg-black/40">
    <div @click.outside="cerrarDetalle()"
      class="bg-white w-full max-w-xl h-full overflow-y-auto shadow-2xl flex flex-col">

      <div x-show="detalle.cargando" class="flex-1 flex items-center justify-center text-slate-400">
        <svg class="w-5 h-5 animate-spin" fill="none" stroke="currentColor" viewBox="0 0 24 24">
          <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"/>
        </svg>
      </div>

      <template x-if="detalle.tarea && !detalle.cargando">
        <div class="flex flex-col flex-1">
          <!-- Header -->
          <div class="sticky top-0 bg-white z-10 px-6 py-4 border-b border-slate-200">
            <div class="flex items-start gap-3">
              <div class="flex-1 min-w-0">
                <!-- Estado chips -->
                <div class="flex flex-wrap gap-1 mb-2">
                  <template x-for="col in columnas" :key="col.id">
                    <button @click="moverDesdeDetalle(col.id)"
                      :class="detalle.tarea.estado === col.id
                        ? 'ring-2 ring-offset-1 ring-[#8eb02f] ' + col.activeBg
                        : 'bg-slate-100 text-slate-500 hover:bg-slate-200'"
                      class="px-2 py-0.5 rounded-full text-xs font-semibold transition"
                      x-text="col.icon + ' ' + col.label"></button>
                  </template>
                </div>
                <h2 class="text-base font-bold text-slate-800 leading-snug" x-text="detalle.tarea.titulo"></h2>
              </div>
              <div class="flex items-center gap-1 shrink-0">
                <button @click="abrirEditar(detalle.tarea)" title="Editar"
                  class="p-1.5 rounded text-slate-400 hover:text-[#8eb02f] hover:bg-[#f5f8e8] transition">
                  <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"/>
                  </svg>
                </button>
                <button @click="cerrarDetalle()" class="p-1.5 rounded text-slate-400 hover:text-slate-600 transition">
                  <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
                  </svg>
                </button>
              </div>
            </div>
          </div>

          <div class="flex-1 px-6 py-5 space-y-5 overflow-y-auto">
            <!-- Meta info -->
            <div class="grid grid-cols-2 gap-3">
              <div class="bg-slate-50 rounded-xl p-3">
                <p class="text-xs text-slate-400 mb-1">Prioridad</p>
                <span class="px-2 py-0.5 rounded text-xs font-semibold"
                  :class="prioClass(detalle.tarea.prioridad)"
                  x-text="prioLabel(detalle.tarea.prioridad)"></span>
              </div>
              <div class="bg-slate-50 rounded-xl p-3">
                <p class="text-xs text-slate-400 mb-1">Fecha límite</p>
                <span class="text-sm font-semibold"
                  :class="detalle.tarea.fecha_limite ? fechaClass(detalle.tarea.fecha_limite) : 'text-slate-400'"
                  x-text="detalle.tarea.fecha_limite ? formatFecha(detalle.tarea.fecha_limite) : 'Sin fecha'"></span>
              </div>
              <div class="bg-slate-50 rounded-xl p-3">
                <p class="text-xs text-slate-400 mb-1">Asignado a</p>
                <div class="flex items-center gap-1.5">
                  <template x-if="detalle.tarea.asignado">
                    <div class="w-5 h-5 rounded-full bg-[#8eb02f] flex items-center justify-center text-white text-xs font-bold"
                      x-text="iniciales(detalle.tarea.asignado.name)"></div>
                  </template>
                  <span class="text-sm font-semibold text-slate-700"
                    x-text="detalle.tarea.asignado ? detalle.tarea.asignado.name : 'Sin asignar'"></span>
                </div>
              </div>
              <div class="bg-slate-50 rounded-xl p-3">
                <p class="text-xs text-slate-400 mb-1">Creado por</p>
                <span class="text-sm font-semibold text-slate-700"
                  x-text="detalle.tarea.creado_por ? detalle.tarea.creado_por.name : '—'"></span>
              </div>
            </div>

            <!-- Descripción -->
            <template x-if="detalle.tarea.descripcion">
              <div>
                <p class="text-xs font-semibold text-slate-500 uppercase tracking-wider mb-2">Descripción</p>
                <p class="text-sm text-slate-700 whitespace-pre-line bg-slate-50 rounded-xl p-3"
                  x-text="detalle.tarea.descripcion"></p>
              </div>
            </template>

            <!-- Comentarios -->
            <div>
              <p class="text-xs font-semibold text-slate-500 uppercase tracking-wider mb-3">
                Comentarios
                <span class="ml-1 bg-slate-100 text-slate-600 px-1.5 rounded-full"
                  x-text="detalle.comentarios.length"></span>
              </p>

              <div class="space-y-3 mb-4">
                <template x-if="detalle.comentarios.length === 0">
                  <p class="text-xs text-slate-400 text-center py-4">Sin comentarios aún</p>
                </template>
                <template x-for="(cm, idx) in detalle.comentarios" :key="cm.id || idx">
                  <div class="flex gap-3">
                    <div class="w-7 h-7 rounded-full bg-slate-300 flex items-center justify-center text-white text-xs font-bold shrink-0"
                      x-text="iniciales(cm.autor ? cm.autor.name : '?')"></div>
                    <div class="flex-1 bg-slate-50 rounded-xl p-3">
                      <div class="flex items-center justify-between mb-1">
                        <span class="text-xs font-semibold text-slate-600"
                          x-text="cm.autor ? cm.autor.name : 'Usuario'"></span>
                        <span class="text-xs text-slate-400" x-text="formatFechaCorta(cm.created_at)"></span>
                      </div>
                      <p class="text-sm text-slate-700 whitespace-pre-line" x-text="cm.contenido"></p>
                      <!-- Archivos adjuntos -->
                      <template x-if="tieneArchivos(cm.archivos)">
                        <div class="mt-2">
                          <template x-for="(arch, i) in parsearArchivos(cm.archivos)" :key="i">
                            <a :href="'/' + arch.ruta" target="_blank"
                              class="inline-flex items-center gap-1 text-xs text-blue-500 hover:underline mt-1">
                              <svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15.172 7l-6.586 6.586a2 2 0 102.828 2.828l6.414-6.586a4 4 0 00-5.656-5.656l-6.415 6.585a6 6 0 108.486 8.486L20.5 13"/>
                              </svg>
                              <span x-text="arch.nombre"></span>
                            </a>
                          </template>
                        </div>
                      </template>
                    </div>
                  </div>
                </template>
              </div>

              <!-- Nuevo comentario -->
              <div class="border border-slate-200 rounded-xl p-3 bg-white">
                <textarea x-model="detalle.nuevoComentario" rows="2"
                  placeholder="Agregar comentario o actualización..."
                  class="w-full text-sm text-slate-700 resize-none focus:outline-none placeholder-slate-400"></textarea>
                <!-- Archivo adjunto -->
                <div class="flex items-center justify-between mt-2 pt-2 border-t border-slate-100">
                  <div class="flex items-center gap-2">
                    <label class="cursor-pointer flex items-center gap-1 text-xs text-slate-400 hover:text-slate-600 transition">
                      <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15.172 7l-6.586 6.586a2 2 0 102.828 2.828l6.414-6.586a4 4 0 00-5.656-5.656l-6.415 6.585a6 6 0 108.486 8.486L20.5 13"/>
                      </svg>
                      Adjuntar
                      <input type="file" class="hidden" x-ref="fileInput" @change="seleccionarArchivo($event)"/>
                    </label>
                    <span x-show="detalle.archivoSeleccionado" class="text-xs text-slate-500 truncate max-w-[150px]"
                      x-text="detalle.archivoSeleccionado"></span>
                  </div>
                  <button @click="enviarComentario()" :disabled="detalle.enviando"
                    class="flex items-center gap-1.5 px-3 py-1.5 rounded-lg text-xs font-semibold text-white transition disabled:opacity-40"
                    style="background-color:#8eb02f"
                    onmouseover="if(!this.disabled)this.style.backgroundColor='#6d8c24'"
                    onmouseout="this.style.backgroundColor='#8eb02f'">
                    <svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                      <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 19l9 2-9-18-9 18 9-2zm0 0v-8"/>
                    </svg>
                    <span x-text="detalle.enviando ? 'Enviando...' : 'Enviar'"></span>
                  </button>
                </div>
              </div>
            </div>
          </div>
        </div>
      </template>
    </div>
  </div>

  <script>
    function tareasApp() {
      return {
        tareas: [],
        usuarios: [],
        cargando: true,
        errorMsg: '',
        successMsg: '',
        guardando: false,
        filtroUsuario: '',
        sortables: [],

        columnas: [
          { id: 'por_hacer',   label: 'Por hacer',    icon: '📥', bg: 'bg-slate-100',   activeBg: 'bg-slate-200 text-slate-700' },
          { id: 'en_progreso', label: 'En progreso',  icon: '🔄', bg: 'bg-blue-50',     activeBg: 'bg-blue-100 text-blue-700' },
          { id: 'revision',    label: 'En revisión',  icon: '🔍', bg: 'bg-amber-50',    activeBg: 'bg-amber-100 text-amber-700' },
          { id: 'hecho',       label: 'Hecho',        icon: '✅', bg: 'bg-green-50',    activeBg: 'bg-green-100 text-green-700' },
        ],

        modal: {
          open: false,
          modo: 'crear',
          editId: null,
          form: { titulo: '', descripcion: '', prioridad: 'media', asignado_id: null, fecha_limite: '', estado: 'por_hacer' },
        },

        detalle: {
          open: false,
          cargando: false,
          tarea: null,
          comentarios: [],
          nuevoComentario: '',
          archivoSeleccionado: '',
          _archivo: null,
          enviando: false,
        },

        async init() {
          await Promise.all([this.cargar(), this.cargarUsuarios()]);
          await this.$nextTick();
          this.iniciarSortable();
        },

        async cargar() {
          this.cargando = true;
          try {
            const r = await fetch('/app/tareas/data');
            this.tareas = await r.json() || [];
          } catch (e) {
            this.mostrarError('Error cargando tareas');
          } finally {
            this.cargando = false;
          }
        },

        async cargarUsuarios() {
          try {
            const r = await fetch('/app/tareas/usuarios');
            this.usuarios = await r.json() || [];
          } catch {}
        },

        tareasFiltradas(estado) {
          return this.tareas.filter(t => {
            if (t.estado !== estado) return false;
            if (this.filtroUsuario && String(t.asignado_id) !== String(this.filtroUsuario)) return false;
            return true;
          });
        },

        iniciarSortable() {
          this.sortables.forEach(s => s.destroy());
          this.sortables = [];
          this.columnas.forEach(col => {
            const el = document.getElementById('col-' + col.id);
            if (!el) return;
            const s = Sortable.create(el, {
              group: 'tareas',
              animation: 150,
              ghostClass: 'opacity-30',
              chosenClass: 'ring-2 ring-[#8eb02f]',
              dragClass: 'rotate-1',
              filter: 'button',
              onEnd: (evt) => {
                const id = parseInt(evt.item.dataset.id);
                const nuevoEstado = evt.to.id.replace('col-', '');
                const estadoAnterior = evt.from.id.replace('col-', '');
                if (nuevoEstado === estadoAnterior) return;

                // Revertir el movimiento DOM de SortableJS para que Alpine
                // pueda re-renderizar el x-for sin conflicto de nodos.
                evt.from.insertBefore(evt.item, evt.from.children[evt.oldIndex] || null);

                const t = this.tareas.find(t => t.ID === id);
                if (!t) return;
                t.estado = nuevoEstado; // dispara el re-render de Alpine

                // Re-iniciar Sortable después de que Alpine actualice el DOM
                this.$nextTick(() => this.iniciarSortable());

                fetch(`/app/tarea/${id}/estado`, {
                  method: 'PUT',
                  headers: { 'Content-Type': 'application/json' },
                  body: JSON.stringify({ estado: nuevoEstado }),
                }).catch(() => {
                  // Revertir estado local si la API falla
                  const tRev = this.tareas.find(t => t.ID === id);
                  if (tRev) tRev.estado = estadoAnterior;
                  this.$nextTick(() => this.iniciarSortable());
                });
              },
            });
            this.sortables.push(s);
          });
        },

        abrirNueva(estado) {
          this.modal.modo = 'crear';
          this.modal.editId = null;
          this.modal.form = {
            titulo: '', descripcion: '', prioridad: 'media',
            asignado_id: null, fecha_limite: '',
            estado: estado || 'por_hacer',
          };
          this.modal.open = true;
        },

        abrirEditar(t) {
          this.modal.modo = 'editar';
          this.modal.editId = t.ID;
          this.modal.form = {
            titulo: t.titulo,
            descripcion: t.descripcion || '',
            prioridad: t.prioridad || 'media',
            asignado_id: t.asignado_id || null,
            fecha_limite: t.fecha_limite ? t.fecha_limite.slice(0, 10) : '',
          };
          this.modal.open = true;
        },

        cerrarModal() { this.modal.open = false; },

        async guardar() {
          if (!this.modal.form.titulo.trim()) {
            this.mostrarError('El título es requerido');
            return;
          }
          this.guardando = true;
          try {
            const esEditar = this.modal.modo === 'editar';
            const url = esEditar ? `/app/tarea/${this.modal.editId}` : '/app/tarea';
            const body = { ...this.modal.form };
            if (!body.asignado_id) body.asignado_id = null;
            if (!body.fecha_limite) body.fecha_limite = null;
            const r = await fetch(url, {
              method: esEditar ? 'PUT' : 'POST',
              headers: { 'Content-Type': 'application/json' },
              body: JSON.stringify(body),
            });
            if (!r.ok) {
              const err = await r.json();
              throw new Error(err.error || 'Error al guardar');
            }
            const data = await r.json();
            if (esEditar) {
              const idx = this.tareas.findIndex(t => t.ID === this.modal.editId);
              if (idx >= 0) this.tareas[idx] = data;
              if (this.detalle.tarea?.ID === this.modal.editId) this.detalle.tarea = data;
            } else {
              this.tareas.push(data);
            }
            this.mostrarExito(esEditar ? 'Tarea actualizada' : 'Tarea creada');
            this.cerrarModal();
            await this.$nextTick();
            this.iniciarSortable();
          } catch (e) {
            this.mostrarError(e.message);
          } finally {
            this.guardando = false;
          }
        },

        async eliminar(t) {
          if (!confirm(`¿Eliminar la tarea "${t.titulo}"?`)) return;
          try {
            const r = await fetch(`/app/tarea/${t.ID}`, { method: 'DELETE' });
            if (!r.ok) throw new Error('Error al eliminar');
            this.tareas = this.tareas.filter(x => x.ID !== t.ID);
            this.mostrarExito('Tarea eliminada');
            if (this.detalle.tarea?.ID === t.ID) this.cerrarDetalle();
          } catch (e) {
            this.mostrarError(e.message);
          }
        },

        async abrirDetalle(t) {
          this.detalle.open = true;
          this.detalle.cargando = true;
          this.detalle.tarea = null;
          this.detalle.comentarios = [];
          this.detalle.nuevoComentario = '';
          this.detalle.archivoSeleccionado = '';
          this.detalle._archivo = null;
          try {
            const r = await fetch(`/app/tarea/${t.ID}`);
            const data = await r.json();
            this.detalle.tarea = data.tarea;
            this.detalle.comentarios = data.comentarios || [];
          } catch {
            this.mostrarError('Error cargando detalle');
          } finally {
            this.detalle.cargando = false;
          }
        },

        cerrarDetalle() {
          this.detalle.open = false;
          this.detalle.tarea = null;
        },

        async moverDesdeDetalle(nuevoEstado) {
          if (!this.detalle.tarea || this.detalle.tarea.estado === nuevoEstado) return;
          const id = this.detalle.tarea.ID;
          try {
            await fetch(`/app/tarea/${id}/estado`, {
              method: 'PUT',
              headers: { 'Content-Type': 'application/json' },
              body: JSON.stringify({ estado: nuevoEstado }),
            });
            this.detalle.tarea.estado = nuevoEstado;
            const t = this.tareas.find(x => x.ID === id);
            if (t) t.estado = nuevoEstado;
          } catch {
            this.mostrarError('Error cambiando estado');
          }
        },

        seleccionarArchivo(evt) {
          const file = evt.target.files[0];
          if (file) {
            this.detalle._archivo = file;
            this.detalle.archivoSeleccionado = file.name;
          }
        },

        async enviarComentario() {
          if (!this.detalle.nuevoComentario.trim() && !this.detalle._archivo) return;
          if (!this.detalle.tarea) return;
          this.detalle.enviando = true;
          try {
            const fd = new FormData();
            fd.append('contenido', this.detalle.nuevoComentario.trim() || ' ');
            if (this.detalle._archivo) fd.append('archivo', this.detalle._archivo);
            const r = await fetch(`/app/tarea/${this.detalle.tarea.ID}/comentario`, {
              method: 'POST',
              body: fd,
            });
            if (!r.ok) {
              const err = await r.json();
              throw new Error(err.error || 'Error al enviar');
            }
            const cm = await r.json();
            this.detalle.comentarios.push(cm);
            this.detalle.nuevoComentario = '';
            this.detalle.archivoSeleccionado = '';
            this.detalle._archivo = null;
            if (this.$refs.fileInput) this.$refs.fileInput.value = '';
          } catch (e) {
            this.mostrarError(e.message);
          } finally {
            this.detalle.enviando = false;
          }
        },

        tieneArchivos(json) {
          try { return JSON.parse(json || '[]').length > 0; } catch { return false; }
        },
        parsearArchivos(json) {
          try { return JSON.parse(json || '[]'); } catch { return []; }
        },

        iniciales(nombre) {
          if (!nombre) return '?';
          return nombre.split(' ').slice(0, 2).map(w => w[0]).join('').toUpperCase();
        },

        prioLabel(p) {
          return { baja: 'Baja', media: 'Media', alta: 'Alta', urgente: 'Urgente' }[p] || p;
        },
        prioClass(p) {
          return {
            baja:    'bg-green-100 text-green-700',
            media:   'bg-yellow-100 text-yellow-700',
            alta:    'bg-orange-100 text-orange-700',
            urgente: 'bg-red-100 text-red-600',
          }[p] || 'bg-slate-100 text-slate-500';
        },
        prioBg(p) {
          return {
            baja:    'bg-green-400',
            media:   'bg-yellow-400',
            alta:    'bg-orange-500',
            urgente: 'bg-red-500',
          }[p] || 'bg-slate-300';
        },

        formatFecha(ts) {
          if (!ts) return '';
          const d = new Date(ts);
          return d.toLocaleDateString('es', { day: '2-digit', month: 'short', year: 'numeric' });
        },
        formatFechaCorta(ts) {
          if (!ts) return '';
          const d = new Date(ts);
          const hoy = new Date();
          const diff = Math.floor((hoy - d) / 1000);
          if (diff < 60) return 'hace ' + diff + 's';
          if (diff < 3600) return 'hace ' + Math.floor(diff / 60) + 'min';
          if (diff < 86400) return 'hace ' + Math.floor(diff / 3600) + 'h';
          return d.toLocaleDateString('es', { day: '2-digit', month: 'short' });
        },
        fechaClass(ts) {
          if (!ts) return 'text-slate-400';
          const d = new Date(ts);
          const hoy = new Date(); hoy.setHours(0, 0, 0, 0);
          if (d < hoy) return 'bg-red-100 text-red-600 px-1.5 py-0.5 rounded text-xs font-semibold';
          const diff = (d - hoy) / 86400000;
          if (diff <= 2) return 'bg-amber-100 text-amber-600 px-1.5 py-0.5 rounded text-xs font-semibold';
          return 'bg-slate-100 text-slate-500 px-1.5 py-0.5 rounded text-xs font-semibold';
        },

        mostrarError(msg) {
          this.errorMsg = msg; this.successMsg = '';
          setTimeout(() => this.errorMsg = '', 5000);
        },
        mostrarExito(msg) {
          this.successMsg = msg; this.errorMsg = '';
          setTimeout(() => this.successMsg = '', 4000);
        },
      };
    }
  </script>
</div>
