<?php
namespace App\Http\Controllers\Reports;

use App\Http\Controllers\Controller;
use App\Models\Ticket;
use App\Models\TicketStatus;
use App\Models\TicketPriority;
use App\Models\TicketCategory;
use App\Models\User;
use App\Models\Asset;
use App\Models\Department;
use Carbon\Carbon;
use Illuminate\Http\Request;

class ReportController extends Controller
{
    public function __construct()
    {
        // Solo admins, jefes y superadmin
    }

    // ── Panel principal de reportes ───────────────────────────────────────────
    public function index()
    {
        abort_unless(auth()->user()->hasAnyRole(['admin','superadmin','jefe_soporte']), 403);
        return view('reports.index');
    }

    // ── Reporte de tickets ────────────────────────────────────────────────────
    public function tickets(Request $request)
    {
        abort_unless(auth()->user()->hasAnyRole(['admin','superadmin','jefe_soporte']), 403);

        $from  = $request->input('from', now()->startOfMonth()->format('Y-m-d'));
        $to    = $request->input('to',   now()->format('Y-m-d'));
        $agent = $request->input('agent');

        $query = Ticket::with(['status','priority','category','requester','assignee'])
            ->whereBetween('created_at', [
                Carbon::parse($from)->startOfDay(),
                Carbon::parse($to)->endOfDay(),
            ])
            ->when($agent, fn($q) => $q->where('assignee_id', $agent));

        $tickets = $query->orderBy('created_at', 'desc')->get();

        // ── Métricas del período ──────────────────────────────────────────────
        $metrics = [
            'total'          => $tickets->count(),
            'open'           => $tickets->filter(fn($t) => !$t->status->is_final)->count(),
            'closed'         => $tickets->filter(fn($t) => $t->status->is_final)->count(),
            'sla_breached'   => $tickets->where('sla_resolution_breached', true)->count(),
            'avg_resolution' => $this->avgResolutionHours($tickets),
            'satisfaction'   => $this->avgSatisfaction($tickets),
        ];

        $slaCompliance = $metrics['closed'] > 0
            ? round((($metrics['closed'] - $metrics['sla_breached']) / $metrics['closed']) * 100)
            : 100;

        // ── Por prioridad ─────────────────────────────────────────────────────
        $byPriority = $tickets->groupBy('priority.name')
            ->map(fn($g) => ['count' => $g->count(), 'color' => $g->first()->priority->color]);

        // ── Por estado ────────────────────────────────────────────────────────
        $byStatus = $tickets->groupBy('status.name')
            ->map(fn($g) => ['count' => $g->count(), 'color' => $g->first()->status->color]);

        // ── Por categoría ─────────────────────────────────────────────────────
        $byCategory = $tickets->groupBy(fn($t) => $t->category?->name ?? 'Sin categoría')
            ->map(fn($g) => $g->count())
            ->sortDesc()
            ->take(8);

        // ── Por agente ────────────────────────────────────────────────────────
        $byAgent = $tickets->groupBy(fn($t) => $t->assignee?->name ?? 'Sin asignar')
            ->map(fn($g) => [
                'total'    => $g->count(),
                'closed'   => $g->filter(fn($t) => $t->status->is_final)->count(),
                'breached' => $g->where('sla_resolution_breached', true)->count(),
                'avg_sat'  => $this->avgSatisfaction($g),
            ])
            ->sortByDesc('total');

        // ── Tendencia diaria ──────────────────────────────────────────────────
        $daily = [];
        $current = Carbon::parse($from);
        $end     = Carbon::parse($to);
        while ($current->lte($end)) {
            $dateStr = $current->format('Y-m-d');
            $daily[] = [
                'date'    => $current->format('d/m'),
                'created' => $tickets->filter(fn($t) => $t->created_at->format('Y-m-d') === $dateStr)->count(),
                'closed'  => $tickets->filter(fn($t) => $t->closed_at?->format('Y-m-d') === $dateStr)->count(),
            ];
            $current->addDay();
        }

        $agents = User::role(['agente','jefe_soporte','admin','superadmin'])->orderBy('name')->get();

        return view('reports.tickets', compact(
            'tickets','metrics','slaCompliance','byPriority','byStatus',
            'byCategory','byAgent','daily','agents','from','to','agent'
        ));
    }

    // ── Reporte de SLA ────────────────────────────────────────────────────────
    public function sla(Request $request)
    {
        abort_unless(auth()->user()->hasAnyRole(['admin','superadmin','jefe_soporte']), 403);

        $from = $request->input('from', now()->startOfMonth()->format('Y-m-d'));
        $to   = $request->input('to',   now()->format('Y-m-d'));

        $tickets = Ticket::with(['status','priority','assignee'])
            ->whereNotNull('sla_resolution_due')
            ->whereBetween('created_at', [
                Carbon::parse($from)->startOfDay(),
                Carbon::parse($to)->endOfDay(),
            ])
            ->get();

        // SLA por prioridad
        $byPriority = TicketPriority::active()->get()->map(function($priority) use ($tickets) {
            $group    = $tickets->where('priority_id', $priority->id);
            $closed   = $group->filter(fn($t) => $t->status->is_final);
            $breached = $group->where('sla_resolution_breached', true);
            $onTime   = $closed->where('sla_resolution_breached', false);
            return [
                'name'       => $priority->name,
                'color'      => $priority->color,
                'total'      => $group->count(),
                'closed'     => $closed->count(),
                'breached'   => $breached->count(),
                'on_time'    => $onTime->count(),
                'compliance' => $closed->count() > 0
                    ? round(($onTime->count() / $closed->count()) * 100) : 100,
                'sla_hours'  => $priority->sla_resolution_hours,
            ];
        });

        // Tickets en breach activos
        $activeBreach = Ticket::with(['priority','assignee','requester'])
            ->open()
            ->where('sla_resolution_breached', true)
            ->orderBy('sla_resolution_due')
            ->get();

        // Tickets próximos a vencer (2h)
        $warning = Ticket::with(['priority','assignee','requester'])
            ->open()
            ->whereNotNull('sla_resolution_due')
            ->where('sla_resolution_due', '>', now())
            ->where('sla_resolution_due', '<=', now()->addHours(4))
            ->orderBy('sla_resolution_due')
            ->get();

        return view('reports.sla', compact('byPriority','activeBreach','warning','from','to'));
    }

    // ── Reporte de inventario ─────────────────────────────────────────────────
    public function inventory(Request $request)
    {
        abort_unless(auth()->user()->hasAnyRole(['admin','superadmin','jefe_soporte']), 403);

        $assets = Asset::with(['category','model.manufacturer','assignedUser','department'])
            ->when($request->category, fn($q) => $q->where('category_id', $request->category))
            ->when($request->status,   fn($q) => $q->where('status', $request->status))
            ->orderBy('code')
            ->get();

        $byCategory = $assets->groupBy('category.name')
            ->map(fn($g) => [
                'count'      => $g->count(),
                'active'     => $g->where('status','active')->count(),
                'value'      => $g->sum('purchase_price'),
                'color'      => $g->first()->category->color,
            ])->sortByDesc('count');

        $byStatus = collect(Asset::$statuses)->map(function($s, $key) use ($assets) {
            return ['label' => $s['label'], 'count' => $assets->where('status', $key)->count()];
        });

        $totalValue      = $assets->sum('purchase_price');
        $warrantyExpired = $assets->filter(fn($a) => $a->isWarrantyExpired())->count();
        $warrantySoon    = $assets->filter(fn($a) => $a->isWarrantyExpiringSoon())->count();
        $categories      = \App\Models\AssetCategory::active()->get();

        return view('reports.inventory', compact(
            'assets','byCategory','byStatus','totalValue',
            'warrantyExpired','warrantySoon','categories'
        ));
    }

    // ── Exportar tickets a CSV ────────────────────────────────────────────────
    public function exportTicketsCsv(Request $request)
    {
        abort_unless(auth()->user()->hasAnyRole(['admin','superadmin','jefe_soporte']), 403);

        $from = $request->input('from', now()->startOfMonth()->format('Y-m-d'));
        $to   = $request->input('to',   now()->format('Y-m-d'));

        $tickets = Ticket::with(['status','priority','category','requester','assignee'])
            ->whereBetween('created_at', [Carbon::parse($from)->startOfDay(), Carbon::parse($to)->endOfDay()])
            ->orderBy('created_at')
            ->get();

        $filename = 'tickets_' . $from . '_' . $to . '.csv';
        $headers  = ['Content-Type' => 'text/csv; charset=UTF-8', 'Content-Disposition' => "attachment; filename=\"$filename\""];

        $callback = function() use ($tickets) {
            $file = fopen('php://output', 'w');
            fprintf($file, chr(0xEF).chr(0xBB).chr(0xBF)); // UTF-8 BOM
            fputcsv($file, ['Número','Título','Estado','Prioridad','Categoría','Tipo','Solicitante','Agente','Departamento','SLA Respuesta','SLA Resolución','SLA Incumplido','Satisfacción','Creado','Cerrado']);
            foreach ($tickets as $t) {
                fputcsv($file, [
                    $t->number,
                    $t->title,
                    $t->status->name,
                    $t->priority->name,
                    $t->category?->name ?? '',
                    $t->type?->name ?? '',
                    $t->requester->name,
                    $t->assignee?->name ?? '',
                    $t->department?->name ?? '',
                    $t->sla_response_due?->format('d/m/Y H:i') ?? '',
                    $t->sla_resolution_due?->format('d/m/Y H:i') ?? '',
                    $t->sla_resolution_breached ? 'Sí' : 'No',
                    $t->satisfaction_score ?? '',
                    $t->created_at->format('d/m/Y H:i'),
                    $t->closed_at?->format('d/m/Y H:i') ?? '',
                ]);
            }
            fclose($file);
        };

        return response()->stream($callback, 200, $headers);
    }

    // ── Exportar inventario a CSV ─────────────────────────────────────────────
    public function exportInventoryCsv(Request $request)
    {
        abort_unless(auth()->user()->hasAnyRole(['admin','superadmin','jefe_soporte']), 403);

        $assets   = Asset::with(['category','model.manufacturer','assignedUser','department'])
            ->orderBy('code')->get();
        $filename = 'inventario_' . now()->format('Y-m-d') . '.csv';
        $headers  = ['Content-Type' => 'text/csv; charset=UTF-8', 'Content-Disposition' => "attachment; filename=\"$filename\""];

        $callback = function() use ($assets) {
            $file = fopen('php://output', 'w');
            fprintf($file, chr(0xEF).chr(0xBB).chr(0xBF));
            fputcsv($file, ['Código','Nombre','Categoría','Fabricante','Modelo','N° Serie','Estado','Ubicación','Departamento','Asignado a','Fecha Compra','Valor','Garantía hasta','Creado']);
            foreach ($assets as $a) {
                fputcsv($file, [
                    $a->code,
                    $a->name,
                    $a->category->name,
                    $a->model?->manufacturer?->name ?? '',
                    $a->model?->name ?? '',
                    $a->serial_number ?? '',
                    $a->status_label,
                    $a->location ?? '',
                    $a->department?->name ?? '',
                    $a->assignedUser?->name ?? '',
                    $a->purchase_date?->format('d/m/Y') ?? '',
                    $a->purchase_price ?? '',
                    $a->warranty_until?->format('d/m/Y') ?? '',
                    $a->created_at->format('d/m/Y'),
                ]);
            }
            fclose($file);
        };

        return response()->stream($callback, 200, $headers);
    }

    // ── Exportar reporte de tickets a PDF ─────────────────────────────────────
    public function exportTicketsPdf(Request $request)
    {
        abort_unless(auth()->user()->hasAnyRole(['admin','superadmin','jefe_soporte']), 403);

        $from = $request->input('from', now()->startOfMonth()->format('Y-m-d'));
        $to   = $request->input('to',   now()->format('Y-m-d'));

        $tickets = Ticket::with(['status','priority','category','requester','assignee'])
            ->whereBetween('created_at', [Carbon::parse($from)->startOfDay(), Carbon::parse($to)->endOfDay()])
            ->orderBy('created_at')
            ->get();

        $metrics = [
            'total'        => $tickets->count(),
            'closed'       => $tickets->filter(fn($t) => $t->status->is_final)->count(),
            'sla_breached' => $tickets->where('sla_resolution_breached', true)->count(),
            'avg_sat'      => $this->avgSatisfaction($tickets),
        ];

        $byPriority = $tickets->groupBy('priority.name')->map(fn($g) => $g->count());
        $byStatus   = $tickets->groupBy('status.name')->map(fn($g) => $g->count());

        $pdf = \Barryvdh\DomPDF\Facade\Pdf::loadView('reports.pdf.tickets', compact(
            'tickets','metrics','byPriority','byStatus','from','to'
        ))->setPaper('letter', 'landscape');

        return $pdf->download('reporte_tickets_' . $from . '_' . $to . '.pdf');
    }

    // ── Exportar inventario a PDF ─────────────────────────────────────────────
    public function exportInventoryPdf()
    {
        abort_unless(auth()->user()->hasAnyRole(['admin','superadmin','jefe_soporte']), 403);

        $assets = Asset::with(['category','model.manufacturer','assignedUser','department'])
            ->orderBy('category_id')->orderBy('code')->get();

        $byCategory = $assets->groupBy('category.name')->map(fn($g) => [
            'count' => $g->count(),
            'value' => $g->sum('purchase_price'),
        ]);

        $pdf = \Barryvdh\DomPDF\Facade\Pdf::loadView('reports.pdf.inventory', compact('assets','byCategory'))
            ->setPaper('letter', 'landscape');

        return $pdf->download('inventario_' . now()->format('Y-m-d') . '.pdf');
    }

    // ── Helpers ───────────────────────────────────────────────────────────────
    private function avgResolutionHours($tickets): ?float
    {
        $resolved = $tickets->filter(fn($t) => $t->resolved_at && $t->created_at);
        if ($resolved->isEmpty()) return null;
        $avg = $resolved->avg(fn($t) => $t->created_at->diffInMinutes($t->resolved_at));
        return round($avg / 60, 1);
    }

    private function avgSatisfaction($tickets): ?float
    {
        $rated = $tickets->whereNotNull('satisfaction_score');
        if ($rated->isEmpty()) return null;
        return round($rated->avg('satisfaction_score'), 1);
    }
}
