<?php

namespace App\Exports;

use App\Facades\Site;
use App\IntegrationRepository;
use App\SalesChannelType;
use App\Traits\UsesSalesChannelRules;
use App\VehicleType;
use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\WithHeadings;
use Mtc\ContentManager\Models\MediaUse;
use Mtc\MercuryDataModels\SalesChannelHistory;
use Mtc\MercuryDataModels\Tenant;
use Mtc\MercuryDataModels\Tools\UiUrlGenerator;
use Mtc\MercuryDataModels\Vehicle;

class EbayMotorsExport implements FromCollection, WithHeadings
{
    use UsesSalesChannelRules;

    /**
     * @return \Illuminate\Support\Collection
     */
    public function collection()
    {
        $collection = collect();
        Tenant::query()->whereNull('suspended_at')->get()->each(function (Tenant $tenant) use (&$collection) {
            tenancy()->initialize($tenant);

            if (new IntegrationRepository()->isEnabled('ebay-motors') !== true) {
                return;
            }

            try {
                $vehicles = $this->getVehicles();
                $collection = $collection->merge($vehicles);
                SalesChannelHistory::store('ebay-motors', true, $vehicles->count() . ' records exported');
            } catch (Exception $exception) {
                SalesChannelHistory::store('ebay-motors', false, $exception->getMessage());
            }
        });

        return $collection;
    }

    /**
     * Heading row
     *
     * @return string[]
     */
    public function headings(): array
    {
        return [
            'Feed_ID',
            'Vehicle_ID',
            'Registration',
            'Make',
            'Model',
            'Mileage',
            'Price',
            'Variant',
            'EngineSize',
            'FuelType',
            'TransmissionType',
            'VehicleType',
            'ManufacturerYear',
            'RegistrationDate',
            'RegLetter',
            'Vin',
            'NoDoors',
            'BodyStyle',
            'Colour',
            'PricePlusVat',
            'Description',
            'PictureRefs',
            'ProductURL',
            'Cap_ID',
            'New',
            'SalesTagline'
        ];
    }

    private function getVehicles()
    {
        return Vehicle::query()
            ->with([
                'mediaUses.media',
                'dealership',
                'make',
                'model',
                'transmission',
                'bodyStyle',
                'fuelType',
                'specs',
            ])
            ->exportable()
            ->when(
                $this->hasSalesChannelRules(SalesChannelType::EBAY_MOTORS),
                fn($query) => $this->applyQueryConditionsForChannel($query, SalesChannelType::EBAY_MOTORS)
            )
            ->get()
            ->map(fn(Vehicle $vehicle) => [
                'Feed_ID' => $vehicle->dealership?->data['ebay-motors-dealer-id'] ?? null,
                'Vehicle_ID' => $vehicle->uuid,
                'Registration' => str_replace(' ', '', $vehicle->registration_number),
                'Make' => $vehicle->make?->name,
                'Model' => $vehicle->model?->name,
                'Mileage' => $vehicle->odometer_mi,
                'Price' => $vehicle->price,
                'Variant' => $vehicle->derivative,
                'EngineSize' => $vehicle->engine_size_cc,
                'FuelType' => $vehicle->fuelType?->name,
                'TransmissionType' => $vehicle->transmission?->name,
                'VehicleType' => $this->getVehicleType($vehicle->type),
                'ManufacturerYear' => $vehicle->manufacture_year,
                'RegistrationDate' => $vehicle->first_registration_date?->format('d/m/Y'),
                'RegLetter' => $this->getRegLetter($vehicle->registration_number),
                'Vin' => $vehicle->vin,
                'NoDoors' => $vehicle->door_count,
                'BodyStyle' => $vehicle->bodyStyle?->name,
                'Colour' => $vehicle->colour,
                'PricePlusVat' => $vehicle->type === VehicleType::CAR->value ? 0 : 1,
                'Description' => $this->getSanitisedDescription($vehicle->description),
                'PictureRefs' => $vehicle->mediaUses
                    ->filter(fn($mediaUse) => $mediaUse->media)
                    ->map(fn(MediaUse $mediaUse) => $mediaUse->media->getOriginalUrlAttribute(true))
                    ->implode(','),
                'ProductURL' => Site::vehicleUrl($vehicle),
                'Cap_ID' => $vehicle->cap_id,
                'New' => ($vehicle->is_new) ? 'new' : 'used',
                'SalesTagline' => $vehicle->attention_grabber
            ]);
    }

    private function getSanitisedDescription(?string $description): string
    {
        if (empty($description)) {
            return '';
        }
        $placeholder_gbp = '((GBP))';
        $placeholder_eur = '((EUR))';

        // remove tags
        $description = strip_tags($description);

        // can't get regex to exclude a range but still allow £ and €,
        // so handle with placeholders to be replaced later.
        $description = str_replace('£', $placeholder_gbp, $description);
        $description = str_replace('€', $placeholder_eur, $description);

        // remove non-printable ASCII characters.
        // ^ negates the following pattern
        // SPACE-~ represents the range of ASCII characters between (and including) SPACE and ~
        // so, replace any characters not in the pattern.
        $description = preg_replace('/[^ -~]/', '', $description);

        // replace placeholder values
        $description = str_replace($placeholder_gbp, '£', $description);
        $description = str_replace($placeholder_eur, '€', $description);

        return trim($description);
    }

    private function getVehicleType($type = ''): int
    {
        $vehicleType = 1;
        if ($type == VehicleType::LCV) {
            $vehicleType = 7;
        } elseif ($type == VehicleType::MOTORCYCLE) {
            $vehicleType = 3;
        }

        return $vehicleType;
    }

    private function getRegLetter($registrationNumber = '')
    {
        $regLetter = '';

        if (!empty($registrationNumber)) {
            $number = substr((string) $registrationNumber, 2, 2);
            if (is_numeric($number)) {
                $regLetter = $number > 50 ? $number - 50 : $number;
            }
        }

        return $regLetter;
    }
}
