<?php

namespace App\Modules\Stock;

use App\Contracts\StockProvider;
use App\Events\NewVehicleImported;
use App\Events\StockSyncFinished;
use App\Events\VehicleUpdatedFromImport;
use App\Facades\Settings;
use App\Jobs\ImportImagesFromUrlList;
use App\TaxonomyMap;
use App\Traits\ImportChecksConditions;
use App\Traits\StockSyncTraits;
use App\VehicleType;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use Mtc\MercuryDataModels\Dealership;
use Mtc\MercuryDataModels\Vehicle;

class DMSNavigator implements StockProvider
{
    use DispatchesJobs;
    use StockSyncTraits;
    use ImportChecksConditions;

    public const NAME = 'dms-navigator';
    private Collection $dealerships;
    private array $make = [];
    private array $model = [];
    private array $transmission = [];
    private array $body_style = [];
    private array $fuel_type = [];

    /**
     * Check if enabled
     *
     * @return bool
     */
    public function enabled(): bool
    {
        return Settings::get('stock-dms-navigator-enabled', false) ?? false;
    }

    /**
     * Name of the integration
     *
     * @return string
     */
    public function name(): string
    {
        return 'DMS Navigator';
    }

    /**
     * Perform a scheduled import task
     *
     * @return void
     */
    public function runScheduledImport(bool $fullSync = true): void
    {
        $this->loadDealerships();
        $this->import($this->fetchVehicles($this->endpoint())->unique('STOCK'));

        Event::dispatch(new StockSyncFinished(self::NAME));
    }

    /**
     * Fields to add to dealership management
     *
     * @return array[]
     */
    public function dealershipAdditionalDataFields()
    {
        return [
            'dms-navigator-dealer-id' => [
                'type' => 'text',
                'label' => 'Location ID within DMS Navigator',
            ],
        ];
    }

    /**
     * API endpoint
     *
     * @return string
     */
    public function endpoint(string $type = 'stock', string $data = ''): string
    {
        return match ($type) {
            'stock' => 'https://services.dmservices.co.uk/DmsNavigator.NavigatorWebService.svc/GetNavigatorReport/'
                . Settings::get('stock-dms-navigator-api-key') . ',1,XML_VEHICLE_STOCK_LIST,json,1,STOCKFEED1,,1,1',
            'image' => 'https://services.dmservices.co.uk/DmsNavigator.NavigatorWebService.svc/GetImage/'
                . Settings::get('stock-dms-navigator-api-key') . ',1,' . $data
        };
    }

    /**
     * Get the vehicle data from API
     *
     * @param string $endpoint
     * @return Collection
     */
    public function fetchVehicles(string $endpoint): Collection
    {
        $response = Http::withOptions(['verify' => false])->get($endpoint);

        if ($response->successful()) {
            return collect($response->json('x:reports.report'));
        }

        Log::warning('DMS Navigator sync issue', [
            'tenant' => tenant('id'),
            'endpoint' => $endpoint,
            'response_code' => $response->status(),
            'response' => $response->body(),
        ]);

        return collect([]);
    }

    protected function getProviderName(): string
    {
        return 'dms-navigator';
    }

    protected function getDetailsForTaxonomyMap(array $record): array
    {
        return [
            'tenant_id' => tenant('id'),
            'registration_number' => $record['Reg'],
            'make' => $record['Make'],
            'model' => $record['Model'],
        ];
    }

    /**
     * Import vehicles
     *
     * @param Collection $stock
     * @return void
     */
    private function import(Collection $stock)
    {
        $stock = $this->filterAvailable($stock);
        $stock->each(fn(array $vehicle) => $this->syncVehicle($vehicle));

        $this->removeOld($stock->pluck('STOCK'));
    }

    /**
     * Filter available records
     *
     * @param Collection $stock
     * @return Collection
     */
    private function filterAvailable(Collection $stock): Collection
    {
        $webOnly = Settings::get('stock-dms-navigator-sync-only-for-website');
        $saleOnly = Settings::get('stock-dms-navigator-sync-only-available-for-sale');
        $exportOnly = Settings::get('stock-dms-navigator-sync-only-available-for-sale');
        return $stock->when($exportOnly, fn(Collection $list) => $list->filter(fn($entry) => $entry['Export']))
            ->when($webOnly, fn(Collection $list) => $list->filter(fn($entry) => $entry['Advertise on Own Web Site']))
            ->when($saleOnly, fn(Collection $list) => $list->filter(fn($entry) => $entry['Available for Sale']));
    }

    /**
     * Sync vehicle record
     *
     * @param array $data
     * @return void
     */
    private function syncVehicle(array $data): void
    {
        $make_id = $this->getMappedTaxonomy(TaxonomyMap::MAKE, $data['Make'], $data);
        /** @var Vehicle $vehicle */
        $vehicle = Vehicle::query()
            ->where('uuid', $data['STOCK'])
            ->firstOrNew([
                'stock_provider' => self::NAME,
                'uuid' => $data['STOCK'],
            ], [
                'type' => $data['Commercial'] ? VehicleType::LCV->value : VehicleType::CAR->value,
                'uuid' => $data['STOCK'],
                'title' => $data['Make'] . ' ' . $data['Model'],
                'derivative' => $data['Derivative'],
                'registration_number' => $data['Reg'],
                'engine_size_cc' => $data['Engine Size'],
                'fuel_type_id' => $this->getMappedTaxonomy(TaxonomyMap::FUEL_TYPE, $data['Engine Type'], $data),
                'colour' => $data['Colour'],
                'body_style_id' => $this->getMappedTaxonomy(TaxonomyMap::BODY_STYLE, $data['Body Style'], $data),
                'make_id' => $make_id,
                'model_id' => $this->getMappedTaxonomy(TaxonomyMap::MODEL, $data['Model'], $data, $make_id),

                'dealership_id' => $this->dealershipId($data['Location']),
            ]);

        // Capture original price before update for numeric comparison
        $originalPrice = $vehicle->price;

        $vehicle->fill([
            'transmission_id' => $this->getMappedTaxonomy(TaxonomyMap::TRANSMISSION, $data['Transmission'], $data),
            'manufacture_year' => $data['Year'],
            'odometer_mi' => $data['Mileage'],
            'odometer_km' => $vehicle->milesToKm($data['Mileage']),
            'price' => $data['Web price'] ?? $data['Retail'],
            'is_new' => $data['Type'] === 'New',
            'dealership_id' => $this->dealershipId($data['Location']),
            'vin' => $data['Chassis'],

        ]);

        $vehicle->is_published = $this->shouldBePublished(
            fn() => $vehicle->is_published,
            'dms-navigator',
            $vehicle,
        );
        $vehicle->save();

        if ($this->shouldSyncImages($vehicle, $data)) {
            $this->syncImages($vehicle, $data['ImageList']);
        }

        $this->storeUnmappedTaxonomy($vehicle);

        if ($vehicle->wasRecentlyCreated) {
            Event::dispatch(new NewVehicleImported($vehicle, $data, $this->getProviderName()));
        } else {
            Event::dispatch(new VehicleUpdatedFromImport($vehicle, $data, $this->getProviderName()));
        }

        if ($vehicle->wasChanged('price')) {
            $this->priceChangeEvents($vehicle, 'motordat', $originalPrice);
        }
    }


    /**
     * Check if images should be synced for vehicles
     *
     * @param Vehicle $vehicle
     * @param array $data
     * @return bool
     */
    private function shouldSyncImages(Vehicle $vehicle, array $data): bool
    {
        return !empty($data['Image'])
            && $vehicle->mediaUses()->exists() === false;
    }

    /**
     * Sync images for vehicle
     *
     * @param Vehicle $vehicle
     * @param array $images
     * @return void
     */
    private function syncImages(Vehicle $vehicle, string $imageListString)
    {
        $imageList = collect(explode(';', $imageListString))->map(fn($image) => $this->endpoint('image', $image));
        $this->dispatch(new ImportImagesFromUrlList($imageList, $vehicle));
    }

    /**
     * Load all dealerships
     *
     * @return void
     */
    private function loadDealerships()
    {
        $this->dealerships = Dealership::all()
            ->each(function (Dealership $dealership) {
                $dealership->stock_location = $dealership->data['dms-navigator-dealer-id'] ?? null;
            });
    }

    /**
     * Get the dealership id from stock location
     *
     * @param $locationId
     * @return string|null
     */
    private function dealershipId($locationId): ?string
    {
        return $this->dealerships
            ->where('stock_location', $locationId)
            ->first()
            ?->stock_location;
    }
}
