<?php

namespace App\Http\Resources;

use App\Facades\Feature;
use App\Facades\Settings;
use App\Http\Resources\VehicleAction\FinanceFactory;
use App\Http\Resources\VehicleAction\LoadsVehicleActions;
use App\Traits\GetsFormResource;
use App\Traits\HasCarAndDrivingVideo;
use App\Traits\HasPlaceholderImage;
use App\Traits\RetrievesContent;
use Carbon\Carbon;
use Illuminate\Http\Resources\Json\JsonResource;
use Illuminate\Support\Collection;
use Mtc\MercuryDataModels\Events\LoadVehicleDataFields;
use Mtc\MercuryDataModels\Traits\HasVehicleCustomAttributes;
use Mtc\MercuryDataModels\VehicleFinance;
use Mtc\MercuryDataModels\VehicleStandardEquipment;
use Mtc\MercuryDataModels\VehicleType;
use App\Http\Resources\Traits\FormatsAutoTraderData;
use App\Http\Resources\Traits\TransformsImageAttributesForDisplay;

class VehicleResource extends JsonResource
{
    use LoadsVehicleActions;
    use FormatsAutoTraderData;
    use HasPlaceholderImage;
    use RetrievesContent;
    use HasVehicleCustomAttributes;
    use GetsFormResource;
    use HasCarAndDrivingVideo;
    use FormatsLabelsForDisplay;
    use TransformsImageAttributesForDisplay;

    private const array EMISSION_STANDARD_NAMES = ['Standard Euro Emissions'];

    private const array EMISSION_STANDARD_CLASSES_CARS = ['euro 4', 'euro 5', 'euro 6'];

    private const array EMISSION_STANDARD_CLASSES_MOTORCYCLES = ['euro 3', 'euro 4', 'euro 5', 'euro 6'];

    public static $wrap = '';

    /**
     * Transform the resource into an array.
     *
     * @param \Illuminate\Http\Request $request
     * @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
     */
    #[\Override]
    public function toArray($request)
    {
        $this->resource->fuel_type = $this->resource->fuelType?->name;
        $this->resource->transmission = $this->resource->transmission?->name;
        $this->resource->body_style = $this->resource->bodyStyle?->name;
        $this->resource->load([
            'mediaUses.media',
            'dealership.departments',
            'specs',
            'features',
            'equipment.filterFeature',
        ]);

        if (Settings::get('vehicle-labels-enabled')) {
            $this->resource->load([
                'labels'
            ]);
        }

        $this->resource->specs = $this->resource->specs->map(fn ($spec) => [
            'category' => trim((string)$spec->category),
            'description' => $spec->description,
            'value' => $spec->value,
        ]);
        $replaceEquipmentName = Settings::get('automotive-vehicle-filters-features-replace-equipment-name');
        $this->resource->equipment = $this->resource->equipment
            ->map(function ($equipment) use ($replaceEquipmentName) {
                $filterFeature = $equipment->filterFeature;
                return [
                    'type'                   => $equipment->type,
                    'description'            => ($replaceEquipmentName && $filterFeature)
                        ? $filterFeature->name
                        : $equipment->description,
                    'category'               => $equipment->category,
                    'price'                  => $equipment->price,
                    'vat_amount'             => $equipment->vat_amount,
                    'code'                   => $equipment->code,
                    'additional_description' => $filterFeature?->description ?? null,
                ];
            })
            ->sortBy('category')
            ->values();

        $this->resource->highlights = $this->resource->features
            ->filter(fn ($feature) => $feature->category === 'Highlight')
            ->pluck('name');

        if ($request->input('features_split_by_type')) {
            $this->resource->features = $this->resource->features
                ->reject(fn ($feature) => $feature->category === 'Highlight')
                ->groupBy('category')
                ->map(fn ($group) => $group->pluck('name'));
        } else {
            $this->resource->features = $this->resource->features
                ->reject(fn ($feature) => $feature->category === 'Highlight')
                ->pluck('name');
        }

        $this->resource->actions = $this->getVehicleActions($this->resource);

        $this->resource->content = $this->getContent();

        if ($this->resource->dealership) {
            $this->resource->dealership->address = collect([
                $this->resource->dealership->address1,
                $this->resource->dealership->address2,
                $this->resource->dealership->city,
                $this->resource->dealership->postcode,
            ])->filter()->implode(', ');
        }

        $finance_calculator = $this->getFinanceData();

        $dealership_whatsapp_number = $this->resource->dealership?->data['whatsapp-phone-number'] ?? null;

        $this->resource->forms = [
            'test_drive' => $this->getResourceForFormByEnquiryType(
                Settings::get('form-enquiry-type-test-drive') ?? '',
                'vehicle_id',
                [
                    'vehicle_id' => $this->resource->id,
                    'dealership_id' => $this->resource->dealership_id,
                    'franchise_id' => $this->resource->dealership?->franchise_id,
                ]
            ),
        ];

        $this->resource->dealership = $this->resource->dealership
            ? [
                ...$this->resource->dealership->only([
                    'slug',
                    'name',
                    'contact_no',
                    'address',
                    'is_open',
                    'opens_at',
                    'closes_at',
                    'franchise',
                    'location_stock',
                    'city',
                    'id',
                    'email',
                    'coordinates',
                ]),
                'departments' => $this->resource->dealership->departments->map->only([
                    'name', 'contact_no', 'email', 'open_times', 'is_primary',
                ]),
            ]
            : null;

        $additions = [];
        $this->resource->financeExamples
            ->each(fn (VehicleFinance $finance) => $finance->makeHidden([
                'id',
                'vehicle_id',
                'provider',
                'created_at',
                'updated_at',
            ]));
        $resource = $this->resource->only([
            ...$additions,
            'id',
            'uuid',
            'actions',
            'admin_fee',
            'is_reserved',
            'is_demo',
            'is_sold',
            'battery_capacity_kwh',
            'battery_charge_time',
            'battery_quick_charge_time',
            'battery_quick_charge_level',
            'battery_quick_charge_start_level',
            'battery_range',
            'battery_slow_charge_description',
            'battery_quick_charge_description',
            'battery_usable_capacity_kwh',
            'plug_type',
            'rapid_charge_plug_type',
            'bhp',
            'bodyStyle',
            'co2',
            'colour',
            'content',
            'dealership',
            'deposit',
            'derivative',
            'door_count',
            'drivetrain',
            'engine_size_cc',
            'equipment',
            'features',
            'highlights',
            'forms',
            'fuel_type',
            'gross_vehicle_weight_kg',
            'is_new',
            'is_vat_applicable',
            'is_vat_qualifying',
            'attention_grabber',
            'main_video_url',
            'make',
            'manufacture_year',
            'model',
            'mpg',
            'odometer_mi',
            'odometer_km',
            'payload_kg',
            'media_uses',
            'monthly_price',
            'original_price',
            'previous_price',
            'price',
            'registration_number',
            'rrp_price',
            'seats',
            'specs',
            'title',
            'transmission',
            'trim',
            'type',
            'wheelbase_mm',
            'wheelbase_type',
            'previous_owner_count',
            'is_sold',
            'vin',
            'first_registration_date',
            'ulez_compliance'
        ]);

        $resource['interior_video'] = !empty($this->resource->interior_video_url)
            ? [
                'url' => $this->resource->interior_video_url,
                'type' => $this->resource->data['interior_video_type'] ?? null,
            ]
            : null;

        if (!empty($resource['first_registration_date'])) {
            $resource['first_registration_date'] = Carbon::parse($resource['first_registration_date'])->format('Y-m-d');
        }

        if ($autoTraderData = $this->getAutoTraderData($this->resource)) {
            $resource['autoTraderData'] = $autoTraderData;
        }

        if (Settings::get('sales-channels-phyron-enabled')) {
            $resource['phyron'] = [
                'username' => Settings::get('sales-channels-phyron-username'),
                'product_key' => $this->resource->uuid,
            ];
        }

        if (Settings::get('automotive-vehicle-brand-on-filter-card')) {
            $resource['filter_features'] = $this->resource->featureEquipment()
                ->with('filterFeature')
                ->get()
                ->filter(fn (VehicleStandardEquipment $equipment) => $equipment->filterFeature)
                ->unique(fn (VehicleStandardEquipment $equipment) => $equipment->feature_id)
                ->map(fn (VehicleStandardEquipment $equipment) => [
                    'name' => $equipment->filterFeature->name,
                    'slug' => $equipment->filterFeature->slug,
                ])
                ->values();
        }

        if ($this->isCarAndDrivingEnabled()) {
            $resource['reviews'] ??= [];
            $resource['reviews']['car_and_driving'] ??= [];
            $resource['reviews']['car_and_driving']['video_url'] = $this->getCarAndDrivingVideoUrl($this->resource);
            $resource['reviews']['car_and_driving']['review'] = $this->resource->reviews()?->first()?->review ?? null;
        }

        if ($this->getDepositFlatRate()) {
            $resource['deposit'] = $this->getDepositFlatRate();
        } elseif (!empty($this->getFinanceExamples())) {
            $cheapest = collect($this->getFinanceExamples())->sortBy('monthly_price')->first();
            if ($cheapest) {
                $resource['deposit'] = $cheapest['customer_deposit'];
            }
        }

        $resource['media_uses'] = $this->getGallery($this->resource)?->values();
        $resource['monthly_cost_type'] = $this->resource->getMonthlyCostType();
        $resource['finance'] = $finance_calculator;
        $resource['financeExamples'] = $this->getFinanceExamples();
        $resource['show_deposit_vat'] = (bool) Settings::get('finance-show-deposit-vat');
        $resource['extra'] = $this->getExtraData();
        $resource['seo'] = $this->fillSeo('vehicle', request()->header('x-path'));
        $resource['social_meta'] = new SocialMetaResource($resource['seo']);
        $resource['age_identifier'] = $this->resource->getAgeIdentifier();
        $resource['custom'] = $this->resource->getAllCustom();
        $resource['vat_status'] = $this->resource->is_vat_applicable
            ? __('automotive.vat_status.inclusive')
            : __('automotive.vat_status.exclusive');
        $resource['coming_soon'] = $this->resource->getComingSoonStatus();
        $resource['labels'] = Settings::get('vehicle-labels-enabled')
            ? $this->formatLabelsForDisplay($this->resource->labels->whereIn('type', ['', 'all', 'fpa'])->values())
            : [];

        $resource['ulez_compliance'] = $this->getUlezCompliance();

        $resource['reservation_amount'] = $this->resource->getReservationAmount();

        $resource['dealership']['whatsapp_no'] = Settings::get('dealerships-whatsapp-enabled')
            ? $dealership_whatsapp_number
            : null;

        if ($this->resource->is_sold && Settings::get('vehicle-hide-sold-prices')) {
            $resource['price'] = null;
            $resource['original_price'] = null;
            $resource['previous_price'] = null;
            $resource['rrp_price'] = null;
            $resource['deposit'] = null;
            $resource['admin_fee'] = null;
            $resource['monthly_price'] = null;
            $resource['finance'] = null;
            $resource['financeExamples'] = null;
        }

        return $resource;
    }

    private function getExtraData()
    {
        $extra = collect(event(new LoadVehicleDataFields($this->resource, 'ui')))
            ->filter()
            ->mapWithKeys(fn ($field) => $field)
            ->merge($this->getCustomAttributes($this->resource));

        return $this->transformImageAttributesForDisplay($extra);
    }

    private function getContent(): Collection
    {
        $content = '';

        $content .= $this->resource->description;

        if (
            Feature::isEnabled('add_dealers_vehicle_description') &&
            !empty($this->resource->dealership->data['vehicle-description'])
        ) {
            $content .= $this->resource->dealership->data['vehicle-description'];
        }

        return collect([
            [
                'title' => __('labels.description'),
                'content' => $content,
                'buttonLink' => false
            ],
        ])->filter(fn ($entry) => !empty($entry['content']));
    }

    private function getFinanceData()
    {
        if ($this->resource->type === VehicleType::LCV->value && !Settings::get('vehicle-fpa-show-finance')) {
            return [];
        }
        return new FinanceFactory()->widget($this->resource);
    }

    public function getFinanceExamples()
    {
        $financeExamples = [];
        $showDepositVat = (bool) Settings::get('finance-show-deposit-vat');

        foreach ($this->resource['financeExamples'] as $financeExample) {
            $financeExamples[$financeExample->finance_type] = [
                'show_deposit_vat' => $showDepositVat,
                'provider' => $financeExample->provider,
                'finance_type' => $financeExample->finance_type,
                'monthly_price' => $financeExample->monthly_price,
                'term' => $financeExample->term,
                'number_of_payments' => $financeExample->number_of_payments,
                'total_deposit' => $financeExample->total_deposit,
                'apr' => $financeExample->apr,
                'first_payment' => $financeExample->first_payment,
                'final_payment' => $financeExample->final_payment,
                'interest_rate' => $financeExample->interest_rate,
                'apply_url' => $financeExample->apply_url,
                'annual_mileage' => $financeExample->annual_mileage,
                'cash_price' => $financeExample->cash_price,
                'dealer_deposit' => $financeExample->dealer_deposit,
                'customer_deposit' => $financeExample->customer_deposit,
                'deposit_tax_payable' => $financeExample->deposit_tax_payable,
                'payable_amount' => $financeExample->payable_amount,
                'option_to_purchase_fee' => $financeExample->option_to_purchase_fee,
                'documentation_fee' => $financeExample->documentation_fee,
                'terms_and_conditions' => $financeExample->terms_and_conditions,
                'total_credit_amount' => $financeExample->total_credit_amount,
                'excess_mileage_charge' => $financeExample->excess_mileage_charge,
            ];
        }

        return $financeExamples;
    }

    protected function largeImageDimensions(): string
    {
        return 'large';
    }

    protected function mediumImageDimensions(): string
    {
        return 'medium';
    }

    protected function thumbnailImageDimensions(): string
    {
        return 'thumbs';
    }

    /**
     * Get the UK age identifier from the registration date.
     * Age identifier should be a 2 digit number.
     *
     * The year runs from March to March for registrations.
     *
     * If reg date between start of March and end of August,
     * age identifier is reg year in 2 digit format.
     *
     * If reg date between start of September and end of December,
     * age identifier is (reg year + 50) in 2 digit format.
     *
     * If reg date between start of January and end of March,
     * age identifier is (previous reg year + 50) in 2 digit format,
     * as the registration belongs to the previous year.
     *
     * @return int|string
     */
    private function getAgeIdentifier()
    {
        if (
            empty($this->resource->first_registration_date)
            || $this->resource->first_registration_date->format('Y') < 2001
        ) {
            return '';
        }

        $reg_year = $this->resource->first_registration_date->format('y');
        $reg_month = $this->resource->first_registration_date->format('m');

        if ($reg_month < 3) {
            // the identifier should relate to the previous year,
            // as the year for registrations runs March to March
            return ($reg_year - 1) + 50;
        }

        if ($reg_month >= 3 && $reg_month < 9) {
            return $reg_year;
        }

        if ($reg_month >= 9) {
            return $reg_year + 50;
        }

        return '';
    }

    private function getDepositFlatRate()
    {
        $below_treshold = Settings::get('finance-deposit-flat-rate-treshold') > 0
            && $this->resource->price < Settings::get('finance-deposit-flat-rate-treshold');

        return $below_treshold
            ? Settings::get('finance-deposit-flat-rate-amount')
            : null;
    }

    private function getUlezCompliance(): ?string
    {
        if (strtolower((string)$this->resource['fuel_type']) == 'electric') {
            return 'Electric';
        }
        $emission_class_data_array = $this->resource->specs
            ->filter(fn ($item) => in_array($item['description'], self::EMISSION_STANDARD_NAMES)
                && in_array(strtolower((string)$item['value']), self::EMISSION_STANDARD_CLASSES_CARS))->first();

        return $emission_class_data_array['value'] ?? null;
    }
}
