<?php

namespace App\VehicleSpec\Services;

use App\VehicleSpec\Config\HPICapIdLookupConfig;
use Mtc\MercuryDataModels\VehicleType;
use Exception;
use Illuminate\Http\Client\Response;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use Mtc\MercuryDataModels\Vehicle;

class HPICapIdLookupService
{
    protected static string $endpointLive = 'https://wss.hpi.co.uk/TradeSoap/services/SupplementaryEnquiryV1/';
    protected static string $endpointTest = 'https://pat-wss.hpi.co.uk/TradeSoap/services/SupplementaryEnquiryV1/';

    public function __construct(protected readonly HPICapIdLookupConfig $config)
    {
    }

    public function lookup(Vehicle $vehicle): array
    {
        if (!$this->config->enabled()) {
            return [];
        }

        try {
            $response = $this->call($this->getVehicleRequest($vehicle));
            return $this->parseResponse($response->body());
        } catch (Exception $exception) {
            Log::error(tenant('id') . ' - ' . $exception->getMessage(), [
                'vehicle_id' => $vehicle->id,
                'vrm' => $vehicle->vrm_condensed,
            ]);
            return [];
        }
    }

    protected function call(array $requestData): Response
    {
        $response = Http::withHeaders($this->getHeaders())
            ->timeout(20)
            ->withBody($this->getEnvelope($requestData), 'text/xml')
            ->post($this->endpoint());

        if ($response->failed()) {
            $this->logSoapFault($response->body(), $requestData);
            throw new Exception('Failed to perform HPI CAP ID lookup call to ' . $this->endpoint());
        }

        return $response;
    }

    protected function getEnvelope(array $requestData): string
    {
        return view('hpi_enquiry_request', ['data' => $requestData])->render();
    }

    protected function endpoint(): string
    {
        return app()->environment() === 'production' || true
            ? self::$endpointLive
            : self::$endpointTest;
    }

    protected function getVehicleRequest(Vehicle $vehicle): array
    {
        return [
            'subscriber_details' => [
                'customer_code' => $this->config->customerCode(),
                'initials' => $this->config->initials(),
                'password' => $this->config->password(),
            ],
            'asset' => [
                'vrm' => $vehicle->vrm_condensed,
                'vin' => $vehicle->vin ?? '',
                'mileage' => $vehicle->odometer_mi ?? '',
                'reference' => '',
            ],
            'primary_product' => $this->config->primaryProductCode(),
            'supplementary_product' => $this->config->supplementaryProductCode(),
        ];
    }

    protected function getHeaders(): array
    {
        return [
            'Content-Type' => 'text/xml; charset=utf-8',
            'SOAPAction' => 'http://webservices.hpi.co.uk/SupplementaryEnquiryV1/enquire',
        ];
    }

    protected function parseResponse(string $responseBody): array
    {
        $xml = simplexml_load_string($responseBody);

        if ($xml === false) {
            Log::error('Failed to parse HPI CAP ID lookup response as XML', [
                'response' => $responseBody,
            ]);
            return [];
        }

        $body = $xml->children('http://schemas.xmlsoap.org/soap/envelope/')->Body;

        if (isset($body->Fault)) {
            $this->logSoapFault($responseBody);
            return [];
        }

        $results = $body
            ->children('http://webservices.hpi.co.uk/SupplementaryEnquiryV1')
            ->EnquiryResponse
            ->RequestResults;

        $capData = $results->Asset->SupplementaryAssetData->CAP ?? null;

        if ($capData === null) {
            return [];
        }

        $capId = (string)($capData->CAPId ?? '');
        $capCode = (string)($capData->CAPCode ?? '');
        $vehicleType = (string)($capData->VehicleType ?? '');

        if (empty($capId)) {
            return [];
        }

        $dvla = $results->Asset->PrimaryAssetData->DVLA ?? null;
        $smmt = $results->Asset->PrimaryAssetData->SMMT ?? null;

        return [
            'cap_id' => $capId,
            'cap_code' => $capCode,
            'type' => $this->mapVehicleType($vehicleType),
            'make' => $dvla ? (string)($dvla->Make->Description ?? '') : '',
            'model' => $dvla ? (string)($dvla->Model->Description ?? '') : '',
            'smmt_model' => $smmt ? $this->cleanSmmtDescription((string)($smmt->Model->Description ?? '')) : '',
            'fuel_type' => $dvla ? (string)($dvla->Engine->Fuel->Description ?? '') : '',
            'body_style' => $dvla ? (string)($dvla->Body->Description ?? '') : '',
            'transmission' => $smmt ? (string)($smmt->Transmission->Description ?? '') : '',
        ];
    }

    protected function logSoapFault(string $responseBody, array $requestData = []): void
    {
        $xml = simplexml_load_string($responseBody);
        $errorCode = '';
        $errorDescription = '';

        if ($xml !== false) {
            $body = $xml->children('http://schemas.xmlsoap.org/soap/envelope/')->Body;
            if (isset($body->Fault)) {
                $fault = $body->Fault;
                $detail = $fault->detail->children('http://webservices.hpi.co.uk/SupplementaryEnquiryV1');
                if (isset($detail->HpiSoapFault->Error)) {
                    $errorCode = (string)$detail->HpiSoapFault->Error->Code;
                    $errorDescription = (string)$detail->HpiSoapFault->Error->Description;
                }
            }
        }

        Log::error('HPI CAP ID lookup SOAP fault', [
            'endpoint' => $this->endpoint(),
            'error_code' => $errorCode,
            'error_description' => $errorDescription,
            'request_data' => array_merge($requestData, [
                'subscriber_details' => ['password' => '***REDACTED***'],
            ]),
            'response' => $responseBody,
        ]);
    }

    /**
     * SMMT model descriptions carry a platform code suffix, e.g. "TERRAMAR (SE336)".
     */
    protected function cleanSmmtDescription(string $description): string
    {
        return trim(preg_replace('/\s*\([^)]*\)/', '', $description));
    }

    protected function mapVehicleType(string $vehicleType): ?string
    {
        return match ($vehicleType) {
            'L' => VehicleType::LCV->value,
            default => VehicleType::CAR->value,
        };
    }
}
