<?php

namespace App\Http\Controllers;

use App\Models\Bien;
use App\Models\Dotacion;
use App\Models\Operacion;
use App\Models\Prestamo;
use App\Models\RegistroStock;
use App\Services\ReporteLegacyService;
use App\Models\Transferencia;
use App\Support\FallbackLabels;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use Illuminate\View\View;
use Symfony\Component\HttpFoundation\StreamedResponse;

class ReporteLegacyController extends Controller
{
    private const ALLOWED_PER_PAGE_VALUES = [10, 50, 100];

    public function __construct(private readonly ReporteLegacyService $reporteLegacyService)
    {
    }

    private const PRESTAMO_STATUS_LABELS = [
        1 => 'Entregado',
        2 => 'Devuelto',
    ];

    private const DOTACION_REASON_LABELS = [
        1 => 'Vencida',
        2 => 'Deterioro',
        3 => 'Adelanto',
    ];

    private const OPERATION_TYPE_LABELS = [
        //1 => 'Asignacion',
        2 => 'Dotacion',
        3 => 'Transferencia',
        4 => 'Registro Stock',
        5 => 'Devolucion Prestamo',
        6 => 'Devolucion Transferencia',
    ];

    public function operaciones(Request $request): View
    {
        $filters = $this->reporteLegacyService->validateOperacionesFilters($request);
        [$startDate, $endDate] = $this->reporteLegacyService->resolveDateRange($filters['fechaIni'], $filters['fechaFin']);

        $operations = Operacion::query()
            ->when($filters['tipoOperacion'] > 0, fn ($q) => $q->where('tipo', $filters['tipoOperacion']))
            ->orderByDesc('numero')
            ->get(['id', 'numero', 'tipo', 'cedulaDespacha']);

        $rows = [];
        foreach ($operations as $operation) {
            $snapshot = $this->reporteLegacyService->resolveOperationSnapshot((int) $operation->tipo, (int) $operation->numero);
            if ($snapshot === null) {
                continue;
            }

            $fecha = $snapshot['fecha'];
            if (! $this->reporteLegacyService->withinDateRange($fecha, $startDate, $endDate)) {
                continue;
            }

            $rows[] = [
                'operacion' => (int) $operation->numero,
                'tipo' => self::OPERATION_TYPE_LABELS[(int) $operation->tipo] ?? 'Sin tipo',
                'fecha' => $this->reporteLegacyService->formatDate($fecha),
                'responsable' => (string) ($snapshot['responsable'] ?: ($operation->cedulaDespacha ?? '')),
            ];
        }

        return $this->renderModuleView(
            moduleKey: 'operaciones',
            title: 'Registro de Operaciones',
            columns: [
                'operacion' => 'Oper',
                'tipo' => 'Tipo',
                'fecha' => 'Fecha',
                'responsable' => 'Responsable',
            ],
            rows: $rows,
            filters: $filters,
            filterDefinitions: [
                [
                    'name' => 'tipoOperacion',
                    'label' => 'Tipo de Operacion',
                    'type' => 'select',
                    'options' => [0 => 'Todas'] + self::OPERATION_TYPE_LABELS,
                ],
                ['name' => 'fechaIni', 'label' => 'Fecha Inicial', 'type' => 'date'],
                ['name' => 'fechaFin', 'label' => 'Fecha Final', 'type' => 'date'],
            ],
        );
    }

    public function operacionesExport(Request $request): StreamedResponse
    {
        $rows = $this->operaciones($request)->getData()['rows'] ?? [];

        return $this->reporteLegacyService->excelResponse('reporte_operaciones', [
            'Oper', 'Tipo', 'Fecha', 'Responsable',
        ], array_map(static fn (array $row): array => [
            $row['operacion'],
            $row['tipo'],
            $row['fecha'],
            $row['responsable'],
        ], $rows), 'Operaciones');
    }

    public function operacionesPrint(Request $request): View
    {
        $view = $this->operaciones($request);
        $data = $view->getData();
        $this->ensurePrintableRows($data['rows'] ?? []);

        return view('reportes.module-print', [
            'title' => 'Registro de Operaciones',
            'columns' => $data['columns'],
            'rows' => $data['rows'],
        ]);
    }

    public function prestamos(Request $request): View
    {
        $filters = $this->reporteLegacyService->validatePrestamoTransferenciaFilters($request, false);
        [$startDate, $endDate] = $this->reporteLegacyService->resolveDateRange($filters['fechaIni'], $filters['fechaFin']);

        $query = Prestamo::query()
            ->leftJoin('bienes as b', 'b.codigo', '=', 'prestamos.codigo')
            ->select([
                'prestamos.numOperacion', 'prestamos.codigo', 'prestamos.cantidad', 'prestamos.cedulaSolicita',
                'prestamos.cedulaAutoriza', 'prestamos.cedulaDespacha',
                'prestamos.status', 'prestamos.fechaEntrega', 'prestamos.fechaDevolucion', 'prestamos.observacion',
                'b.sap', 'b.descripcion', 'b.tipo', 'b.costo', 'b.peso',
            ]);

        $this->reporteLegacyService->applyBienAndDateFilters($query, $filters, 'prestamos.fechaEntrega', $startDate, $endDate);

        $fieldMap = [
            0 => 'b.descripcion',
            1 => 'b.sap',
            2 => 'prestamos.codigo',
            3 => 'prestamos.cedulaSolicita',
        ];
        $this->reporteLegacyService->applySearchFilter($query, $fieldMap[$filters['tipoBusqueda']] ?? 'b.descripcion', $filters['busqueda']);

        if ($filters['status'] > 0) {
            $query->where('prestamos.status', $filters['status']);
        }

        $rows = $query
            ->orderByDesc('prestamos.fechaEntrega')
            ->get()
            ->map(fn ($row): array => [
                'operacion' => (int) ($row->numOperacion ?? 0),
                'sap' => (string) ($row->sap ?? ''),
                'codigo' => (string) ($row->codigo ?? ''),
                'descripcion' => (string) ($row->descripcion ?? ''),
                'tipo' => FallbackLabels::BIEN_TYPE_LABELS[(int) ($row->tipo ?? 0)] ?? 'Sin tipo',
                'costo' => (string) ($row->costo ?? ''),
                'peso' => (string) ($row->peso ?? ''),
                'cantidad' => (int) ($row->cantidad ?? 0),
                'cedulaSolicita' => (string) ($row->cedulaSolicita ?? ''),
                'cedulaAutoriza' => (string) ($row->cedulaAutoriza ?? ''),
                'cedulaDespacha' => (string) ($row->cedulaDespacha ?? ''),
                'status' => self::PRESTAMO_STATUS_LABELS[(int) ($row->status ?? 0)] ?? 'Sin status',
                'fechaEntrega' => $this->reporteLegacyService->formatDate($row->fechaEntrega),
                'fechaDevolucion' => $this->reporteLegacyService->formatDate($row->fechaDevolucion),
                'observacion' => (string) ($row->observacion ?? ''),
            ])
            ->values()
            ->all();

        return $this->renderModuleView(
            moduleKey: 'prestamos',
            title: 'Reporte de Asignaciones',
            columns: [
                'operacion' => 'Oper',
                'sap' => 'SAP',
                'codigo' => 'Codigo',
                'descripcion' => 'Descripcion',
                'tipo' => 'Tipo',
                'costo' => 'Costo ($)',
                'peso' => 'Peso',
                'cantidad' => 'Cant',
                'cedulaSolicita' => 'Cedula Solicito',
                'cedulaAutoriza' => 'Cedula Autorizo',
                'cedulaDespacha' => 'Cedula Despacho',
                'status' => 'Status',
                'fechaEntrega' => 'Fecha Entrega',
                'fechaDevolucion' => 'Fecha Devolucion',
                'observacion' => 'Observacion',
            ],
            rows: $rows,
            filters: $filters,
            filterDefinitions: [
                [
                    'name' => 'tipoBienes',
                    'label' => 'Tipo de Bienes',
                    'type' => 'select',
                    'options' => [0 => 'Todos'] + FallbackLabels::BIEN_TYPE_LABELS,
                ],
                [
                    'name' => 'tipoBusqueda',
                    'label' => 'Tipo de Busqueda',
                    'type' => 'select',
                    'options' => [
                        0 => 'Descripcion',
                        1 => 'Codigo SAP',
                        2 => 'Codigo de Barras',
                        3 => 'Cedula Solicitante',
                    ],
                ],
                [
                    'name' => 'status',
                    'label' => 'Status',
                    'type' => 'select',
                    'options' => [0 => 'Todos'] + self::PRESTAMO_STATUS_LABELS,
                ],
                ['name' => 'busqueda', 'label' => 'Buscar', 'type' => 'text', 'placeholder' => 'Buscar...'],
                ['name' => 'fechaIni', 'label' => 'Fecha Inicial', 'type' => 'date'],
                ['name' => 'fechaFin', 'label' => 'Fecha Final', 'type' => 'date'],
            ],
        );
    }

    public function prestamosExport(Request $request): StreamedResponse
    {
        $rows = $this->prestamos($request)->getData()['rows'] ?? [];

        return $this->reporteLegacyService->excelResponse('reporte_prestamos', [
            'Oper', 'SAP', 'Codigo', 'Descripcion', 'Tipo', 'Costo ($)', 'Peso', 'Cant',
            'Cedula Solicito', 'Cedula Autorizo', 'Cedula Despacho', 'Status',
            'Fecha Entrega', 'Fecha Devolucion', 'Observacion',
        ], array_map(static fn (array $row): array => [
            $row['operacion'], $row['sap'], $row['codigo'], $row['descripcion'], $row['tipo'],
            $row['costo'], $row['peso'], $row['cantidad'], $row['cedulaSolicita'], $row['cedulaAutoriza'],
            $row['cedulaDespacha'], $row['status'], $row['fechaEntrega'], $row['fechaDevolucion'], $row['observacion'],
        ], $rows), 'Asignaciones');
    }

    public function prestamosPrint(Request $request): View
    {
        $view = $this->prestamos($request);
        $data = $view->getData();
        $this->ensurePrintableRows($data['rows'] ?? []);

        return view('reportes.module-print', [
            'title' => 'Reporte de Asignaciones',
            'columns' => $data['columns'],
            'rows' => $data['rows'],
        ]);
    }

    public function transferencias(Request $request): View
    {
        $filters = $this->reporteLegacyService->validatePrestamoTransferenciaFilters($request, true);
        [$startDate, $endDate] = $this->reporteLegacyService->resolveDateRange($filters['fechaIni'], $filters['fechaFin']);

        $query = Transferencia::query()
            ->leftJoin('bienes as b', 'b.codigo', '=', 'transferencias.codigo')
            ->select([
                'transferencias.numOperacion', 'transferencias.codigo', 'transferencias.cantidad',
                'transferencias.cedulaSolicita', 'transferencias.cedulaAutoriza', 'transferencias.cedulaDespacha',
                'transferencias.status', 'transferencias.fechaEntrega', 'transferencias.fechaDevolucion',
                'transferencias.receptor', 'transferencias.observacion',
                'b.sap', 'b.descripcion', 'b.tipo', 'b.costo', 'b.peso',
            ]);

        $this->reporteLegacyService->applyBienAndDateFilters($query, $filters, 'transferencias.fechaEntrega', $startDate, $endDate);

        $fieldMap = [
            0 => 'transferencias.receptor',
            1 => 'b.descripcion',
            2 => 'b.sap',
            3 => 'transferencias.codigo',
            4 => 'transferencias.cedulaSolicita',
        ];
        $this->reporteLegacyService->applySearchFilter($query, $fieldMap[$filters['tipoBusqueda']] ?? 'transferencias.receptor', $filters['busqueda']);

        if ($filters['status'] > 0) {
            $query->where('transferencias.status', $filters['status']);
        }

        $rows = $query
            ->orderByDesc('transferencias.fechaEntrega')
            ->get()
            ->map(fn ($row): array => [
                'operacion' => (int) ($row->numOperacion ?? 0),
                'sap' => (string) ($row->sap ?? ''),
                'codigo' => (string) ($row->codigo ?? ''),
                'descripcion' => (string) ($row->descripcion ?? ''),
                'tipo' => FallbackLabels::BIEN_TYPE_LABELS[(int) ($row->tipo ?? 0)] ?? 'Sin tipo',
                'costo' => (string) ($row->costo ?? ''),
                'peso' => (string) ($row->peso ?? ''),
                'cantidad' => (int) ($row->cantidad ?? 0),
                'cedulaSolicita' => (string) ($row->cedulaSolicita ?? ''),
                'cedulaAutoriza' => (string) ($row->cedulaAutoriza ?? ''),
                'cedulaDespacha' => (string) ($row->cedulaDespacha ?? ''),
                'status' => self::PRESTAMO_STATUS_LABELS[(int) ($row->status ?? 0)] ?? 'Sin status',
                'fechaEntrega' => $this->reporteLegacyService->formatDate($row->fechaEntrega),
                'fechaDevolucion' => $this->reporteLegacyService->formatDate($row->fechaDevolucion),
                'receptor' => (string) ($row->receptor ?? ''),
                'observacion' => (string) ($row->observacion ?? ''),
            ])
            ->values()
            ->all();

        return $this->renderModuleView(
            moduleKey: 'transferencias',
            title: 'Reporte de Transferencias',
            columns: [
                'operacion' => 'Oper',
                'sap' => 'SAP',
                'codigo' => 'Codigo',
                'descripcion' => 'Descripcion',
                'tipo' => 'Tipo',
                'costo' => 'Costo ($)',
                'peso' => 'Peso',
                'cantidad' => 'Cant',
                'cedulaSolicita' => 'Cedula Solicito',
                'cedulaAutoriza' => 'Cedula Autorizo',
                'cedulaDespacha' => 'Cedula Despacho',
                'status' => 'Status',
                'fechaEntrega' => 'Fecha Entrega',
                'fechaDevolucion' => 'Fecha Devolucion',
                'receptor' => 'Receptor',
                'observacion' => 'Observacion',
            ],
            rows: $rows,
            filters: $filters,
            filterDefinitions: [
                [
                    'name' => 'tipoBienes',
                    'label' => 'Tipo de Bienes',
                    'type' => 'select',
                    'options' => [0 => 'Todos'] + FallbackLabels::BIEN_TYPE_LABELS,
                ],
                [
                    'name' => 'tipoBusqueda',
                    'label' => 'Tipo de Busqueda',
                    'type' => 'select',
                    'options' => [
                        0 => 'Receptor',
                        1 => 'Descripcion',
                        2 => 'Codigo SAP',
                        3 => 'Codigo de Barras',
                        4 => 'Cedula Solicitante',
                    ],
                ],
                [
                    'name' => 'status',
                    'label' => 'Status',
                    'type' => 'select',
                    'options' => [0 => 'Todos'] + self::PRESTAMO_STATUS_LABELS,
                ],
                ['name' => 'busqueda', 'label' => 'Buscar', 'type' => 'text', 'placeholder' => 'Buscar...'],
                ['name' => 'fechaIni', 'label' => 'Fecha Inicial', 'type' => 'date'],
                ['name' => 'fechaFin', 'label' => 'Fecha Final', 'type' => 'date'],
            ],
        );
    }

    public function transferenciasExport(Request $request): StreamedResponse
    {
        $rows = $this->transferencias($request)->getData()['rows'] ?? [];

        return $this->reporteLegacyService->excelResponse('reporte_transferencias', [
            'Oper', 'SAP', 'Codigo', 'Descripcion', 'Tipo', 'Costo ($)', 'Peso', 'Cant',
            'Cedula Solicito', 'Cedula Autorizo', 'Cedula Despacho', 'Status',
            'Fecha Entrega', 'Fecha Devolucion', 'Receptor', 'Observacion',
        ], array_map(static fn (array $row): array => [
            $row['operacion'], $row['sap'], $row['codigo'], $row['descripcion'], $row['tipo'],
            $row['costo'], $row['peso'], $row['cantidad'], $row['cedulaSolicita'], $row['cedulaAutoriza'],
            $row['cedulaDespacha'], $row['status'], $row['fechaEntrega'], $row['fechaDevolucion'],
            $row['receptor'], $row['observacion'],
        ], $rows), 'Transferencias');
    }

    public function transferenciasPrint(Request $request): View
    {
        $view = $this->transferencias($request);
        $data = $view->getData();
        $this->ensurePrintableRows($data['rows'] ?? []);

        return view('reportes.module-print', [
            'title' => 'Reporte de Transferencias',
            'columns' => $data['columns'],
            'rows' => $data['rows'],
        ]);
    }

    public function dotaciones(Request $request): View
    {
        $filters = $request->validate([
            'tipoBusqueda' => ['nullable', 'integer', 'in:0,1,2,3'],
            'busqueda' => ['nullable', 'string', 'max:120'],
            'fechaIni' => ['nullable', 'date'],
            'fechaFin' => ['nullable', 'date'],
        ]);

        $filters = [
            'tipoBusqueda' => (int) ($filters['tipoBusqueda'] ?? 0),
            'busqueda' => trim((string) ($filters['busqueda'] ?? '')),
            'fechaIni' => (string) ($filters['fechaIni'] ?? ''),
            'fechaFin' => (string) ($filters['fechaFin'] ?? ''),
        ];

        [$startDate, $endDate] = $this->reporteLegacyService->resolveDateRange($filters['fechaIni'], $filters['fechaFin']);

        $query = Dotacion::query()
            ->leftJoin('bienes as b', 'b.codigo', '=', 'dotaciones.codigo')
            ->where('b.tipo', 3)
            ->select([
                'dotaciones.numOperacion', 'dotaciones.codigo', 'dotaciones.cantidad',
                'dotaciones.cedulaSolicita', 'dotaciones.cedulaDespacha',
                'dotaciones.fechaEntrega', 'dotaciones.razon',
                'b.sap', 'b.descripcion',
            ]);

        if ($startDate && $endDate) {
            $query->whereBetween('dotaciones.fechaEntrega', [$startDate->toDateTimeString(), $endDate->toDateTimeString()]);
        }

        $fieldMap = [
            0 => 'b.descripcion',
            1 => 'b.sap',
            2 => 'dotaciones.codigo',
            3 => 'dotaciones.cedulaSolicita',
        ];
        $this->reporteLegacyService->applySearchFilter($query, $fieldMap[$filters['tipoBusqueda']] ?? 'b.descripcion', $filters['busqueda']);

        $rows = $query
            ->orderByDesc('dotaciones.fechaEntrega')
            ->get()
            ->map(fn ($row): array => [
                'operacion' => (int) ($row->numOperacion ?? 0),
                'sap' => (string) ($row->sap ?? ''),
                'codigo' => (string) ($row->codigo ?? ''),
                'descripcion' => (string) ($row->descripcion ?? ''),
                'cantidad' => (int) ($row->cantidad ?? 0),
                'cedulaSolicita' => (string) ($row->cedulaSolicita ?? ''),
                'cedulaDespacha' => (string) ($row->cedulaDespacha ?? ''),
                'fechaEntrega' => $this->reporteLegacyService->formatDate($row->fechaEntrega),
                'razon' => self::DOTACION_REASON_LABELS[(int) ($row->razon ?? 0)] ?? 'Sin razon',
            ])
            ->values()
            ->all();

        return $this->renderModuleView(
            moduleKey: 'dotaciones',
            title: 'Reporte de Dotaciones',
            columns: [
                'operacion' => 'Oper',
                'sap' => 'SAP',
                'codigo' => 'Codigo',
                'descripcion' => 'Descripcion',
                'cantidad' => 'Cant',
                'cedulaSolicita' => 'Cedula Solicito',
                'cedulaDespacha' => 'Cedula Despacho',
                'fechaEntrega' => 'Fecha Entrega',
                'razon' => 'Razon',
            ],
            rows: $rows,
            filters: $filters,
            filterDefinitions: [
                [
                    'name' => 'tipoBusqueda',
                    'label' => 'Tipo de Busqueda',
                    'type' => 'select',
                    'options' => [
                        0 => 'Descripcion',
                        1 => 'Codigo SAP',
                        2 => 'Codigo de Barras',
                        3 => 'Cedula Solicitante',
                    ],
                ],
                ['name' => 'busqueda', 'label' => 'Buscar', 'type' => 'text', 'placeholder' => 'Buscar...'],
                ['name' => 'fechaIni', 'label' => 'Fecha Inicial', 'type' => 'date'],
                ['name' => 'fechaFin', 'label' => 'Fecha Final', 'type' => 'date'],
            ],
        );
    }

    public function dotacionesExport(Request $request): StreamedResponse
    {
        $rows = $this->dotaciones($request)->getData()['rows'] ?? [];

        return $this->reporteLegacyService->excelResponse('reporte_dotaciones', [
            'Oper', 'SAP', 'Codigo', 'Descripcion', 'Cant', 'Cedula Solicito',
            'Cedula Despacho', 'Fecha Entrega', 'Razon',
        ], array_map(static fn (array $row): array => [
            $row['operacion'], $row['sap'], $row['codigo'], $row['descripcion'], $row['cantidad'],
            $row['cedulaSolicita'], $row['cedulaDespacha'], $row['fechaEntrega'], $row['razon'],
        ], $rows), 'Dotaciones');
    }

    public function dotacionesPrint(Request $request): View
    {
        $view = $this->dotaciones($request);
        $data = $view->getData();
        $this->ensurePrintableRows($data['rows'] ?? []);

        return view('reportes.module-print', [
            'title' => 'Reporte de Dotaciones',
            'columns' => $data['columns'],
            'rows' => $data['rows'],
        ]);
    }

    public function stock(Request $request): View
    {
        $filters = $request->validate([
            'tipoBienes' => ['nullable', 'integer', 'min:0'],
            'tipoBusqueda' => ['nullable', 'integer', 'in:0,1,2'],
            'busqueda' => ['nullable', 'string', 'max:120'],
            'fechaIni' => ['nullable', 'date'],
            'fechaFin' => ['nullable', 'date'],
        ]);

        $filters = [
            'tipoBienes' => (int) ($filters['tipoBienes'] ?? 0),
            'tipoBusqueda' => (int) ($filters['tipoBusqueda'] ?? 0),
            'busqueda' => trim((string) ($filters['busqueda'] ?? '')),
            'fechaIni' => (string) ($filters['fechaIni'] ?? ''),
            'fechaFin' => (string) ($filters['fechaFin'] ?? ''),
        ];

        [$startDate, $endDate] = $this->reporteLegacyService->resolveDateRange($filters['fechaIni'], $filters['fechaFin']);

        $query = RegistroStock::query()
            ->leftJoin('bienes as b', 'b.codigo', '=', 'registrosstock.codigo')
            ->select([
                'registrosstock.numOperacion', 'registrosstock.cantidad', 'registrosstock.objetivo',
                'registrosstock.fechaOperacion', 'registrosstock.cedulaResponsable', 'registrosstock.observacion',
                'b.sap', 'b.codigo', 'b.descripcion', 'b.tipo', 'b.costo', 'b.peso',
            ]);

        if ($filters['tipoBienes'] > 0) {
            $query->where('b.tipo', $filters['tipoBienes']);
        }

        if ($startDate && $endDate) {
            $query->whereBetween('registrosstock.fechaOperacion', [$startDate->toDateTimeString(), $endDate->toDateTimeString()]);
        }

        $fieldMap = [
            0 => 'b.descripcion',
            1 => 'b.sap',
            2 => 'registrosstock.codigo',
        ];
        $this->reporteLegacyService->applySearchFilter($query, $fieldMap[$filters['tipoBusqueda']] ?? 'b.descripcion', $filters['busqueda']);

        $rows = $query
            ->orderByDesc('registrosstock.fechaOperacion')
            ->get()
            ->map(fn ($row): array => [
                'operacion' => (int) ($row->numOperacion ?? 0),
                'sap' => (string) ($row->sap ?? ''),
                'codigo' => (string) ($row->codigo ?? ''),
                'descripcion' => (string) ($row->descripcion ?? ''),
                'tipo' => FallbackLabels::BIEN_TYPE_LABELS[(int) ($row->tipo ?? 0)] ?? 'Sin tipo',
                'costo' => (string) ($row->costo ?? ''),
                'peso' => (string) ($row->peso ?? ''),
                'cantidad' => (int) ($row->cantidad ?? 0),
                'objetivo' => (int) ($row->objetivo ?? 0) === 1 ? 'Almacenamiento' : 'En Stock',
                'fechaOperacion' => $this->reporteLegacyService->formatDate($row->fechaOperacion),
                'responsable' => (string) ($row->cedulaResponsable ?? ''),
                'observacion' => (string) ($row->observacion ?? ''),
            ])
            ->values()
            ->all();

        return $this->renderModuleView(
            moduleKey: 'stock',
            title: 'Registro del Stock',
            columns: [
                'operacion' => 'Oper',
                'sap' => 'SAP',
                'codigo' => 'Codigo',
                'descripcion' => 'Descripcion',
                'tipo' => 'Tipo',
                'costo' => 'Costo ($)',
                'peso' => 'Peso',
                'cantidad' => 'Cantidad',
                'objetivo' => 'Objetivo',
                'fechaOperacion' => 'Fecha Operacion',
                'responsable' => 'Responsable',
                'observacion' => 'Observacion',
            ],
            rows: $rows,
            filters: $filters,
            filterDefinitions: [
                [
                    'name' => 'tipoBienes',
                    'label' => 'Tipo de Bienes',
                    'type' => 'select',
                    'options' => [0 => 'Todos'] + FallbackLabels::BIEN_TYPE_LABELS,
                ],
                [
                    'name' => 'tipoBusqueda',
                    'label' => 'Tipo de Busqueda',
                    'type' => 'select',
                    'options' => [
                        0 => 'Descripcion',
                        1 => 'Codigo SAP',
                        2 => 'Codigo de Barras',
                    ],
                ],
                ['name' => 'busqueda', 'label' => 'Buscar', 'type' => 'text', 'placeholder' => 'Buscar...'],
                ['name' => 'fechaIni', 'label' => 'Fecha Inicial', 'type' => 'date'],
                ['name' => 'fechaFin', 'label' => 'Fecha Final', 'type' => 'date'],
            ],
        );
    }

    public function stockExport(Request $request): StreamedResponse
    {
        $rows = $this->stock($request)->getData()['rows'] ?? [];

        return $this->reporteLegacyService->excelResponse('reporte_stock', [
            'Oper', 'SAP', 'Codigo', 'Descripcion', 'Tipo', 'Costo ($)', 'Peso',
            'Cantidad', 'Objetivo', 'Fecha Operacion', 'Responsable', 'Observacion',
        ], array_map(static fn (array $row): array => [
            $row['operacion'], $row['sap'], $row['codigo'], $row['descripcion'], $row['tipo'],
            $row['costo'], $row['peso'], $row['cantidad'], $row['objetivo'], $row['fechaOperacion'],
            $row['responsable'], $row['observacion'],
        ], $rows), 'Stock');
    }

    public function stockPrint(Request $request): View
    {
        $view = $this->stock($request);
        $data = $view->getData();
        $this->ensurePrintableRows($data['rows'] ?? []);

        return view('reportes.module-print', [
            'title' => 'Registro del Stock',
            'columns' => $data['columns'],
            'rows' => $data['rows'],
        ]);
    }

    public function salidasap(Request $request): View
    {
        $filters = $request->validate([
            'busqueda' => ['nullable', 'string', 'max:120'],
        ]);

        $filters = [
            'busqueda' => trim((string) ($filters['busqueda'] ?? '')),
        ];

        $rows = [];

        if (Schema::hasTable('salidasap')) {
            $hasSolicitanteNombre = Schema::hasColumn('salidasap', 'nombreSolicita');
            $hasSolicitanteLegacy = Schema::hasColumn('salidasap', 'solicito');
            $hasAutorizanteNombre = Schema::hasColumn('salidasap', 'nombreAutoriza');
            $hasAutorizanteLegacy = Schema::hasColumn('salidasap', 'autorizo');

            $query = DB::table('salidasap')
                ->select([
                    'sap',
                    'cantidad',
                    'ubicacion',
                    'numOperacion',
                ]);

            if ($hasSolicitanteNombre) {
                $query->selectRaw('nombreSolicita as solicitante');
            } elseif ($hasSolicitanteLegacy) {
                $query->selectRaw('solicito as solicitante');
            } else {
                $query->selectRaw("'' as solicitante");
            }

            if ($hasAutorizanteNombre) {
                $query->selectRaw('nombreAutoriza as autorizante');
            } elseif ($hasAutorizanteLegacy) {
                $query->selectRaw('autorizo as autorizante');
            } else {
                $query->selectRaw("'' as autorizante");
            }

            if (Schema::hasColumn('salidasap', 'numOperacion')) {
                $query->orderByDesc('numOperacion');
            }

            if ($filters['busqueda'] !== '') {
                $term = '%' . $filters['busqueda'] . '%';
                $query->where(static function ($where) use (
                    $term,
                    $hasSolicitanteNombre,
                    $hasSolicitanteLegacy,
                    $hasAutorizanteNombre,
                    $hasAutorizanteLegacy
                ): void {
                    $where->where('sap', 'like', $term)
                        ->orWhere('ubicacion', 'like', $term)
                        ->orWhere('cantidad', 'like', $term)
                        ->orWhere('numOperacion', 'like', $term);

                    if ($hasSolicitanteNombre) {
                        $where->orWhere('nombreSolicita', 'like', $term);
                    } elseif ($hasSolicitanteLegacy) {
                        $where->orWhere('solicito', 'like', $term);
                    }

                    if ($hasAutorizanteNombre) {
                        $where->orWhere('nombreAutoriza', 'like', $term);
                    } elseif ($hasAutorizanteLegacy) {
                        $where->orWhere('autorizo', 'like', $term);
                    }
                });
            }

            $rows = $query
                ->get()
                ->map(static fn ($row): array => [
                    'sap' => (string) ($row->sap ?? ''),
                    'cantidad' => (int) ($row->cantidad ?? 0),
                    'ubicacion' => (string) ($row->ubicacion ?? ''),
                    'solicitante' => (string) ($row->solicitante ?? ''),
                    'autorizante' => (string) ($row->autorizante ?? ''),
                    'numOperacion' => (int) ($row->numOperacion ?? 0),
                ])
                ->values()
                ->all();
        }

        return $this->renderModuleView(
            moduleKey: 'salidasap',
            title: 'Registro de Salida SAP',
            columns: [
                'sap' => 'Codigo SAP',
                'cantidad' => 'Cantidad',
                'ubicacion' => 'Dependencia/Centro Costo',
                'solicitante' => 'Retirado Por',
                'autorizante' => 'Autorizado Por',
                'numOperacion' => 'Nro. Operacion',
            ],
            rows: $rows,
            filters: $filters,
            filterDefinitions: [
                [
                    'name' => 'busqueda',
                    'label' => 'Buscar',
                    'type' => 'text',
                    'placeholder' => 'SAP, operacion, ubicacion, retirado o autorizado por',
                ],
            ],
        );
    }

    public function salidasapExport(Request $request): StreamedResponse
    {
        $rows = $this->salidasap($request)->getData()['rows'] ?? [];

        return $this->reporteLegacyService->excelResponse('reporte_salidasap', [
            'Codigo SAP',
            'Cantidad',
            'Dependencia/Centro Costo',
            'Retirado Por',
            'Autorizado Por',
            'Nro. Operacion',
        ], array_map(static fn (array $row): array => [
            $row['sap'],
            $row['cantidad'],
            $row['ubicacion'],
            $row['solicitante'],
            $row['autorizante'],
            $row['numOperacion'],
        ], $rows), 'Salida SAP');
    }

    public function salidasapPrint(Request $request): View
    {
        $view = $this->salidasap($request);
        $data = $view->getData();
        $this->ensurePrintableRows($data['rows'] ?? []);

        return view('reportes.module-print', [
            'title' => 'Registro de Salida SAP',
            'columns' => $data['columns'],
            'rows' => $data['rows'],
        ]);
    }

    public function salidasapClear(Request $request): RedirectResponse
    {
        if (! Schema::hasTable('salidasap')) {
            return redirect()
                ->route('reportes.salidasap')
                ->with('warning', 'La tabla salidasap no existe en esta base de datos.');
        }

        DB::table('salidasap')->truncate();

        return redirect()
            ->route('reportes.salidasap')
            ->with('status', 'Registro de Salida SAP limpiado correctamente.');
    }

    public function seguimiento(Request $request): View
    {
        $filters = $request->validate([
            'tipoBienes' => ['nullable', 'integer', 'min:0'],
            'tipoBusqueda' => ['nullable', 'integer', 'in:0,1,2'],
            'busqueda' => ['nullable', 'string', 'max:120'],
        ]);

        $filters = [
            'tipoBienes' => (int) ($filters['tipoBienes'] ?? 0),
            'tipoBusqueda' => (int) ($filters['tipoBusqueda'] ?? 0),
            'busqueda' => trim((string) ($filters['busqueda'] ?? '')),
        ];

        $bienQuery = Bien::query()->select([
            'codigo', 'sap', 'descripcion', 'tipo', 'unidad', 'cantidadSap', 'cantidadRotacion', 'costo', 'peso',
        ]);

        if ($filters['tipoBienes'] > 0) {
            $bienQuery->where('tipo', $filters['tipoBienes']);
        }

        $fieldMap = [
            0 => 'descripcion',
            1 => 'sap',
            2 => 'codigo',
        ];
        $this->reporteLegacyService->applySearchFilter($bienQuery, $fieldMap[$filters['tipoBusqueda']] ?? 'descripcion', $filters['busqueda']);

        $bienes = $bienQuery->orderBy('descripcion')->get();

        $transferRows = DB::table('transferencias')
            ->select('codigo', 'ubicacion')
            ->selectRaw('SUM(cantidad) as total_transferido')
            ->where('status', 1)
            ->groupBy('codigo', 'ubicacion')
            ->get();

        $transferMap = [];
        foreach ($transferRows as $transferRow) {
            $code = (string) ($transferRow->codigo ?? '');
            if ($code === '') {
                continue;
            }

            if (! isset($transferMap[$code])) {
                $transferMap[$code] = [];
            }

            $ubicacion = trim((string) ($transferRow->ubicacion ?? ''));
            if ($ubicacion === '') {
                $ubicacion = 'Almacen';
            }

            $transferMap[$code][$ubicacion] = ($transferMap[$code][$ubicacion] ?? 0)
                + (int) ($transferRow->total_transferido ?? 0);
        }

        $rows = [];
        foreach ($bienes as $bien) {
            $codigo = (string) ($bien->codigo ?? '');
            $ubicaciones = $transferMap[$codigo] ?? ['Almacen' => 0];
            $cantidadTotal = (int) ($bien->cantidadSap ?? 0) + (int) ($bien->cantidadRotacion ?? 0);

            foreach ($ubicaciones as $nombreUbicacion => $cantidadTransferida) {
                $rows[] = [
                    'sap' => (string) ($bien->sap ?? ''),
                    'descripcion' => (string) ($bien->descripcion ?? ''),
                    'costo' => (string) ($bien->costo ?? ''),
                    'peso' => (string) ($bien->peso ?? ''),
                    'unidad' => (string) ($bien->unidad ?? ''),
                    'cantidadTotal' => $cantidadTotal,
                    'cantidadSap' => (int) ($bien->cantidadSap ?? 0),
                    'cantidadRotacion' => (int) ($bien->cantidadRotacion ?? 0),
                    'cantidadTransferida' => (int) $cantidadTransferida,
                    'ubicacion' => (string) $nombreUbicacion,
                ];
            }
        }

        return $this->renderModuleView(
            moduleKey: 'seguimiento',
            title: 'Seguimiento de Materiales',
            columns: [
                'sap' => 'Codigo SAP',
                'descripcion' => 'Descripcion',
                'costo' => 'Costo ($)',
                'peso' => 'Peso',
                'unidad' => 'Unidad',
                'cantidadTotal' => 'Cantidad Total',
                'cantidadSap' => 'Cantidad SAP',
                'cantidadRotacion' => 'Cantidad Rotacion',
                'cantidadTransferida' => 'Cantidad Transferida',
                'ubicacion' => 'Ubicacion',
            ],
            rows: $rows,
            filters: $filters,
            filterDefinitions: [
                [
                    'name' => 'tipoBienes',
                    'label' => 'Tipo de Bienes',
                    'type' => 'select',
                    'options' => [0 => 'Todos'] + FallbackLabels::BIEN_TYPE_LABELS,
                ],
                [
                    'name' => 'tipoBusqueda',
                    'label' => 'Tipo de Busqueda',
                    'type' => 'select',
                    'options' => [
                        0 => 'Descripcion',
                        1 => 'Codigo SAP',
                        2 => 'Codigo de Barras',
                    ],
                ],
                ['name' => 'busqueda', 'label' => 'Buscar', 'type' => 'text', 'placeholder' => 'Buscar...'],
            ],
        );
    }

    public function seguimientoExport(Request $request): StreamedResponse
    {
        $rows = $this->seguimiento($request)->getData()['rows'] ?? [];

        return $this->reporteLegacyService->excelResponse('reporte_seguimiento', [
            'Codigo SAP', 'Descripcion', 'Costo ($)', 'Peso', 'Unidad',
            'Cantidad Total', 'Cantidad SAP', 'Cantidad Rotacion', 'Cantidad Transferida', 'Ubicacion',
        ], array_map(static fn (array $row): array => [
            $row['sap'], $row['descripcion'], $row['costo'], $row['peso'], $row['unidad'],
            $row['cantidadTotal'], $row['cantidadSap'], $row['cantidadRotacion'], $row['cantidadTransferida'], $row['ubicacion'],
        ], $rows), 'Seguimiento');
    }

    public function seguimientoPrint(Request $request): View
    {
        $view = $this->seguimiento($request);
        $data = $view->getData();
        $this->ensurePrintableRows($data['rows'] ?? []);

        return view('reportes.module-print', [
            'title' => 'Seguimiento de Materiales',
            'columns' => $data['columns'],
            'rows' => $data['rows'],
        ]);
    }

    public function inventarioMensual(Request $request): View
    {
        $perPage = $this->resolvePerPage($request);
        $filters = $request->validate([
            'mes' => ['nullable', 'integer', 'min:1', 'max:12'],
            'anio' => ['nullable', 'integer', 'min:2000', 'max:2100'],
        ]);

        $mes = (int) ($filters['mes'] ?? now()->month);
        $anio = (int) ($filters['anio'] ?? now()->year);
        $daysInMonth = cal_days_in_month(CAL_GREGORIAN, $mes, $anio);

        $records = DB::table('prestamos as p')
            ->join('bienes as b', 'b.codigo', '=', 'p.codigo')
            ->selectRaw('p.ubicacion, p.numOperacion, DAY(p.fechaEntrega) as dia, SUM(p.cantidad * COALESCE(b.costo, 0)) as costo_total')
            ->whereMonth('p.fechaEntrega', $mes)
            ->whereYear('p.fechaEntrega', $anio)
            ->groupBy('p.ubicacion', 'p.numOperacion', DB::raw('DAY(p.fechaEntrega)'))
            ->orderBy('p.ubicacion')
            ->orderBy('p.numOperacion')
            ->get();

        $matrix = [];
        $dayTotals = array_fill(1, $daysInMonth, 0.0);
        $grandTotal = 0.0;

        foreach ($records as $record) {
            $key = ($record->ubicacion ?? '') . '|' . (string) ($record->numOperacion ?? 0);
            if (! isset($matrix[$key])) {
                $matrix[$key] = [
                    'ubicacion' => (string) ($record->ubicacion ?? ''),
                    'numOperacion' => (int) ($record->numOperacion ?? 0),
                    'dias' => array_fill(1, $daysInMonth, 0.0),
                    'total' => 0.0,
                ];
            }

            $dia = (int) ($record->dia ?? 0);
            $costo = (float) ($record->costo_total ?? 0);
            if ($dia < 1 || $dia > $daysInMonth) {
                continue;
            }

            $matrix[$key]['dias'][$dia] = $costo;
            $matrix[$key]['total'] += $costo;
            $dayTotals[$dia] += $costo;
            $grandTotal += $costo;
        }

        $matrix = array_values($matrix);
        $paginator = null;

        if ($request->routeIs('reportes.inventario-mensual')) {
            $paginator = $this->paginateRows($matrix, $perPage);
            $matrix = $paginator->items();
        }

        return view('reportes.inventario-mensual', [
            'mes' => $mes,
            'anio' => $anio,
            'perPage' => $perPage,
            'paginator' => $paginator,
            'daysInMonth' => $daysInMonth,
            'matrix' => $matrix,
            'dayTotals' => $dayTotals,
            'grandTotal' => $grandTotal,
            'monthLabels' => [
                1 => 'ENERO', 2 => 'FEBRERO', 3 => 'MARZO', 4 => 'ABRIL',
                5 => 'MAYO', 6 => 'JUNIO', 7 => 'JULIO', 8 => 'AGOSTO',
                9 => 'SEPTIEMBRE', 10 => 'OCTUBRE', 11 => 'NOVIEMBRE', 12 => 'DICIEMBRE',
            ],
        ]);
    }

    public function inventarioMensualExport(Request $request): StreamedResponse
    {
        $view = $this->inventarioMensual($request);
        $data = $view->getData();

        $headers = ['Ubicacion', 'Num Operacion'];
        for ($d = 1; $d <= (int) $data['daysInMonth']; $d++) {
            $headers[] = 'Dia ' . $d;
        }
        $headers[] = 'Total';

        $rows = [];
        foreach ($data['matrix'] as $row) {
            $line = [$row['ubicacion'], $row['numOperacion']];
            for ($d = 1; $d <= (int) $data['daysInMonth']; $d++) {
                $line[] = (float) ($row['dias'][$d] ?? 0);
            }
            $line[] = (float) ($row['total'] ?? 0);
            $rows[] = $line;
        }

        return $this->reporteLegacyService->excelResponse('reporte_inventario_mensual', $headers, $rows, 'Inventario Mensual');
    }

    public function inventarioMensualPrint(Request $request): View
    {
        $view = $this->inventarioMensual($request);
        $data = $view->getData();
        $this->ensurePrintableRows($data['matrix'] ?? []);

        return view('reportes.inventario-mensual-print', $data);
    }

    private function ensurePrintableRows(array $rows): void
    {
        if ($rows === []) {
            abort(422, 'No hay datos para imprimir con los filtros seleccionados.');
        }
    }

    private function renderModuleView(
        string $moduleKey,
        string $title,
        array $columns,
        array $rows,
        array $filters,
        array $filterDefinitions,
    ): View {
        $paginator = null;
        $perPage = $this->resolvePerPage(request());

        if (request()->routeIs('reportes.' . $moduleKey)) {
            $paginator = $this->paginateRows($rows, $perPage);
            $rows = $paginator->items();
        }

        return view('reportes.module', [
            'moduleKey' => $moduleKey,
            'title' => $title,
            'columns' => $columns,
            'rows' => $rows,
            'paginator' => $paginator,
            'perPage' => $perPage,
            'filters' => $filters,
            'filterDefinitions' => $filterDefinitions,
            'navItems' => $this->reporteLegacyService->reportNavItems(),
        ]);
    }

    private function paginateRows(array $rows, int $perPage): LengthAwarePaginator
    {
        $currentPage = max(1, (int) request()->query('page', 1));
        $offset = ($currentPage - 1) * $perPage;

        return new LengthAwarePaginator(
            items: array_slice($rows, $offset, $perPage),
            total: count($rows),
            perPage: $perPage,
            currentPage: $currentPage,
            options: [
                'path' => request()->url(),
                'query' => request()->query(),
            ],
        );
    }

    private function resolvePerPage(Request $request): int
    {
        $perPage = (int) $request->query('per_page', self::ALLOWED_PER_PAGE_VALUES[0]);

        return in_array($perPage, self::ALLOWED_PER_PAGE_VALUES, true)
            ? $perPage
            : self::ALLOWED_PER_PAGE_VALUES[0];
    }
}
