<?php

namespace App\Services;

use App\Crm\Config\DealerKitCrmConfig;
use App\Crm\EnquiryDataToProviderData;
use App\Modules\Stock\Config\DealerKitConfig;
use Illuminate\Http\Client\Response;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use Mtc\Crm\Contracts\EnquiryActionModel;
use Mtc\Crm\Contracts\EnquiryModel;
use Mtc\MercuryDataModels\ApiNotification;
use Mtc\MercuryDataModels\Vehicle;
use Mtc\MercuryDataModels\VehicleValuation;

class DealerKitApi
{
    use EnquiryDataToProviderData;

    private const LIVE_URL = 'https://api.dealerkit.uk';
    private const TEST_URL = 'https://api.dealerkit.test';
    private const STOCK_PROVIDER_KEY = 'dealerkit';
    public const NOTIFICATION_PROVIDER = 'dealerkit-crm';

    private ?Response $response = null;
    private ?string $skippedReason = null;

    public function __construct(
        private readonly DealerKitConfig $stockConfig,
        private readonly DealerKitCrmConfig $crmConfig,
    ) {
    }

    public function getStockPage(
        int|string $dealerId,
        int $page = 1,
        int $perPage = 50,
        bool $specifications = true
    ): array {
        return $this->get('/integrators/stock', [
            'dealer_id' => $dealerId,
            'page' => $page,
            'per_page' => $perPage,
            'specifications' => $specifications ? 'true' : 'false',
        ]);
    }

    public function get(string $path, array $query = []): array
    {
        $response = Http::withToken((string) $this->stockConfig->apiSecret())
            ->acceptJson()
            ->get($this->endpoint($path), $query)
            ->onError(fn (Response $error) => Log::error('DealerKit API error', [
                'path' => $path,
                'status' => $error->status(),
                'body' => $error->body(),
            ]));

        return $response->json() ?? [];
    }

    public function sendLead(EnquiryModel $enquiry, EnquiryActionModel $action): bool
    {
        $this->response = null;
        $this->skippedReason = null;

        $payload = $this->buildLeadPayload($enquiry);

        if ($payload === null) {
            $this->logNotification([], null, false);
            return false;
        }

        $this->response = Http::withToken((string) $this->crmConfig->apiSecret())
            ->acceptJson()
            ->post($this->leadEndpoint(), $payload);

        $success = $this->response->status() === 201;
        $this->logNotification($payload, $this->response, $success);

        return $success;
    }

    public function getResponseAttribute(string $attribute): mixed
    {
        return $this->response?->json($attribute);
    }

    public function getSkippedReason(): ?string
    {
        return $this->skippedReason;
    }

    public function getResponseStatus(): ?int
    {
        return $this->response?->status();
    }

    public function endpoint(string $path): string
    {
        return $this->buildUrl($this->stockConfig->useLiveApi(), $path);
    }

    private function leadEndpoint(): string
    {
        return $this->buildUrl($this->crmConfig->useLiveApi(), '/integrators/leads');
    }

    private function buildUrl(bool $live, string $path): string
    {
        $base = $live ? self::LIVE_URL : self::TEST_URL;
        return $base . '/' . ltrim($path, '/');
    }

    protected function buildLeadPayload(EnquiryModel $enquiry): ?array
    {
        $params = $this->convertEnquiryToParams($enquiry, 'dealerkit-field');
        $stockListingId = $this->resolveStockListingId($enquiry);
        $valuationVehicle = $this->mapValuationVehicle($enquiry);

        if ($stockListingId !== null) {
            $payload = [
                'type' => 'sales',
                'person' => $this->mapPerson($params),
                'stock_listing_id' => $stockListingId,
            ];
            if ($valuationVehicle !== null) {
                $payload['part_exchange'] = $valuationVehicle;
            }
            return $this->appendCommonFields($payload, $params, $enquiry);
        }

        if ($this->hasAnyAttachedVehicle($enquiry)) {
            $this->skippedReason = 'Attached vehicle is not DealerKit-sourced';
            return null;
        }

        if ($valuationVehicle !== null) {
            $payload = [
                'type' => 'buying',
                'person' => $this->mapPerson($params),
                'vehicle' => $valuationVehicle,
            ];
            return $this->appendCommonFields($payload, $params, $enquiry);
        }

        $this->skippedReason = 'No DealerKit-sourced vehicle or valuation attached to enquiry';
        return null;
    }

    private function appendCommonFields(array $payload, array $params, EnquiryModel $enquiry): array
    {
        if (!empty($params['message.plain'])) {
            $payload['message'] = ['plain' => (string) $params['message.plain']];
        }
        if (!empty($params['note'])) {
            $payload['note'] = (string) $params['note'];
        }
        if ($tracking = $this->mapTracking($enquiry)) {
            $payload['tracking'] = $tracking;
        }
        return $payload;
    }

    private function hasAnyAttachedVehicle(EnquiryModel $enquiry): bool
    {
        foreach ($enquiry->objects as $object) {
            if ($object->object_type === 'vehicle' && $object->object) {
                return true;
            }
        }
        return false;
    }

    private function mapPerson(array $params): array
    {
        $person = $this->filterEmpty([
            'title' => $params['person.title'] ?? null,
            'first_name' => $params['person.first_name'] ?? null,
            'last_name' => $params['person.last_name'] ?? null,
            'company_name' => $params['person.company_name'] ?? null,
            'email' => $params['person.email'] ?? null,
            'telephone' => $params['person.telephone'] ?? null,
        ]);

        $methods = $this->parseContactMethods($params);
        $person['marketing_consent'] = [
            'sms' => in_array('sms', $methods),
            'email' => in_array('email', $methods),
            'telephone' => in_array('phone', $methods),
        ];
        $person['updated_at'] = now()->format('Y-m-d H:i:s');

        return $person;
    }

    private function resolveStockListingId(EnquiryModel $enquiry): ?string
    {
        foreach ($enquiry->objects as $object) {
            if ($object->object_type !== 'vehicle' || !$object->object) {
                continue;
            }
            /** @var Vehicle $vehicle */
            $vehicle = $object->object;
            if ($vehicle->stock_provider === self::STOCK_PROVIDER_KEY && !empty($vehicle->uuid)) {
                return (string) $vehicle->uuid;
            }
        }
        return null;
    }

    private function mapValuationVehicle(EnquiryModel $enquiry): ?array
    {
        foreach ($enquiry->objects as $object) {
            if ($object->object_type !== 'valuation' || !$object->object instanceof VehicleValuation) {
                continue;
            }
            $valuation = $object->object;
            if (empty($valuation->registration) || !isset($valuation->mileage)) {
                return null;
            }
            return [
                'vrm' => (string) $valuation->registration,
                'mileage' => (int) $valuation->mileage,
            ];
        }
        return null;
    }

    private function mapTracking(EnquiryModel $enquiry): array
    {
        $meta = $enquiry->data['meta'] ?? [];
        return $this->filterEmpty([
            'landing_page_url' => $meta['source_url'] ?? null,
            'referrer' => $meta['referrer'] ?? null,
            'utm_campaign' => $meta['utm_campaign'] ?? null,
            'utm_content' => $meta['utm_content'] ?? null,
            'utm_medium' => $meta['utm_medium'] ?? null,
            'utm_source' => $meta['utm_source'] ?? null,
            'utm_term' => $meta['utm_term'] ?? null,
        ]);
    }

    private function filterEmpty(array $data): array
    {
        return array_filter($data, fn ($value) => $value !== null && $value !== '');
    }

    private function logNotification(array $payload, ?Response $response, bool $processed): void
    {
        ApiNotification::query()->create([
            'provider' => self::NOTIFICATION_PROVIDER,
            'processed' => $processed,
            'headers' => ['Authorization' => 'Bearer ' . (string) $this->crmConfig->apiSecret()],
            'data' => [
                'request' => $payload,
                'result' => $response?->body(),
                'http_status' => $response?->status(),
                'endpoint' => $this->leadEndpoint(),
                'skipped_reason' => $this->skippedReason,
            ],
            'data_model' => self::class,
        ]);
    }
}
