"use client" import { useState, useEffect } from "react" import { DashboardLayout } from "@/components/dashboard-layout" import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card" import { Badge } from "@/components/ui/badge" import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table" import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select" import { BarChart3, User, Calendar, TrendingUp, Sprout, Package, Filter, ArrowRight } from "lucide-react" import { apiFetch } from "@/lib/apiutils" import { PaginationControl } from "@/components/ui/pagination-control" interface Productor { id: string nombre: string cuit?: string razon_social?: string email?: string tipo_produccion?: string } interface Establecimiento { id: string nombre: string ubicacion: string productor?: Productor } interface Campana { id: string nombre: string cultivo: string hectareas: number // Comes from Establishment size? Or Campaign specific? rindeQQha?: number estado: string // "activa" | "finalizada" fecha_inicio: string fecha_fin: string } interface Producto { nombre_producto?: string nombre?: string dosis: number unidad_medida?: string unidad?: string } interface RecetaItem { id: string labor: string rinde?: number lote?: { nombre: string } cultivo?: { nombre: string } productos: Producto[] } interface Receta { id: string fecha: string observaciones?: string superficie: number items: RecetaItem[] } // Extended Campana for detailed view interface CampanaDetalle extends Campana { establecimiento: Establecimiento recetas: Receta[] } export default function AnalisisProduccionPage() { // Filters State const [establecimientos, setEstablecimientos] = useState([]) const [selectedEstablecimientoId, setSelectedEstablecimientoId] = useState("") const [campanas, setCampanas] = useState([]) const [selectedCampanaId, setSelectedCampanaId] = useState("") const [cultivosDisponibles, setCultivosDisponibles] = useState([]) const [selectedCultivo, setSelectedCultivo] = useState("todos") // "todos" or specific crop name // Data State const [analisisData, setAnalisisData] = useState(null) const [isLoading, setIsLoading] = useState(false) const [currentPage, setCurrentPage] = useState(1) const ITEMS_PER_PAGE = 3 // Fetch Establecimientos on mount useEffect(() => { const fetchEstablecimientos = async () => { try { const res = await apiFetch("/establecimientos") if (res.ok) { const data = await res.json() setEstablecimientos(data.data || []) } } catch (e) { console.error(e) } } fetchEstablecimientos() }, []) // Fetch Campanas when Establecimiento selected useEffect(() => { // Reset selection when establishment changes setSelectedCampanaId("") setCampanas([]) setAnalisisData(null) if (selectedEstablecimientoId) { const fetchCampanas = async () => { try { // Pass limit=-1 or high number if backend supports it to get all? // CampanaController default is 10. We might need all relevant ones. // Let's assume pagination is default 10 but we might want more. // For now just standard call. // Backend CampanaController index handles 'establecimiento_id' const res = await apiFetch(`/campanas?establecimiento_id=${selectedEstablecimientoId}&limit=50`) if (res.ok) { const data = await res.json() setCampanas(data.data || []) } } catch (e) { console.error(e) } } fetchCampanas() } }, [selectedEstablecimientoId]) // Fetch Analysis Data (Campana Detail) when BOTH selected useEffect(() => { if (selectedCampanaId && selectedEstablecimientoId) { const fetchDetail = async () => { setIsLoading(true) try { const res = await apiFetch(`/campanas/${selectedCampanaId}?establecimiento_id=${selectedEstablecimientoId}`) if (res.ok) { const data = await res.json() setAnalisisData(data) // Extract unique crops from recipes' items const crops = Array.from(new Set(data.recetas.flatMap((r: any) => r.items?.map((i: any) => i.cultivo?.nombre || "Desconocido") || []))) setCultivosDisponibles(crops as string[]) setSelectedCultivo("todos") setCurrentPage(1) // Reset page on new data } } catch (e) { console.error(e) } finally { setIsLoading(false) } } fetchDetail() } else { setAnalisisData(null) setCultivosDisponibles([]) } }, [selectedCampanaId, selectedEstablecimientoId]) const getStatusColor = (status: string) => { const colors = { activa: "bg-green-100 text-green-800 border-green-300", finalizada: "bg-gray-100 text-gray-800 border-gray-300", } return colors[status as keyof typeof colors] || colors.activa } const getFilteredItems = () => { if (!analisisData) return [] let items = analisisData.recetas.flatMap((r: any) => (r.items || []).map((item: any) => ({ item: item, receta: r }))) if (selectedCultivo !== "todos") { items = items.filter(x => (x.item.cultivo?.nombre || "Desconocido") === selectedCultivo) } // Sort by descending date return items.sort((a, b) => new Date(b.receta.fecha).getTime() - new Date(a.receta.fecha).getTime()) } const calcularInsumosTotal = (filteredItems: any[]) => { const insumosMap = new Map() filteredItems.forEach(({ item, receta }) => { (item.productos || []).forEach((prod: any) => { const nombre = prod.nombre_producto || prod.nombre || "Desconocido" const unidad = prod.unidad || prod.unidad_medida || "-" const key = `${nombre}-${unidad}` if (!insumosMap.has(key)) { insumosMap.set(key, { cantidad: 0, unidad: unidad }) } const current = insumosMap.get(key)! const superficie = receta.superficie || 0 current.cantidad += prod.dosis * superficie }) }) return Array.from(insumosMap.entries()).map(([key, value]) => ({ nombre: key.split("-")[0], unidad: value.unidad, total: value.cantidad })) } const filteredItems = getFilteredItems() const totalItems = filteredItems.length const lastPage = Math.ceil(totalItems / ITEMS_PER_PAGE) || 1 const paginatedItems = filteredItems.slice((currentPage - 1) * ITEMS_PER_PAGE, currentPage * ITEMS_PER_PAGE) return (

Análisis de Producción

Analiza el rendimiento y costos por Campaña y Establecimiento

{/* Panel izquierdo: Filtros */}
Filtros
{analisisData && cultivosDisponibles.length > 0 && (
)}
{/* Show Producer Card only if Analysis fetches */} {analisisData && analisisData.establecimiento.productor && ( Productor
{analisisData.establecimiento.productor.nombre} {analisisData.establecimiento.productor.razon_social}
{analisisData.establecimiento.productor.cuit && (
CUIT: {analisisData.establecimiento.productor.cuit}
)} {analisisData.establecimiento.productor.email && (
Email: {analisisData.establecimiento.productor.email}
)} {analisisData.establecimiento.productor.tipo_produccion && (
Tipo: {analisisData.establecimiento.productor.tipo_produccion}
)}
)}
{/* Panel derecho: Detalle */}
{isLoading ? (
) : analisisData ? (
{/* Información de la campaña */} {analisisData.nombre} Detalle de campaña en {analisisData.establecimiento.nombre}

Cultivo

{selectedCultivo === "todos" ? cultivosDisponibles.join(", ") : selectedCultivo}

Período

{new Date(analisisData.fecha_inicio).getFullYear()}/{new Date(analisisData.fecha_fin).getFullYear()}

Superficie

{analisisData.hectareas} ha

Estado

{analisisData.estado === "activa" ? "Activa" : "Finalizada"}
{/* Labores / Recetas */} Historial de Aplicaciones Recetas agronómicas aplicadas en esta campaña {filteredItems.length === 0 ? (

No hay labores registradas para esta selección

) : (
{paginatedItems.map((data: any, index: number) => { const { item, receta } = data return (
{item.labor || "Aplicación"} en {item.lote?.nombre || "General"} {item.cultivo?.nombre && ( {item.cultivo.nombre} )} {item.labor === 'Cosecha' && item.rinde !== undefined && item.rinde !== null && ( Rinde: {item.rinde} qq/ha )}
{new Date(receta.fecha).toLocaleDateString("es-AR")}

{receta.observaciones || "Sin observaciones"}

{item.productos && item.productos.length > 0 && (

Productos:

{item.productos.map((prod: any, idx: number) => (
{prod.nombre_producto || prod.nombre}
{prod.dosis} {prod.unidad || prod.unidad_medida}
))}
)}
) })}
)} {filteredItems.length > ITEMS_PER_PAGE && (
)} {/* Insumos Utilizados - Always shown */} Insumos Utilizados Listado de productos aplicados {filteredItems.length === 0 ? (

Sin datos de insumos

) : (
Producto Total Usado Unidad {calcularInsumosTotal(filteredItems).map((insumo, idx) => ( {insumo.nombre} {insumo.total.toLocaleString("es-AR", { minimumFractionDigits: 2, maximumFractionDigits: 2 })} {insumo.unidad} ))}
)}
) : (

Comienza el Análisis

Selecciona un Establecimiento y una Campaña en los filtros de la izquierda para ver el reporte detallado.

)}
) }