<script setup lang="ts">
import { computed, watch, ref } from 'vue'
import { useI18n } from 'vue-i18n'
import { useProjectsStore } from '@/stores/projects'
import { useWorkItemsStore } from '@/stores/workitems'
import { useUsersStore } from '@/stores/users'
import { storage } from '@/services/storage'
import { getTypeLabel, getTypeColor, getTypeIcon } from '@/services/hierarchy'
import { Activity, FileText, Layers, Clock, Info, AlertTriangle, Plus, Brain, Sparkles, Loader2, CheckCircle2, XCircle, Send, ChevronDown, Eye } from 'lucide-vue-next'
import { Button } from '@/components/ui/button'
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from '@/components/ui/dialog'
import HuDrafts from '@/components/HuDrafts.vue'
import AiProjectChat from '@/components/AiProjectChat.vue'
import PrioritizerCard from '@/components/PrioritizerCard.vue'
import SCurveChart from '@/components/SCurveChart.vue'
import { analyzeProjectEpics, analyzeProjectHUs, saveEpicDrafts, saveHUDrafts } from '@/services/project-analyzer'
import { getDrafts, deleteDraft, type HuDraftRecord } from '@/services/hu-drafts-db'
import { kappa } from '@/services/kappa-api'
import { generateAndSavePlan, getQAPlans, type HUQAPlan } from '@/services/qa-analyzer'
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
import { Badge } from '@/components/ui/badge'
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from '@/components/ui/select'
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from '@/components/ui/table'

const { t } = useI18n()
const projects = useProjectsStore()
const workItems = useWorkItemsStore()
const usersStore = useUsersStore()
const project = computed(() => projects.selected)

// ─── Inline notification (funciona en Tauri) ─────────
const notification = ref<{ type: 'success' | 'error'; message: string } | null>(null)
let notifTimeout: ReturnType<typeof setTimeout> | null = null

function showNotif(type: 'success' | 'error', message: string) {
  if (notifTimeout) clearTimeout(notifTimeout)
  notification.value = { type, message }
  notifTimeout = setTimeout(() => { notification.value = null }, 5000)
}

// ─── Description modals ──────────────────────────────
const descModal = ref<{ title: string; content: string } | null>(null)
const descModalOpen = ref(false)

function openDescription(title: string, content: string) {
  descModal.value = { title, content }
  descModalOpen.value = true
}

// ─── Team members for this project ────────────────────
const projectTeam = computed(() => {
  const p = project.value
  if (!p) return []
  const ids = storage.getJSON<number[]>(`project_team_${p.id}`)
  if (!ids) return []
  return ids
    .map(id => usersStore.users.find(u => u.id === id))
    .filter(Boolean)
    .map(u => ({ id: u!.id, name: u!.full_name || u!.email }))
})

const assignedUsers = computed(() => {
  const seen = new Set<number>()
  const list: { id: number; name: string }[] = []
  for (const hu of workItems.userStories) {
    const employeeId = hu._assignedEmployeeId
    if (employeeId == null || employeeId <= 0 || seen.has(employeeId)) continue
    seen.add(employeeId)
    // Resolver employee → user para mostrar el nombre real
    const uid = resolveEmployeeToUser(employeeId)
    const name = uid != null
      ? (usersStore.users.find(u => u.id === uid)?.full_name || usersStore.users.find(u => u.id === uid)?.email || '')
      : ''
    list.push({ id: employeeId, name: name || hu._assignedName || `Usuario #${employeeId}` })
  }
  return list.sort((a, b) => a.name.localeCompare(b.name))
})

// ─── HU assignments (local) ───────────────────────────
const STORAGE_KEY = 'hu_assignments'

function loadAssignments(): Record<number, number> {
  return storage.getJSON<Record<number, number>>(STORAGE_KEY) || {}
}

function saveAssignment(huId: number, userId: number | null) {
  const all = loadAssignments()
  if (userId === null) {
    delete all[huId]
  } else {
    all[huId] = userId
  }
  storage.setJSON(STORAGE_KEY, all)
}

function resolveEmployeeToUser(employeeId: number | null): number | null {
  if (employeeId == null) return null
  const emp = usersStore.employees.find(e => e.id === employeeId)
  return emp?.user ?? null
}

function getAssignedUserId(hu: { _assignedEmployeeId?: number | null; _assignedUserId?: number | null; id?: number }): number | null {
  // 1. KAPPA asigna por employee_id (asignado_a: [1135]) → resolver a user_id
  if (hu._assignedEmployeeId != null && hu._assignedEmployeeId > 0) {
    const userId = resolveEmployeeToUser(hu._assignedEmployeeId)
    if (userId != null) return userId
  }
  // 2. KAPPA asigna directo por user_id (assigned_to)
  if (hu._assignedUserId != null && hu._assignedUserId > 0) return hu._assignedUserId
  // 3. Fallback: asignación manual en localStorage
  if (hu.id != null) {
    const all = loadAssignments()
    return all[hu.id] ?? null
  }
  return null
}

function assignedName(hu: { _assignedName?: string; _assignedEmployeeId?: number | null; _assignedUserId?: number | null; id?: number }): string {
  // 1. Intentar resolver employee_id → user_id → nombre real
  if (hu._assignedEmployeeId != null && hu._assignedEmployeeId > 0) {
    const userId = resolveEmployeeToUser(hu._assignedEmployeeId)
    if (userId != null) {
      const u = usersStore.users.find(u => u.id === userId)
      if (u) return u.full_name || u.email
    }
    // Si el employee no se ha cargado aún, mostrar el nombre de KAPPA (asignado_a_names)
    if (hu._assignedName) return hu._assignedName
  }
  // 2. user_id directo
  if (hu._assignedUserId != null && hu._assignedUserId > 0) {
    const u = usersStore.users.find(u => u.id === hu._assignedUserId)
    if (u) return u.full_name || u.email
    if (hu._assignedName) return hu._assignedName
  }
  // 3. Fallback localStorage
  const uid = getAssignedUserId(hu)
  if (uid) {
    const u = usersStore.users.find(u => u.id === uid)
    if (u) return u.full_name || u.email
  }
  return hu._assignedName || ''
}

// ─── Priority helpers ─────────────────────────────────
const PRIORITY_MAP: Record<string, { label: string; variant: string }> = {
  '1': { label: 'Baja', variant: 'secondary' },
  '2': { label: 'Media', variant: 'default' },
  '3': { label: 'Alta', variant: 'destructive' },
  'alta': { label: 'Alta', variant: 'destructive' },
  'high': { label: 'Alta', variant: 'destructive' },
  'critical': { label: 'Crítica', variant: 'destructive' },
  'urgente': { label: 'Urgente', variant: 'destructive' },
  'media': { label: 'Media', variant: 'default' },
  'medium': { label: 'Media', variant: 'default' },
  'normal': { label: 'Media', variant: 'default' },
  'baja': { label: 'Baja', variant: 'secondary' },
  'low': { label: 'Baja', variant: 'secondary' },
}

function priorityVariant(p: unknown) {
  const s = String(p ?? '').toLowerCase().trim()
  return (PRIORITY_MAP[s]?.variant ?? 'outline') as 'default' | 'destructive' | 'outline' | 'secondary'
}

function priorityLabel(p: unknown) {
  const s = String(p ?? '').toLowerCase().trim()
  return PRIORITY_MAP[s]?.label ?? String(p ?? '—')
}

// ─── Filters ─────────────────────────────────────────
const filterStatus = ref('')
const filterPriority = ref('')
const filterAssigned = ref('')

const filteredHUs = computed(() => {
  let list = workItems.userStories
  if (filterStatus.value && filterStatus.value !== '__all') {
    list = list.filter(h => {
      const s = String(h.status ?? '').toLowerCase()
      return s === filterStatus.value
    })
  }
  if (filterPriority.value && filterPriority.value !== '__all') {
    list = list.filter(h => {
      const p = String(h.priority ?? '').toLowerCase()
      return p === filterPriority.value
    })
  }
  if (filterAssigned.value && filterAssigned.value !== '__all') {
    if (filterAssigned.value === '__none') {
      list = list.filter(h => !getAssignedUserId(h) && !h._assignedEmployeeId)
    } else {
      const targetId = Number(filterAssigned.value)
      list = list.filter(h => h._assignedEmployeeId === targetId || getAssignedUserId(h) === targetId)
    }
  }
  return list
})

const emit = defineEmits<{
  'navigate-settings': []
}>()

// ─── QA Plans ───────────────────────────────────────────
const qaPlans = ref<any[]>([])
const generatingQA = ref<string | null>(null)
const expandedQA = ref<string | null>(null)

const qaMetrics = computed(() => {
  const plans = qaPlans.value
  let auto = 0, manual = 0, parcial = 0, totalCases = 0
  for (const p of plans) {
    const plan = parseQAPlan(p)
    if (!plan) continue
    for (const tc of plan.testCases) {
      totalCases++
      if (tc.automatizable === 'SÍ') auto++
      else if (tc.automatizable === 'MANUAL') manual++
      else parcial++
    }
  }
  return { total: plans.length, auto, manual, parcial, totalCases }
})

async function loadQAPlans(projectId: number) {
  qaPlans.value = await getQAPlans(projectId)
}

async function generateQA(d: HuDraftRecord) {
  generatingQA.value = d.id
  try {
    await generateAndSavePlan(d.projectId, d.id, d.title, d.description || '', d.acceptanceCriteria)
    await loadQAPlans(d.projectId)
  } catch (e: any) {
    console.error('[Alpha] QA generation error:', e)
  } finally {
    generatingQA.value = null
  }
}

function parseQAPlan(record: any): HUQAPlan | null {
  try { return JSON.parse(record.plan) as HUQAPlan } catch { return null }
}

function toggleQAExpand(id: string) {
  expandedQA.value = expandedQA.value === id ? null : id
}

function qaBadgeColor(a: string) {
  if (a === 'SÍ') return 'text-green-600 border-green-300'
  if (a === 'MANUAL') return 'text-red-600 border-red-300'
  return 'text-amber-600 border-amber-300'
}

// ─── Drafts ──────────────────────────────────────────────
function getEpicLinkedHUs(d: HuDraftRecord): string[] {
  try {
    const meta = JSON.parse(d.metadata || '{}')
    return meta.linkedHuTitles || []
  } catch { return [] }
}

function getEpicCode(d: HuDraftRecord): string {
  try {
    const meta = JSON.parse(d.metadata || '{}')
    return meta.epicCode || ''
  } catch { return '' }
}

function getItemCode(d: HuDraftRecord): string {
  const match = d.title.match(/\[([^\]]+)\]/)
  return match ? match[1] : ''
}

function stripEpicTitle(title: string): string {
  return title.replace(/^\[[^\]]+\]\s*/, '')
}
const drafts = ref<HuDraftRecord[]>([])
const pushingDraftId = ref<string | null>(null)

async function loadDrafts() {
  if (!project.value) return
  drafts.value = await getDrafts(project.value.id)
}

async function pushDraft(d: HuDraftRecord) {
  pushingDraftId.value = d.id
  d.syncStatus = 'pushing'
  await dbSaveDraft(d)
  try {
    const token = localStorage.getItem('kappa_token')
    const headers = { 'Content-Type': 'application/json', ...(token ? { 'Authorization': `Bearer ${token}` } : {}) }

    let endpoint: string, body: string

    if (d.type === 'E') {
      // Push épica primero — KAPPA asigna el ID
      const meta = JSON.parse(d.metadata || '{}')
      const linkedHuIds: number[] = []
      for (const huTitle of meta.linkedHuTitles || []) {
        const pushedHu = drafts.value.find(x => x.type !== 'E' && (x.title.toLowerCase().trim() === huTitle.toLowerCase().trim()) && x.kappaId)
        if (pushedHu?.kappaId) linkedHuIds.push(pushedHu.kappaId)
      }
      endpoint = '/api/epicdevelopment/create/'
      body = JSON.stringify({
        initiative: String(d.projectId),
        name: d.title,
        description: d.description ? `<p>${d.description.replace(/\n/g, '</p><p>')}</p>` : '',
        stimated_start_date: meta.estimatedStart || null,
        stimated_end_date: meta.estimatedEnd || null,
        client_taker: Number(meta.clientTaker) || null,
        hu: linkedHuIds,
        status: false,
      })
    } else {
      // Push HU con epic_development si está vinculada a una épica
      const meta = JSON.parse(d.metadata || '{}')
      const epicDevId = meta.epicDevelopment || null
      endpoint = '/api/userstorys/create/'
      body = JSON.stringify({
        initiative: String(d.projectId),
        title: d.title,
        description: d.description ? `<p>${d.description.replace(/\n/g, '</p><p>')}</p>` : '',
        criterios_aceptacion: d.acceptanceCriteria ? `<p>${d.acceptanceCriteria.replace(/\n/g, '</p><p>')}</p>` : '',
        story_points: d.story_points ?? null,
        priority: d.priority === 'Alta' ? '3' : d.priority === 'Baja' ? '1' : '2',
        sprint: meta.sprint ?? '',
        asignado_a: meta.asignado_a ?? [],
        client_taker: meta.clientTaker ?? null,
        characterization_hu: meta.characterizationHu ?? '',
        has_impairment: false,
        epic_development: epicDevId,
        feature: meta.feature ?? '',
        initial_date: null,
        end_date: meta.endDate ?? null,
        status: meta.status ?? 1,
        is_planned: false,
      })
    }

    const res = await fetch(endpoint, { method: 'POST', headers, body })
    if (res.ok) {
      if (d.type === 'E') {
        // Épica creada → capturar ID y vincular HUs pendientes
        const created = await res.json()
        const epicKappaId = created.id
        const meta = JSON.parse(d.metadata || '{}')
        for (const huTitle of meta.linkedHuTitles || []) {
          const linkedDraft = drafts.value.find(x =>
            x.type !== 'E' && x.syncStatus === 'draft' &&
            x.title.toLowerCase().trim() === huTitle.toLowerCase().trim()
          )
          if (linkedDraft) {
            const linkedMeta = JSON.parse(linkedDraft.metadata || '{}')
            linkedMeta.epicDevelopment = String(epicKappaId)
            linkedDraft.metadata = JSON.stringify(linkedMeta)
            await dbSaveDraft(linkedDraft)
          }
        }
      } else {
        const created = await res.json()
        d.kappaId = created.id || undefined
      }
      await deleteDraft(d.id)
      await loadDrafts()
      await workItems.fetchWorkItems(project.value!.id)
      showNotif('success', `${d.type === 'E' ? 'Épica' : 'HU'} creada en KAPPA: ${d.title.slice(0, 80)}`)
    } else {
      const errorText = await res.text().catch(() => 'Error desconocido')
      console.error(`[Alpha] Error push a KAPPA (${endpoint}): ${res.status} — ${errorText}`)
      showNotif('error', `Error (${res.status}): ${errorText.slice(0, 200)}`)
      d.syncStatus = 'draft'
      await dbSaveDraft(d)
    }
  } catch (e: any) {
    console.error('[Alpha] Error en pushDraft:', e)
    showNotif('error', `Error de red: ${e.message}`)
    d.syncStatus = 'draft'
    await dbSaveDraft(d)
  } finally {
    pushingDraftId.value = null
    await loadDrafts()
    await loadQAPlans(project.value!.id)
    await workItems.fetchWorkItems(project.value!.id)
  }
}

async function dbSaveDraft(d: HuDraftRecord) {
  const { saveDraft } = await import('@/services/hu-drafts-db')
  await saveDraft(d)
}

watch(() => project.value?.id, () => { if (project.value) { loadDrafts(); loadQAPlans(project.value.id) } }, { immediate: false })

async function discardDraft(id: string) {
  await deleteDraft(id)
  await loadDrafts()
}

// ─── Project analysis — Two-phase ─────────────────────────
const phase = ref<'idle' | 'epics' | 'hus' | 'done'>('idle')
const analyzing = ref(false)
const analysisAbort = ref<AbortController | null>(null)
const analysisMessage = ref('')
const analysisResult = ref<{ saved: number; skipped: number } | null>(null)

function cancelAnalysis() {
  analysisAbort.value?.abort()
  analyzing.value = false
  analysisAbort.value = null
  analysisMessage.value = ''
  phase.value = 'idle'
}

// Obtener épicas que ya existen en KAPPA
function getExistingEpicNames(): string[] {
  return workItems.epics.map(e => (e._cleanName || e.name || e.title || '').toLowerCase().trim()).filter(Boolean)
}

// FASE 1: Generar épicas
async function runPhaseEpics() {
  if (!project.value) return
  phase.value = 'epics'
  analyzing.value = true
  analysisAbort.value = new AbortController()
  analysisResult.value = null
  analysisMessage.value = 'Analizando contexto y generando épicas...'

  try {
    const existingEpics = getExistingEpicNames()
    const result = await analyzeProjectEpics(
      project.value.id, project.value.name || '',
      workItems.userStories, existingEpics,
      analysisAbort.value?.signal,
      workItems.epics,
    )
    analysisMessage.value = result.rationale

    if (result.epics.length > 0) {
      const outcome = await saveEpicDrafts(project.value.id, result.epics, workItems.userStories)
      analysisResult.value = outcome
      await loadDrafts()
    } else {
      analysisResult.value = { saved: 0, skipped: 0 }
      analysisMessage.value = 'No se identificaron nuevas épicas necesarias.'
    }
  } catch (e: any) {
    if (e.name === 'AbortError' || e.message?.includes('aborted')) {
      analysisMessage.value = 'Análisis cancelado'
    } else {
      console.error('[Alpha] Phase 1 error:', e)
      analysisMessage.value = `Error: ${e.message}`
    }
    analysisResult.value = { saved: 0, skipped: 0 }
    phase.value = 'idle'
  } finally {
    analyzing.value = false
  }
}

// FASE 2: Generar HUs dentro de las épicas
async function runPhaseHUs() {
  if (!project.value) return
  phase.value = 'hus'
  analyzing.value = true
  analysisAbort.value = new AbortController()
  analysisResult.value = null
  analysisMessage.value = 'Generando HUs dentro de las épicas...'

  try {
    // Obtener las épicas confirmadas desde los drafts de tipo épica
    const epicDrafts = drafts.value.filter(d => d.type === 'E')
    const confirmedEpics = epicDrafts.map(d => ({
      name: d.title,
      description: d.description,
      linkedHuTitles: (() => { try { return JSON.parse(d.metadata || '{}').linkedHuTitles || [] } catch { return [] } })(),
    }))

    if (confirmedEpics.length === 0) {
      analysisMessage.value = 'No hay épicas en borrador. Primero generá y enviá las épicas a KAPPA.'
      analysisResult.value = { saved: 0, skipped: 0 }
      phase.value = 'idle'
      analyzing.value = false
      return
    }

    const result = await analyzeProjectHUs(
      project.value.id, project.value.name || '',
      workItems.userStories, confirmedEpics,
      analysisAbort.value?.signal,
    )
    analysisMessage.value = result.summary

    if (result.hus.length > 0) {
      const outcome = await saveHUDrafts(project.value.id, result.hus, workItems.userStories)
      analysisResult.value = outcome
      await loadDrafts()
      phase.value = 'done'
    } else {
      analysisResult.value = { saved: 0, skipped: 0 }
      analysisMessage.value = 'No se identificaron HUs nuevas. Todo parece cubierto.'
      phase.value = 'done'
    }
  } catch (e: any) {
    if (e.name === 'AbortError' || e.message?.includes('aborted')) {
      analysisMessage.value = 'Análisis cancelado'
    } else {
      console.error('[Alpha] Phase 2 error:', e)
      analysisMessage.value = `Error: ${e.message}`
    }
    analysisResult.value = { saved: 0, skipped: 0 }
    phase.value = 'idle'
  } finally {
    analyzing.value = false
  }
}

watch(
  () => projects.selectedId,
  async (id) => {
    if (id) {
      await workItems.fetchWorkItems(id)
      if (usersStore.users.length === 0) {
        usersStore.fetchAll()
      }
    }
  },
  { immediate: true }
)

// ─── Epic progress bar ───────────────────────────────
const epicProgress = computed(() => {
  const map = new Map<string, { total: number; done: number }>()
  for (const hu of workItems.userStories) {
    const epicCode = hu._epicCode || ''
    if (!epicCode) continue
    if (!map.has(epicCode)) map.set(epicCode, { total: 0, done: 0 })
    const entry = map.get(epicCode)!
    entry.total++
    const s = String(hu.status ?? '').toLowerCase()
    if (['done', 'completed', 'closed', 'finalizado', '5', '6', '7', 'qa-client', 'ready to deploy'].includes(s)) {
      entry.done++
    }
  }
  const result: Record<string, number> = {}
  for (const [code, { total, done }] of map) {
    result[code] = total > 0 ? Math.round((done / total) * 100) : 0
  }
  return result
})

function getEpicProgress(epic: any): number {
  const code = epic._epicCode
  return code ? epicProgress.value[code] ?? 0 : 0
}

const statusVariant = (status: unknown) => {
  const s = String(status ?? '').toLowerCase()
  if (['done', 'completed', 'closed', 'finalizado'].includes(s)) return 'secondary'
  if (['in_progress', 'doing', 'wip', 'active', 'in progress', 'en progreso'].includes(s)) return 'default'
  if (['blocked', 'bloqueado'].includes(s)) return 'destructive'
  if (s === 'true') return 'default'
  return 'outline'
}

const statusLabel = (status: unknown) => {
  const s = String(status ?? '').toLowerCase()
  if (s === 'true') return t('status.inProgress')
  if (['done', 'completed', 'closed', 'finalizado'].includes(s)) return t('status.completed')
  if (['in_progress', 'doing', 'wip', 'active', 'in progress', 'en progreso'].includes(s)) return t('status.inProgress')
  if (['blocked', 'bloqueado'].includes(s)) return t('status.blocked')
  if (['todo', 'por hacer'].includes(s)) return t('status.todo')
  if (['review', 'revisión'].includes(s)) return t('status.review')
  if (['testing', 'pruebas'].includes(s)) return t('status.testing')
  if (s === 'false') return t('status.todo')
  return String(status ?? '—')
}
</script>

<template>
  <div v-if="project" class="@container/main flex flex-1 flex-col gap-4 px-4 lg:px-6">
    <div class="flex flex-col gap-1">
      <h1 class="text-2xl font-bold tracking-tight">
        <span class="font-mono text-sm text-muted-foreground mr-2">#{{ project.id }}</span>
        {{ project.name }}
      </h1>
      <div class="flex items-center gap-2">
        <Badge v-if="project.key" variant="outline" class="text-xs">{{ project.key }}</Badge>
      </div>
    </div>

    <!-- Stats -->
    <div id="dashboard-stats" class="grid gap-3 @xl:grid-cols-2 @3xl:grid-cols-5">
      <Card id="dashboard-stats-epics" class="bg-gradient-to-t from-primary/5 to-card shadow-xs dark:bg-card">
        <CardHeader class="flex flex-row items-center justify-between space-y-0 pb-2">
          <CardTitle class="text-sm font-medium">{{ t('dashboard.epics') }}</CardTitle>
          <Layers class="size-4 text-muted-foreground" />
        </CardHeader>
        <CardContent>
          <div class="text-2xl font-bold">{{ workItems.totalEpics }}</div>
          <p class="text-xs text-muted-foreground">{{ t('dashboard.epicsSubtitle') }}</p>
        </CardContent>
      </Card>

      <Card id="dashboard-stats-hus" class="bg-gradient-to-t from-primary/5 to-card shadow-xs dark:bg-card">
        <CardHeader class="flex flex-row items-center justify-between space-y-0 pb-2">
          <CardTitle class="text-sm font-medium">{{ t('dashboard.hus') }}</CardTitle>
          <FileText class="size-4 text-muted-foreground" />
        </CardHeader>
        <CardContent>
          <div id="dashboard-stats-hus-count" class="text-2xl font-bold">{{ workItems.totalHUs }}</div>
          <p class="text-xs text-muted-foreground">{{ t('dashboard.husSubtitle') }}</p>
        </CardContent>
      </Card>

      <Card id="dashboard-stats-inprogress" class="bg-gradient-to-t from-primary/5 to-card shadow-xs dark:bg-card">
        <CardHeader class="flex flex-row items-center justify-between space-y-0 pb-2">
          <CardTitle class="text-sm font-medium">{{ t('dashboard.inProgress') }}</CardTitle>
          <Activity class="size-4 text-muted-foreground" />
        </CardHeader>
        <CardContent>
          <div class="text-2xl font-bold">{{ workItems.inProgressHUs }}</div>
          <p class="text-xs text-muted-foreground">{{ t('dashboard.activeHus') }}</p>
        </CardContent>
      </Card>

      <Card id="dashboard-stats-qa" class="bg-gradient-to-t from-primary/5 to-card shadow-xs dark:bg-card">
        <CardHeader class="flex flex-row items-center justify-between space-y-0 pb-2">
          <CardTitle class="text-sm font-medium">QA</CardTitle>
          <CheckCircle2 class="size-4 text-muted-foreground" />
        </CardHeader>
        <CardContent>
          <div class="text-2xl font-bold">{{ qaMetrics.total }}</div>
          <p class="text-xs text-muted-foreground">Planes QA · {{ qaMetrics.totalCases }} casos</p>
          <div class="flex gap-2 mt-1.5 text-[10px]">
            <span class="text-green-600 dark:text-green-400">{{ qaMetrics.auto }} auto</span>
            <span class="text-amber-600 dark:text-amber-400">{{ qaMetrics.parcial }} parcial</span>
            <span class="text-red-600 dark:text-red-400">{{ qaMetrics.manual }} manual</span>
          </div>
        </CardContent>
      </Card>

      <Card id="dashboard-stats-sessions" class="bg-gradient-to-t from-primary/5 to-card shadow-xs dark:bg-card">
        <CardHeader class="flex flex-row items-center justify-between space-y-0 pb-2">
          <CardTitle class="text-sm font-medium">{{ t('dashboard.sessions') }}</CardTitle>
          <Clock class="size-4 text-muted-foreground" />
        </CardHeader>
        <CardContent>
          <div class="text-2xl font-bold">{{ workItems.totalSessions }}</div>
          <p class="text-xs text-muted-foreground">{{ t('dashboard.sessionsSubtitle') }}</p>
        </CardContent>
      </Card>
    </div>

    <!-- Priorizador Diario -->
    <PrioritizerCard />

    <!-- Curva S -->
    <SCurveChart v-if="project" :project-id="project.id" />

    <!-- AI Chat -->
    <AiProjectChat
      :project-id="project.id"
      :project-name="project.name ?? ''"
      :project-description="project.description ?? ''"
      :epic-count="workItems.totalEpics"
      :hu-count="workItems.totalHUs"
      @navigate-settings="emit('navigate-settings')"
    />

    <!-- Project Analysis — Two-phase -->
    <Card id="dashboard-analysis" class="border-dashed">
      <CardHeader class="pb-3 flex flex-row items-center justify-between">
        <CardTitle class="text-sm font-medium flex items-center gap-2">
          <Sparkles class="size-4" />
          Análisis del proyecto
        </CardTitle>
        <div v-if="!analyzing" class="flex gap-2">
          <Button
            size="sm"
            variant="outline"
            :disabled="analyzing || phase === 'done'"
            @click="runPhaseEpics()"
          >
            <Sparkles class="size-3 mr-1" />
            1. Generar Épicas
          </Button>
          <Button
            size="sm"
            :disabled="analyzing || phase === 'idle'"
            @click="runPhaseHUs()"
          >
            <Sparkles class="size-3 mr-1" />
            2. Generar HUs
          </Button>
        </div>
        <Button
          v-if="analyzing"
          size="sm"
          variant="outline"
          @click="cancelAnalysis()"
        >
          Cancelar
        </Button>
      </CardHeader>
      <CardContent class="space-y-3">
        <div v-if="analyzing" class="flex items-center gap-2 text-sm text-muted-foreground">
          <Loader2 class="size-4 animate-spin" />
          {{ analysisMessage }}
        </div>
        <div v-if="analysisResult" class="space-y-2 text-sm">
          <p class="text-muted-foreground">{{ analysisMessage }}</p>
          <div class="flex items-center gap-3 text-xs">
            <span v-if="analysisResult.saved > 0" class="text-green-600 dark:text-green-400 flex items-center gap-1">
              <CheckCircle2 class="size-3" /> {{ analysisResult.saved }} borradores guardados
            </span>
            <span v-if="analysisResult.skipped > 0" class="text-amber-600 dark:text-amber-400 flex items-center gap-1">
              {{ analysisResult.skipped }} duplicadas saltadas
            </span>
            <span v-if="analysisResult.saved === 0 && analysisResult.skipped === 0" class="text-muted-foreground">
              {{ phase === 'epics' ? 'No se requieren nuevas épicas.' : phase === 'hus' ? 'No se requieren nuevas HUs.' : '' }}
            </span>
          </div>
        </div>
      </CardContent>
    </Card>

    <!-- Borradores (web) -->
    <Card v-if="drafts.length > 0" id="dashboard-drafts" class="border-dashed">
      <CardHeader class="pb-3 flex flex-row items-center justify-between">
        <CardTitle class="text-sm font-medium">{{ drafts.length }} borradores pendientes</CardTitle>
      </CardHeader>
      <CardContent class="space-y-2">
        <div v-for="d in drafts" :key="d.id" class="flex items-start gap-3 p-2 rounded-lg border text-sm">
          <div class="flex-1 min-w-0">
            <div class="flex items-center gap-2">
              <Badge variant="outline" class="text-[10px]" :class="d.type === 'E' ? 'border-purple-300 text-purple-600' : ''">
                {{ d.type === 'E' ? 'Épica' : 'HU' }}
              </Badge>
              <span v-if="d.type === 'E'" class="font-mono text-[10px] text-muted-foreground shrink-0">[{{ getEpicCode(d) }}]</span>
              <span v-else class="font-mono text-[10px] text-muted-foreground shrink-0">{{ getItemCode(d) }}</span>
              <p class="font-medium">{{ d.type === 'E' ? stripEpicTitle(d.title) : d.title }}</p>
            </div>
            <div v-if="d.type === 'E' && d.metadata" class="text-xs text-muted-foreground mt-0.5">
              <span v-if="getEpicLinkedHUs(d).length > 0">
                HUs vinculadas: {{ getEpicLinkedHUs(d).join(', ') }}
              </span>
              <span v-else class="italic">Sin HUs vinculadas</span>
            </div>
            <p v-if="d.description && d.type !== 'E'" class="text-xs text-muted-foreground truncate">{{ d.description }}</p>
            <div class="flex items-center gap-2 mt-1">
              <Badge variant="outline" class="text-[10px]">{{ d.priority }}</Badge>
              <Badge variant="outline" class="text-[10px] font-mono" :class="d.syncStatus === 'pushed' ? 'text-green-600 border-green-300' : ''">
                {{ d.syncStatus === 'pushing' ? 'Enviando...' : d.syncStatus === 'pushed' ? `Enviada (ID ${d.kappaId || '?'})` : 'Borrador' }}
              </Badge>
            </div>
          </div>
          <div class="flex gap-1 shrink-0">
            <Button v-if="d.syncStatus !== 'pushed'" size="sm" variant="outline" class="text-xs h-7"
              :disabled="pushingDraftId === d.id"
              @click="pushDraft(d)"
            >
              <Loader2 v-if="pushingDraftId === d.id" class="size-3 mr-1 animate-spin" />
              <Send v-else class="size-3 mr-1" />
              {{ d.type === 'E' ? 'Epica' : 'HU' }}
            </Button>
            <Button size="sm" variant="outline" class="text-xs h-7"
              :disabled="generatingQA === d.id"
              @click="generateQA(d)"
            >
              <Loader2 v-if="generatingQA === d.id" class="size-3 mr-1 animate-spin" />
              QA
            </Button>
            <Button size="sm" variant="ghost" class="text-xs h-7"
              @click="discardDraft(d.id)"
            >✕</Button>
          </div>
        </div>
      </CardContent>
    </Card>

    <!-- Epics Table -->
    <Card v-if="workItems.epics.length > 0" id="dashboard-epics-table">
      <CardHeader class="pb-2">
        <CardTitle class="text-sm font-medium">{{ t('dashboard.epicsCount', { count: workItems.totalEpics }) }}</CardTitle>
      </CardHeader>
      <CardContent>
        <Table>
          <TableHeader>
            <TableRow>
              <TableHead class="w-[80px]">{{ t('dashboard.code') }}</TableHead>
              <TableHead class="w-[60px]">{{ t('users.role') }}</TableHead>
              <TableHead>{{ t('dashboard.title') }}</TableHead>
              <TableHead class="w-[60px] text-center">Desc</TableHead>
              <TableHead class="w-[140px]">Progreso</TableHead>
            </TableRow>
          </TableHeader>
          <TableBody>
            <TableRow v-for="epic in workItems.epics" :key="epic.id">
              <TableCell class="font-mono text-xs text-muted-foreground">{{ epic._epicCode || epic.code || `EP-${epic.id}` }}</TableCell>
              <TableCell>
                <span class="inline-flex items-center rounded px-1 py-0.5 text-[10px] font-bold" :class="getTypeColor(epic._itemType)">{{ getTypeLabel(epic._itemType) }}</span>
              </TableCell>
              <TableCell class="text-sm">{{ epic._cleanName || epic.name || epic.title || t('dashboard.epicFallback', { id: epic.id }) }}</TableCell>
              <TableCell class="text-center">
                <Dialog v-if="epic.description">
                  <DialogTrigger as-child>
                    <Button variant="ghost" size="icon" class="size-6" @click="openDescription(epic._cleanName || epic.name || '', epic.description || '')">
                      <Eye class="size-3.5 text-muted-foreground" />
                    </Button>
                  </DialogTrigger>
                </Dialog>
                <span v-else class="text-xs text-muted-foreground/40">—</span>
              </TableCell>
              <TableCell class="text-xs">
                <div class="flex items-center gap-2">
                  <div class="flex-1 h-2 rounded-full bg-muted overflow-hidden">
                    <div
                      class="h-full rounded-full transition-all duration-300"
                      :class="getEpicProgress(epic) >= 100 ? 'bg-green-500' : getEpicProgress(epic) > 0 ? 'bg-primary' : ''"
                      :style="{ width: getEpicProgress(epic) + '%' }"
                    />
                  </div>
                  <span class="font-mono text-[10px] text-muted-foreground w-8 text-right">{{ getEpicProgress(epic) }}%</span>
                </div>
              </TableCell>
            </TableRow>
          </TableBody>
        </Table>
      </CardContent>
    </Card>

    <!-- QA Plans -->
    <Card v-if="qaPlans.length > 0" id="dashboard-qa-plans">
      <CardHeader class="pb-2">
        <CardTitle class="text-sm font-medium flex items-center gap-2">
          <CheckCircle2 class="size-4" />
          Planes QA · {{ qaPlans.length }}
        </CardTitle>
      </CardHeader>
      <CardContent class="space-y-2">
        <div v-for="p in qaPlans" :key="p.id" class="border rounded-lg p-3 text-sm">
          <div class="flex items-center justify-between cursor-pointer" @click="toggleQAExpand(p.id)">
            <span class="font-medium">{{ p.huTitle }}</span>
            <ChevronDown class="size-4 text-muted-foreground transition-transform" :class="expandedQA === p.id ? 'rotate-180' : ''" />
          </div>
          <div v-if="expandedQA === p.id" class="mt-2 space-y-2">
            <template v-if="parseQAPlan(p) as HUQAPlan">
              <div class="text-xs text-muted-foreground">{{ (parseQAPlan(p) as HUQAPlan).acceptanceCriteria?.length || 0 }} criterios, {{ (parseQAPlan(p) as HUQAPlan).testCases.length }} casos de prueba</div>
              <table class="w-full text-xs">
                <thead><tr class="text-muted-foreground"><th class="text-left py-1">Prueba</th><th class="text-left py-1">Tipo</th><th class="text-left py-1">Herramienta</th></tr></thead>
                <tbody>
                  <tr v-for="(tc, i) in (parseQAPlan(p) as HUQAPlan).testCases" :key="i" class="border-t">
                    <td class="py-1 pr-2">{{ tc.description }}</td>
                    <td class="py-1 pr-2"><Badge variant="outline" :class="qaBadgeColor(tc.automatizable)" class="text-[10px]">{{ tc.automatizable }}</Badge></td>
                    <td class="py-1 text-muted-foreground">{{ tc.tool }}</td>
                  </tr>
                </tbody>
              </table>
            </template>
          </div>
        </div>
      </CardContent>
    </Card>

    <!-- Borradores (Tauri) -->
    <HuDrafts v-if="project" :initiative-id="project.id" />

    <!-- HUs Table -->
    <Card id="dashboard-hus-table">
      <CardHeader class="flex flex-row items-center justify-between pb-2">
        <CardTitle class="text-sm font-medium">{{ t('dashboard.userStoriesTitle') }}</CardTitle>
        <Badge variant="outline" class="text-xs">{{ t('dashboard.husCount', { count: filteredHUs.length }) }} / {{ workItems.userStories.length }}</Badge>
      </CardHeader>
      <CardContent class="space-y-3">
        <!-- Filters -->
        <div class="flex items-center gap-2 flex-wrap justify-end">
          <Select v-model="filterStatus">
            <SelectTrigger class="h-8 w-[130px] text-xs"><SelectValue :placeholder="t('dashboard.status')" /></SelectTrigger>
            <SelectContent>
              <SelectItem value="__all" class="text-xs">{{ t('dashboard.filterAll') }}</SelectItem>
              <SelectItem value="todo" class="text-xs">{{ t('status.todo') }}</SelectItem>
              <SelectItem value="in_progress" class="text-xs">{{ t('status.inProgress') }}</SelectItem>
              <SelectItem value="done" class="text-xs">{{ t('status.completed') }}</SelectItem>
              <SelectItem value="blocked" class="text-xs">{{ t('status.blocked') }}</SelectItem>
              <SelectItem value="review" class="text-xs">{{ t('status.review') }}</SelectItem>
              <SelectItem value="testing" class="text-xs">{{ t('status.testing') }}</SelectItem>
            </SelectContent>
          </Select>
          <Select v-model="filterPriority">
            <SelectTrigger class="h-8 w-[120px] text-xs"><SelectValue :placeholder="t('dashboard.priority')" /></SelectTrigger>
            <SelectContent>
              <SelectItem value="__all" class="text-xs">{{ t('dashboard.filterAll') }}</SelectItem>
              <SelectItem value="alta" class="text-xs">Alta</SelectItem>
              <SelectItem value="media" class="text-xs">Media</SelectItem>
              <SelectItem value="baja" class="text-xs">Baja</SelectItem>
              <SelectItem value="critical" class="text-xs">Crítica</SelectItem>
              <SelectItem value="urgente" class="text-xs">Urgente</SelectItem>
              <SelectItem value="3" class="text-xs">Alta (3)</SelectItem>
              <SelectItem value="2" class="text-xs">Media (2)</SelectItem>
              <SelectItem value="1" class="text-xs">Baja (1)</SelectItem>
            </SelectContent>
          </Select>
          <Select v-model="filterAssigned">
            <SelectTrigger class="h-8 w-[150px] text-xs"><SelectValue :placeholder="t('dashboard.assignedTo')" /></SelectTrigger>
            <SelectContent>
              <SelectItem value="__all" class="text-xs">{{ t('dashboard.filterAll') }}</SelectItem>
              <SelectItem value="__none" class="text-xs">{{ t('dashboard.unassigned') }}</SelectItem>
              <SelectItem v-for="m in assignedUsers" :key="m.id" :value="String(m.id)" class="text-xs">{{ m.name }}</SelectItem>
            </SelectContent>
          </Select>
        </div>

        <Table v-if="filteredHUs.length > 0">
          <TableHeader>
            <TableRow>
              <TableHead class="w-[80px]">{{ t('dashboard.code') }}</TableHead>
              <TableHead class="w-[60px]">{{ t('users.role') }}</TableHead>
              <TableHead>{{ t('dashboard.title') }}</TableHead>
              <TableHead class="w-[50px] text-center">Desc</TableHead>
              <TableHead class="w-[50px] text-center">SP</TableHead>
              <TableHead class="w-[110px]">{{ t('dashboard.status') }}</TableHead>
              <TableHead class="w-[90px]">{{ t('dashboard.priority') }}</TableHead>
              <TableHead class="w-[140px]">{{ t('dashboard.assignedTo') }}</TableHead>
            </TableRow>
          </TableHeader>
          <TableBody>
            <TableRow v-for="hu in filteredHUs" :key="hu.id">
              <TableCell class="font-mono text-xs text-muted-foreground">{{ hu.code || `HU-${hu.id}` }}</TableCell>
              <TableCell>
                <span class="inline-flex items-center rounded px-1 py-0.5 text-[10px] font-bold" :class="getTypeColor(hu._itemType)">{{ getTypeLabel(hu._itemType) }}</span>
              </TableCell>
              <TableCell class="text-sm flex items-center gap-1 py-3">
                <AlertTriangle v-if="hu.has_impairment" class="size-3.5 text-amber-500 shrink-0" title="Tiene impedimentos pendientes" />
                <span>{{ hu._cleanTitle || hu.title }}</span>
                <span v-if="hu._criteriaList?.length" class="group relative inline-flex shrink-0 cursor-help ml-1">
                  <Info class="size-3.5 text-muted-foreground hover:text-foreground transition-colors" />
                  <div class="absolute bottom-full left-0 mb-2 w-72 p-3 rounded-lg border bg-popover text-popover-foreground text-xs shadow-md opacity-0 group-hover:opacity-100 transition-opacity z-50 pointer-events-none">
                    <p class="font-semibold mb-1.5 text-[11px] uppercase tracking-wider text-muted-foreground">Criterios de aceptación</p>
                    <ol class="list-decimal list-inside space-y-1 text-[11px]"><li v-for="(c, i) in hu._criteriaList" :key="i">{{ c }}</li></ol>
                  </div>
                </span>
              </TableCell>
              <TableCell class="text-center">
                <Button v-if="hu.description" variant="ghost" size="icon" class="size-6" @click="openDescription(hu._cleanTitle || hu.title || '', hu.description)">
                  <Eye class="size-3.5 text-muted-foreground" />
                </Button>
                <span v-else class="text-xs text-muted-foreground/40">—</span>
              </TableCell>
              <TableCell class="text-center text-xs font-mono text-muted-foreground">{{ hu.story_points ?? '—' }}</TableCell>
              <TableCell><Badge :variant="statusVariant(hu.status || '')" class="text-xs capitalize">{{ hu._statusName || statusLabel(hu.status || '') }}</Badge></TableCell>
              <TableCell><Badge :variant="priorityVariant(hu.priority)" class="text-xs">{{ priorityLabel(hu.priority) }}</Badge></TableCell>
              <TableCell>
                <span v-if="assignedName(hu)" class="text-xs">{{ assignedName(hu) }}</span>
                <span v-else class="text-xs text-muted-foreground italic">{{ t('dashboard.unassigned') }}</span>
              </TableCell>
            </TableRow>
          </TableBody>
        </Table>
        <p v-else class="text-xs text-muted-foreground/50 italic text-center py-4">{{ t('dashboard.noUserStories') }}</p>
      </CardContent>
    </Card>

    <!-- Description Modal -->
    <Dialog v-model:open="descModalOpen">
      <DialogContent class="sm:max-w-[700px] max-h-[80vh] overflow-y-auto">
        <DialogHeader>
          <DialogTitle class="text-sm">{{ descModal?.title }}</DialogTitle>
        </DialogHeader>
        <div class="text-xs leading-relaxed whitespace-pre-wrap text-muted-foreground" v-html="descModal?.content"></div>
      </DialogContent>
    </Dialog>

    <!-- Inline notification (funciona en Tauri) -->
    <div
      v-if="notification"
      class="fixed bottom-4 right-4 z-50 flex items-start gap-3 p-3 rounded-lg border bg-card border-l-[3px] text-xs shadow-lg max-w-sm"
      :class="notification.type === 'success' ? 'border-l-green-500' : 'border-l-red-500'"
    >
      <CheckCircle2 v-if="notification.type === 'success'" class="size-4 text-green-500 shrink-0 mt-0.5" />
      <XCircle v-else class="size-4 text-red-500 shrink-0 mt-0.5" />
      <div class="flex-1 min-w-0">
        <p class="font-medium text-foreground">{{ notification.type === 'success' ? 'Completado' : 'Error' }}</p>
        <p class="text-muted-foreground mt-0.5">{{ notification.message }}</p>
      </div>
      <button class="text-muted-foreground hover:text-foreground shrink-0" @click="notification = null">&times;</button>
    </div>
  </div>

  <div v-else class="flex flex-1 items-center justify-center">
    <div class="text-center space-y-2">
      <p v-if="projects.loading" class="text-sm text-muted-foreground">{{ t('common.loading') }}</p>
      <p v-else class="text-sm text-muted-foreground">{{ t('dashboard.selectProject') }}</p>
    </div>
  </div>
</template>
