<?php

namespace App\Imports;

use App\Events\NewVehicleImported;
use App\Facades\Settings;
use App\TaxonomyMap;
use App\Traits\MapsTaxonomies;
use App\VehicleType;
use Carbon\Carbon;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Event;
use Maatwebsite\Excel\Concerns\ToCollection;
use Mtc\ContentManager\Facades\Media;
use Mtc\MercuryDataModels\Dealership;
use Mtc\MercuryDataModels\Services\FinanceService;
use Mtc\MercuryDataModels\Services\FinanceServiceHelper;
use Mtc\MercuryDataModels\Vehicle;
use Mtc\MercuryDataModels\VehicleModel;
use Maatwebsite\Excel\Concerns\SkipsFailures;
use Maatwebsite\Excel\Concerns\WithCustomCsvSettings;

class KeyloopRev8StockImport implements ToCollection, WithCustomCsvSettings
{
    use MapsTaxonomies;
    use SkipsFailures;

    public function __construct(private readonly ?string $filename)
    {
    }

    private Collection $dealerships;

    /**
     * @param Collection $collection
     */
    public function collection(Collection $collection): void
    {
        $this->dealerships = Dealership::query()
            ->with('franchise')
            ->get()
            ->each(function (Dealership $dealership) {
                $dealership->stock_location = $dealership->data['keyloop-rev8-location-id'] ?? null;
            });

        $stock = $collection->filter(fn($vehicle) => $this->filterByPrice($vehicle));
        $stock->each(fn(Collection $vehicle) => $this->syncVehicle($vehicle));

        $this->removeOld($stock);
    }


    /**
     * Filter out vehicles depending on price settings
     *
     * @param array $vehicle
     * @return bool
     */
    private function filterByPrice(Collection $vehicle): bool
    {
        if (Settings::get('stock-keyloop-rev8-sync-with-price') !== true) {
            return true;
        }

        return ($vehicle[13]) > 0;
    }

    /**
     * Sync vehicle record
     *
     * @param array $data
     * @return void
     */
    private function syncVehicle(Collection $data): void
    {
        $registrationDate = $arrivalDate = null;
        if (!empty($data[20] > 0)) {
            if (is_numeric($data[20])) {
                // Date offset: https://www.epochconverter.com/seconds-days-since-y0
                $registrationDate = Carbon::create(1900)->addDays($data[20])->subDays(2);
            } else {
                try {
                    $registrationDate = Carbon::createFromFormat('d/m/Y', $data[20]);
                } catch (\Exception $exception) {
                    //
                }
            }
        }
        if (!empty($data[21])) {
            if (is_numeric($data[21])) {
                // Date offset: https://www.epochconverter.com/seconds-days-since-y0
                $arrivalDate = Carbon::create(1900)->addDays($data[21])->subDays(2);
            } else {
                try {
                    $arrivalDate = Carbon::createFromFormat('d/m/Y', $data[21]);
                } catch (\Exception $exception) {
                    //
                }
            }
        }
        /** @var Vehicle $vehicle */
        $vehicle = Vehicle::query()
            ->firstOrNew([
                'stock_provider' => 'rev8' . ($this->filename ? '-' . $this->filename : ''),
                'uuid' => trim($data[1]),
            ]);

        $makeId = null;
        if ($data[9] != 'Other') {
            $makeId = $this->getMappedTaxonomy(TaxonomyMap::MAKE, $data[9], $data->toArray());
        }

        $modelId = null;
        if (!in_array($data[10], ['Non Franchise', 'NON FRANCHISE MODEL'])) {
            $model = $data[10];
            $modelId = $this->getMappedTaxonomy(TaxonomyMap::MODEL, $model, $data->toArray());
        }

        $isPublished = in_array($data[24], ['A', 'R']);
        if ($data[10] === 'Demonstrator' && $data[24] === 'R') {
            $isPublished = false;
        }

        $type = $data[17] == 'MB Poole CV' ? VehicleType::LCV->value : VehicleType::CAR->value;
        $vat_applicable = in_array($data[22], ['Y', 'G']) && ($type ?? 'car') == VehicleType::CAR->value;
        // update all
        $vehicle->fill([
            'is_published' => $isPublished,
            'is_reserved' => $data[24] === 'R',
            'price' => $vat_applicable ? trim($data[13]) * 1.2 : trim($data[13]),
            'first_registration_date' => $registrationDate,
            'manufacture_year' => $registrationDate?->year ?? $data[5],
            'stock_arrival_date' => $arrivalDate,
            'dealership_id' => $this->dealershipId($data[17], $this->isAvocadoStock($data)),
            'body_style_id' => $this->getMappedTaxonomy(TaxonomyMap::BODY_STYLE, $data[7], $data->toArray()),
            'attention_grabber' => $data[25] ?? null,
            'registration_number' => $data[2],
            'odometer_mi' => $data[6],
            'type' => $type
        ]);
        $vrm_changed = $vehicle->isDirty('registration_number');
        if ($vrm_changed) {
            $vehicle->cap_id = null;
        }

        if (!empty($modelId)) {
            $vehicle->model_id = $modelId;
        }

        // only new
        if ($vehicle->exists === false) {
            $vehicle->fill([
                'colour' => ucwords(strtolower($data[3])),
                'fuel_type_id' => $this->getMappedTaxonomy(TaxonomyMap::FUEL_TYPE, $data[4], $data->toArray()),
                'door_count' => $data[8],
                'make_id' => $makeId,
                'model_id' => $modelId,
                'derivative' => $data[11],
                'title' => $data[11],
                'engine_size_cc' => $data[12],
                'transmission_id' => $this->getMappedTaxonomy(TaxonomyMap::TRANSMISSION, $data[14], $data->toArray()),
                'is_new' => $data[15] === 'YES',
                'is_demo' => $data[18] === 'YES',
                'vin' => $data[19],
                'is_vat_applicable' => $data[22] !== 'N',
                'attention_grabber' => $data[25] ?? null,
            ]);
        }
        $vehicle->save();

        $this->updateImages($vehicle);

        $this->storeUnmappedTaxonomy($vehicle);

        if ($vehicle->wasRecentlyCreated || $vrm_changed) {
            Event::dispatch(new NewVehicleImported($vehicle, $data->toArray()));
        }
    }

    /**
     * Remove vehicles that are not part of the stock feed
     *
     * @param Collection $vehicles
     * @return void
     */
    private function removeOld(Collection $vehicles)
    {
        Vehicle::query()
            ->where('stock_provider', 'rev8' . ($this->filename ? '-' . $this->filename : ''))
            ->whereNotIn('uuid', $vehicles->map(fn($entry) => trim($entry[1])))
            ->delete();
    }

    private function isAvocadoStock($data)
    {
        return $data['24'] == 'A' && in_array(trim($data[10]), ['NON FRANCHISE MODEL', 'Non Franchise']);
    }

    /**
     * Get the dealership id from stock location
     *
     * @param $locationId
     * @return string|null
     */
    private function dealershipId($locationId, $isAvocado = false): ?string
    {
        $filteredDealerships = $this->dealerships->filter(function ($dealership) use ($isAvocado) {
            if ($isAvocado) {
                return $dealership->franchise?->slug === 'avocado';
            } else {
                return $dealership->franchise?->slug !== 'avocado';
            }
        });

        return $filteredDealerships->where('stock_location', $locationId)
            ->first()
            ?->id;
    }

    protected function getProviderName(): string
    {
        return 'keyloop-rev8';
    }

    private function updateTaxonomyModel($modelId, $value): void
    {
        $model = VehicleModel::find($modelId);
        if (!empty($model) && $model->name != $value) {
            $model->name = $value;
            $model->save();
        }
    }

    public function getCsvSettings(): array
    {
        return [
            'input_encoding' => 'CP1252'
        ];
    }

    private function updateImages($vehicle): void
    {
        $vehicle->loadCount('mediaUses');

        if ($vehicle->media_uses_count > 0) {
            return;
        }

        $oldVehicle = Vehicle::query()
            ->onlyTrashed()
            ->withCount('mediaUses')
            ->with('mediaUses')
            ->when(!empty($vehicle->vin), fn ($query) => $query->where('vin', $vehicle->vin))
            ->when(
                empty($vehicle->vin) && !empty($vehicle->registration_number),
                fn ($query) => $query->where('registration_number', $vehicle->registration_number)
            )
            ->first();

        if ($oldVehicle && $oldVehicle->media_uses_count > 0) {
            Media::setUsesForModel(
                $oldVehicle->mediaUses->pluck('media_id')->toArray(),
                $vehicle,
                ['primary' => true]
            );
        }
    }
}
