<?php

namespace Daniv04\HaciendaPackage\Http\Controllers;

use Illuminate\Http\JsonResponse;
use Daniv04\HaciendaPackage\Http\Requests\GeneralRequest;
use Illuminate\Support\Facades\Validator;
use Daniv04\HaciendaPackage\Http\Requests\CreditNoteRequest;
use Daniv04\HaciendaPackage\Http\Requests\DebitNoteRequest;
use Daniv04\HaciendaPackage\Http\Requests\ElectronicExportInvoiceRequest;
use Daniv04\HaciendaPackage\Http\Requests\ElectronicInvoiceRequest;
use Daniv04\HaciendaPackage\Http\Requests\ElectronicPaymentReceiptRequest;
use Daniv04\HaciendaPackage\Http\Requests\ElectronicPurchaseInvoiceRequest;
use Daniv04\HaciendaPackage\Http\Requests\ElectronicTicketRequest;
use Daniv04\HaciendaPackage\Services\DbService\DbService;
use Daniv04\HaciendaPackage\Services\Providers\ProviderFactoryService;
use Daniv04\HaciendaPackage\Services\InvoicingService;
use Daniv04\HaciendaPackage\Http\Resources\ReceiptStatusResource;
use Daniv04\HaciendaPackage\Http\Resources\ReceiptResource;
use Daniv04\HaciendaPackage\Exceptions\HaciendaException;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Illuminate\Validation\ValidationException;
use Daniv04\HaciendaPackage\Exceptions\InvalidReceiptException;
use Daniv04\HaciendaPackage\Jobs\SendReceiptToProviderJob;

class ElectronicReceiptsController extends BaseController
{
    protected $dbService;
    protected $providerFactory;
    protected $invoicingService;
    public function __construct(DbService $dbService, ProviderFactoryService $providerFactory, InvoicingService $invoicingService)
    {
        $this->dbService = $dbService;
        $this->providerFactory = $providerFactory;
        $this->invoicingService = $invoicingService;
    }

    public function store(GeneralRequest $request): JsonResponse
    {
        try {
            $validatedRequest = $request->validated();
            $receiptType = $validatedRequest['ReceiptType'];
            $jsonPayload = $validatedRequest['Payload'];

            //Validate based on type
            $validatedData = $this->validateByType($receiptType, $jsonPayload);

            //Save receipt on DB
            $receipt = $this->dbService->saveReceipt($validatedData, $receiptType);

            //Sent to configured provider
            $provider = config('invoicing.electronic_invoicing_provider');
            SendReceiptToProviderJob::dispatch($receipt, $validatedData, $provider);


            return $this->SuccessResponse(
                [
                'receipt_id' => $receipt->id,
                'consecutive_number' => $receipt->consecutive_number,
                'status' => 'queued',
                'message' => 'Receipt queued for processing'
                ],
                'Document created successfully and queued for sending to provider',
                201
            );
            //catch validation exceptions from the specific request validation
        } catch (ValidationException $e) {
            return response()->json([
                'status' => 422,
                'message' => 'Validation Error',
                'errors' => $e->errors()
            ], 422);
        } catch (\Exception $e) {
            Log::error('Error in ElectronicReceiptsController', [
                'message' => $e->getMessage(),
                'file' => $e->getFile(),
                'line' => $e->getLine(),
                'trace' => $e->getTraceAsString()
            ]);
            return $this->ErrorResponse(
                'Error saving electronic receipt: ' . $e->getMessage(),
                500
            );
        }
    }

    public function getAllDocuments(Request $request): JsonResponse
    {
        try {
            $receipts = $this->dbService->getAllReceipts($request->integer('per_page', 25));

            if($receipts->isEmpty()) {
                return $this->SuccessResponse([], 'No documents found', 200);
            }

            return $this->PaginatedResponse(ReceiptResource::collection($receipts), 'Documents retrieved successfully');

        } catch (\Exception $e) {
            Log::error('Error in getDocuments', [
                'message' => $e->getMessage(),
                'file' => $e->getFile(),
                'line' => $e->getLine(),
                'trace' => $e->getTraceAsString()
            ]);
            return $this->ErrorResponse(
                'Error retrieving documents: ' . $e->getMessage(),
                500
            );
        }
    }

    public function getDocumentStatus($ui_key): JsonResponse
    {
        try {
            if (!isset($ui_key)) {
                return $this->ErrorResponse('UI Key is required', 400);
            }

            $status = $this->invoicingService->getDocumentStatus($ui_key);

            return $this->SuccessResponse($status, 'Document status retrieved successfully', 200);
        } catch (HaciendaException $e) {
            return $this->ErrorResponse('Error al consultar Hacienda: ' . $e->getMessage(), 502);
        } catch (\Exception $e) {
            Log::error('Error in getDocumentStatus', [
                'message' => $e->getMessage(),
                'file'    => $e->getFile(),
                'line'    => $e->getLine(),
                'trace'   => $e->getTraceAsString(),
            ]);
            return $this->ErrorResponse(
                'Error retrieving document status: ' . $e->getMessage(),
                500
            );
        }
    }

    public function getDocumentByUiKey($ui_key): JsonResponse
    {
        try {
            if(!isset($ui_key)) {
                return $this->ErrorResponse('UI Key is required', 400);
            }

            $receipt = $this->dbService->getReceiptByUiKey($ui_key);

            if (!$receipt) {
                return $this->ErrorResponse('Document with UI Key ' . $ui_key . ' not found', 404);
            }

            return $this->SuccessResponse(new ReceiptResource($receipt), 'Document retrieved successfully',200);
        } catch (\Exception $e) {
            Log::error('Error in getDocumentByUiKey', [
                'message' => $e->getMessage(),
                'file' => $e->getFile(),
                'line' => $e->getLine(),
                'trace' => $e->getTraceAsString()
            ]);
            return $this->ErrorResponse(
                'Error retrieving document: ' . $e->getMessage(),
                500
            );
        }
    }

    private function validateByType($type, $data)
    {

        $requestClass = match ($type) {
            'FE' => ElectronicInvoiceRequest::class,
            'FEE' => ElectronicExportInvoiceRequest::class,
            'FEC' => ElectronicPurchaseInvoiceRequest::class,
            'TE' => ElectronicTicketRequest::class,
            'ND' => DebitNoteRequest::class,
            'NC' => CreditNoteRequest::class,
            'REP' => ElectronicPaymentReceiptRequest::class,
            default => throw new InvalidReceiptException('Invalid receipt type'),
        };

        $requestInstance = new $requestClass();

        // Inject the data into the request instance and validate it
        $requestInstance->replace($data);

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

        if (method_exists($requestInstance, 'withValidator')) {
            $requestInstance->withValidator($validator);
        }

        return $validator->validate();
    }
}
