<?php

namespace App\Http\Controllers\Api\Hacienda;

use App\Data\ClaveDto;
use App\Http\Attributes\CurrentBranch;
use App\Http\Attributes\CurrentClient;
use App\Services\DocumentoService;

use Illuminate\Http\JsonResponse;

use App\Http\Controllers\ApiController;
use App\Http\Requests\Documents\AddCliente;
use App\Http\Requests\Documents\AddDocRequest;
use App\Http\Requests\Documents\AddCredentials;
use App\Http\Requests\Documents\CreateSucursal;
use App\Http\Requests\Documents\EliminarSucursal;
use App\Http\Requests\Documents\UpdateSucursal;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;

use Illuminate\Http\Request as HttpRequest;
use Illuminate\Support\Facades\Validator;

use Symfony\Component\HttpFoundation\HeaderUtils;
use Symfony\Component\HttpFoundation\Response;

use App\Http\Requests\Documents\AddMensajeReceptorRequest;

class DocumentoController extends ApiController
{
    public function __construct(
        protected DocumentoService $service
    ) {}

    public function agregarCliente(AddCliente $request): JsonResponse
    {      
        $addCliente = $this->service->agregarCliente($request->validated());
        return response()->json($addCliente, 201);
    }

    public function actualizarSucursal(UpdateSucursal $request, #[CurrentClient] object $cliente)
    {
        $result = $this->service->updateSucursal(
            $request->validated(), 
            $cliente->id, 
            $request->route('sucursalId')
        );

        return response()->json($result);
    }

    public function agregarSucursal(CreateSucursal $request, #[CurrentClient] object $cliente)
    {
        $result = $this->service->crearSucursal(
            $request->validated(), 
            $cliente->id
        );

        return response()->json($result);
    }

    public function agregarSucursalApiKey(string $sucursalId, #[CurrentClient] object $cliente)
    {
        $result = $this->service->crearSucursalApiKey(
            $cliente->id,
            $sucursalId
        );

        return response()->json($result);
    }

    public function consultarSucursalApiKeys(string $sucursalId, #[CurrentClient] object $cliente)
    {
        return response()->json($this->service->getSucursalApiKeys(
            $cliente->id,
            $sucursalId
        ));
    }

    public function eliminarSucursal(EliminarSucursal $request, #[CurrentClient] object $cliente)
    {
        $result = $this->service->deleteSucursal(
            $request->route('sucursalId'), 
            $cliente->id
        );

        return response()->json($result);
    }

    public function consultarSucursalesCliente(#[CurrentClient] object $cliente) 
    {
        return response()->json($this->service->getSucursalesByClient($cliente->id));
    }

    public function consultarDocumentosCliente(#[CurrentClient] object $cliente)
    {
        return response()->json($this->service->getDocsByClient($cliente->id));
    }

    public function consultarDocumentosPendientes(): JsonResponse    
    {
        $claves = DB::table('documentos')
            ->where('estado', 'enviado')
            ->pluck('clave');

        return response()->json([
            'message' => "Verificando estado de {$claves->count()} documentos pendientes", 
        ]);
    }

    public function descargarFirmadoXml(ClaveDto $request)
    {
        $doc = $this->service->getDocumentByClave($request->clave);

        if (!$doc->xml_firmado) {
            throw new NotFoundHttpException(\sprintf('No se ha encontrado un XML de la clave "%s"', $request->clave));
        }

        $disposition = HeaderUtils::makeDisposition(
            HeaderUtils::DISPOSITION_ATTACHMENT,
            "{$doc->clave}.xml"
        );

        $response = new Response(base64_decode($doc->xml_firmado));
        $response->headers->set('Content-Disposition', $disposition);
        $response->headers->set('Content-Type', 'application/xml');

        return $response;
    }

    public function descargarRespuestaXml(ClaveDto $request)
    {
        $doc = $this->service->getDocumentByClave($request->clave);

        if (!$doc->xml_respuesta) {
            throw new NotFoundHttpException(\sprintf('No se ha encontrado un XML Respuesta para la clave "%s"', $request->clave));
        }

        $disposition = HeaderUtils::makeDisposition(
            HeaderUtils::DISPOSITION_ATTACHMENT,
            "{$doc->clave}_respuesta.xml"
        );

        $response = new Response(base64_decode($doc->xml_respuesta));
        $response->headers->set('Content-Disposition', $disposition);
        $response->headers->set('Content-Type', 'application/xml');

        return $response;
    }

    public function consultarEstadoDocumento(ClaveDto $request, #[CurrentBranch] array $mh_credenciales): JsonResponse
    {
        return response()->json(
            $this->service->getDocumentStatus($request->clave, $mh_credenciales)
        );
    }

    public function agregarDocumento(AddDocRequest $request, #[CurrentBranch] array $mh_credenciales): JsonResponse 
    {
        Log::info('Incoming POST AGREGAR DOCUMENTO Request:', [
            'Method' => $request->method(),
            'Path' => $request->path(),
            'IP' => $request->ip(),
            'Data' => $request->all(),
        ]);
        
        return response()->json($this->service->addDocumento($mh_credenciales, $request->validated()));
    }
    
    public function agregarMensajeReceptor(AddMensajeReceptorRequest $request, #[CurrentBranch] array $mh_credenciales): JsonResponse
    {
        $clave = preg_replace('/\D+/', '', (string) $request->input('clave'));

        Log::info('Incoming POST AGREGAR MENSAJE RECEPTOR Request:', [
            'Method' => $request->method(),
            'Path' => $request->path(),
            'IP' => $request->ip(),
            'SucursalId' => $mh_credenciales['sucursal_id'] ?? null,
            'Mensaje' => (string) $request->input('mensaje'),
            'TipoDocumento' => (string) $request->input('tipo_documento'),
            'ClaveMask' => $clave !== '' ? str_repeat('*', max(0, strlen($clave) - 8)) . substr($clave, -8) : null,
        ]);
    
        $payload = $request->validated();
        $payload['_branch_emisor'] = $request->input('emisor'); // lo inyecta InjectBranchContext
    
        return response()->json(
            $this->service->addMensajeReceptor($mh_credenciales, $payload)
        );
    }
    
    public function consultarMensajeReceptor(int $id, #[CurrentBranch] array $mh_credenciales): JsonResponse
    {
        return response()->json(
            $this->service->consultarMensajeReceptor($mh_credenciales, $id)
        );
    }
    
    public function consultarMensajeReceptorPorClave(string $clave, #[CurrentBranch] array $mh_credenciales): JsonResponse
    {
        return response()->json(
            $this->service->consultarMensajeReceptorPorClave($mh_credenciales, $clave)
        );
    }
    
    public function listarMensajesReceptor(HttpRequest $request, #[CurrentBranch] array $mh_credenciales): JsonResponse
    {
        return response()->json(
            $this->service->listarMensajesReceptor($mh_credenciales, $request->query())
        );
    }
    
    public function listarMensajesReceptorPorEstado(string $estado, HttpRequest $request, #[CurrentBranch] array $mh_credenciales): JsonResponse
    {
        $filters = $request->query();
        $filters['estado'] = $estado;
    
        return response()->json(
            $this->service->listarMensajesReceptor($mh_credenciales, $filters)
        );
    }

    public function enviarFirmados() 
    { 
        $data = $this->service->procesarFirmados(); 
        
        return response()->json(
            [
                'success' => true
            ]
        );
    }
    
    public function anularDocumento(string $clave, HttpRequest $request, #[CurrentBranch] array $mh_credenciales) 
    {
        $doc = $this->service->getDocumentByClave($clave);

        if (!$doc || $doc->sucursal_id !== $mh_credenciales['sucursal_id']) 
        {
            return response()->json("No se ha encontrado o no te pertenece este documento", 404);
        }

        $lineas = $this->service->getDocumentLineasByDocId($doc->id);

        $data = [
            'tipo_documento'                => '03',
            'moneda'                        => $doc->moneda,
            'tipo_cambio'                   => $doc->tipo_cambio,
            'condicion_venta'               => $doc->condicion_venta,
            'condicion_venta_otros'         => $doc->condicion_venta_otros,
            'cod_act_economica_emisor'      => $request->input('cod_act_economica_emisor'),
            'cod_act_economica_receptor'    => $doc->cod_actividad_receptor,
            'emisor'                        => $request->input('emisor'),
            'medio_pago' => [
                [
                    "medio_pago_tipo" => $doc->medio_pago
                ]
            ],
            'info_referencia' => [
                'tipo_doc' => $doc->tipo_documento,
                'clave'     => $doc->clave,
                'fecha_emision' => $doc->fecha_emision,
                'codigo' => '01',
                'razon' => "Anula Documento de Referencia"
            ]
        ];

        $data['receptor'] = [
            'nombre'              => $doc->receptor_nombre,
            'nombre_comercial'    => $doc->receptor_nombre_comercial,
            'tipo_identificacion' => $doc->receptor_tipo_ident,
            'numero_identificacion' => $doc->receptor_ident,
            'correo'              => $doc->receptor_correo,
            'ubicacion' => [
                'provincia' => $doc->receptor_provincia,
                'canton'    => $doc->receptor_canton,
                'distrito'  => $doc->receptor_distrito,
                'sennas'    => $doc->receptor_otras_sennas,
            ],
        ];

        if (collect($data['receptor']['ubicacion'])->filter()->isEmpty() || $doc->tipo_documento == "04") {
            $data['receptor']['ubicacion'] = null;
        }

        if (collect($data['receptor'])->filter()->isEmpty() || $doc->tipo_documento == "04") {
            $data['receptor'] = null;
        }

        $data['lineas'] = collect($lineas)->map(
            function ($linea) {

                $lineaObj = [ 
                    'detalle' => $linea->detalle, 
                    'cantidad' => $linea->cantidad, 
                    'precio_unitario' => $linea->precio_unitario,
                    'codigo_cabys' => $linea->codigo_cabys,
                    'impuestos' => [
                        [ 
                            'codigo'                    => $linea->codigo_impuesto,
                            'codigo_impuesto_otros'     => $linea->codigo_impuesto_otros,
                            'codigo_tarifa_iva'         => str_pad($linea->codigo_tarifa_iva, 2, "0", STR_PAD_LEFT),
                            'tarifa'                    => $linea->tarifa_impuesto
                        ]
                    ]
                ];

                $lineaObj['descuentos'] = [
                    [
                        'codigo_descuento' => $linea->codigo_descuento,
                        'codigo_descuento_otros' => $linea->codigo_descuento_otros,
                        'monto_descuento'   => $linea->monto_descuento, 
                        'naturaleza_descuento' => $linea->razon_descuento
                    ]
                ];

                if (collect($lineaObj['descuentos'][0])->filter()->isEmpty()) {
                    $lineaObj['descuentos'] = null;
                }

                return $lineaObj; 
            }
        )->toArray();

        $rules = (new AddDocRequest())->rules(); 
        $validator = Validator::make($data, $rules);

        return response()->json($this->service->addDocumento($mh_credenciales, $validator->validated()));
    }

    public function agregarCredenciales(AddCredentials $request, #[CurrentClient] object $cliente): JsonResponse  
    {
        $this->service->addCredentials($request->validated(), $cliente->id);
        return response()->json(null, 201);
    }

}