<?php

namespace App\Http\Resources;

use App\Crm\EnquiryDataToProviderData;
use App\Crm\StormMSDynamics;
use App\Facades\Settings;
use App\Facades\Site;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
use Mtc\Crm\Models\FormQuestion;
use Mtc\MercuryDataModels\Booking;
use Mtc\MercuryDataModels\Dealership;
use Mtc\MercuryDataModels\Enquiry;
use Mtc\MercuryDataModels\NewCar;
use Mtc\MercuryDataModels\Vehicle;
use Mtc\MercuryDataModels\VehicleOffer;
use Mtc\MercuryDataModels\VehicleValuation;
use Mtc\VehicleReservations\Reservation;

class StormEnquiryResource extends JsonResource
{
    use EnquiryDataToProviderData;

    /**
     * Transform the resource into an array.
     *
     * @return array<string, mixed>
     */
    #[\Override]
    public function toArray(Request $request): array
    {
        $queryParams = $request->except(['page', 'tenant']);

        return [
            '_meta' => [
                'totalCount' => $this->resource->total(),
                'perPage' => $this->resource->perPage(),
                'pageCount' => $this->resource->lastPage(),
                'currentPage' => $request->input('page', 1),
            ],
            '_links' => [
                'self' => route(
                    'storm-enquiries',
                    array_merge([
                        'tenant' => tenant('id'),
                        'page' => $this->resource->currentPage()
                    ], $queryParams)
                ),
                'next' => $this->resource->appends($queryParams)->nextPageUrl(),
                'first' => route('storm-enquiries', array_merge(['tenant' => tenant('id'), 'page' => 1], $queryParams)),
                'last' => route(
                    'storm-enquiries',
                    array_merge(
                        [
                        'tenant' => tenant('id'),
                        'page' => $this->resource->lastPage()
                        ],
                        $queryParams
                    )
                ),
            ],
            'items' => collect($this->resource->items())->map(fn($item) => $this->mapItem($item))->toArray()
        ];
    }

    protected function mapItem($item): array
    {
        return match ($item::class) {
            Enquiry::class => $this->mapEnquiry($item),
            Booking::class => $this->mapBooking($item),
            Reservation::class => $this->mapReservation($item),
            default => throw new \RuntimeException("Unsupported item type: " . $item::class),
        };
    }

    protected function mapEnquiry(Enquiry $enquiry): array
    {
        $params = $this->convertEnquiryToParams($enquiry, 'ms-dynamics-field');
        if (!empty($params['contact_methods']) && is_string($params['contact_methods'])) {
            $contact_methods = explode(',', strtolower($params['contact_methods']));
        } else {
            $contact_methods = is_array($params['contact_methods'] ?? null) ? $params['contact_methods'] : [];
        }
        $location = $this->getLocation($enquiry);
        $vehicle_object = $enquiry->objects->firstWhere('object_type', 'vehicle');
        /** @var ?VehicleOffer $offer */
        $offer = $enquiry->objects->firstWhere('object_type', 'offer')?->object;
        /** @var ?NewCar $new_car */
        $new_car = $enquiry->objects->firstWhere('object_type', 'new-car')?->object;
        /** @var Vehicle $vehicle */
        $vehicle = $vehicle_object ? $vehicle_object->object()->withTrashed()->first() : null;

        $offer_url = $vehicle_url = $vehicle_data = null;
        if ($vehicle) {
            $vehicle_data = $this->mapVehicle($vehicle);
            $vehicle_url = Site::vehicleUrl($vehicle);
        } elseif ($offer) {
            $vehicle_data = $this->mapOffer($offer);
            $offer_url = Site::offerUrl($offer);
        } elseif ($new_car) {
            $vehicle_data = $this->mapNewCar($new_car);
            $offer_url = Site::newCarUrl($new_car);
        }
        if (!empty($params['full_name'])) {
            $names = explode(' ', (string) $params['full_name']);
            $params['last_name'] = array_pop($names);
            $params['first_name'] = implode(' ', $names);
        }

        return [
            '_links' => [
                'self' => route(
                    'storm-enquiry',
                    [
                        'tenant' => tenant('id'),
                        'type' => $enquiry->getMorphClass(),
                        'id' => $enquiry->id,
                    ]
                ),
            ],
            'context' => [
                'language' => 'en',
                'offer_url' => $offer_url,
                'product_url' => $vehicle_url,
                // Site vehicle
                'vehicle' => $vehicle_data,
            ],
            'date_submitted' => $enquiry->created_at->format('Y-m-d H:i:s'),
            'dealer' => [
                'franchise' => [
                    'hash' => null,
                ],
                'group' => [
                    'hash' => null,
                ],
                'location' => [
                    'hash' => $location?->data['ms-dynamics-dealership'] ?? null,
                ],
            ],
            'customValues' => $this->getCustomValuesArray($params),
            'form' => [
                'customer' => [
                    'address' => [
                        'building_ext' => $params['building_ext'] ?? null,
                        'building_int' => $params['building_int'] ?? null,
                        'country_code' => $params['country_code'] ?? null,
                        'district' => $params['district'] ?? null,
                        'postcode' => $params['postcode'] ?? null,
                        'primary_locality' => $params['primary_locality'] ?? null,
                        'secondary_locality' => $params['secondary_locality'] ?? null,
                        'street' => $params['street'] ?? null,
                    ],
                    'email' => $params['email'] ?? null,
                    'first_name' => $params['first_name'] ?? null,
                    'last_name' => $params['last_name'] ?? null,
                    'marketing_preferences' => [
                        'first_party' => [
                            'email' => in_array('email', $contact_methods),
                            'phone' => in_array('phone', $contact_methods),
                            'post' => in_array('post', $contact_methods),
                            'sms' => in_array('sms', $contact_methods),
                        ]
                    ],
                    'phone' => [
                        'number' => $params['phone'] ?? null,
                        'type' => null,
                    ],
                    'postcode' => $params['postcode'] ?? null,
                    'title' => $params['title'] ?? null,
                    // Part-ex or service vehicle
                    'vehicle' => $this->mapCustomerVehicle($enquiry, $params),

                ],
                'enquiry' => [
                    'configuration' => null,
                    'enquiry_url' => $params['source_url'] ?? null,
                    'group_software_hash' => 'abc123',
                    'message' => $params['message'] ?? null,
                    'source_url' => $enquiry->source,
                    'offer_price' => null,
                    'order_type' => null,
                    'preferred_date' => $params['preferred_date']
                        ?? $params['customer_vehicle_service_due_date']
                        ?? '',
                    'preferred_date_approximate' => $params['preferred_date_approximate'] ?? '',
                    'referring_url' => '',
                    'gclid' => $enquiry->data['meta']['gclid'] ?? null,
                ],
            ],
            'guid' => $enquiry->id,
            'type' => [
                'id' => $enquiry->form_id,
                'name' => $enquiry->form?->name,
            ]
        ];
    }

    protected function mapBooking(Booking $booking): array
    {
        $location = $booking->location;
        $vehicleData = $booking->vehicle_data ?? [];

        return [
            '_links' => [
                'self' => route(
                    'storm-enquiry',
                    [
                        'tenant' => tenant('id'),
                        'type' => $booking->getMorphClass(),
                        'id' => $booking->id,
                    ]
                ),
            ],

            'context' => [
                'language' => 'en',
                'offer_url' => null,
                'product_url' => null,
                'vehicle' => [
                    'condition' => $vehicleData['condition'] ?? 'Used',
                    'manufacturer' => $vehicleData['make'] ?? null,
                    'model' => $vehicleData['model'] ?? null,
                    'fuel_type' => $vehicleData['fuel_type'] ?? null,
                    'engine_size_litres' => isset($vehicleData['engine_size_cc'])
                        ? round((float)$vehicleData['engine_size_cc'] / 1000, 2)
                        : null,
                    'odometer' => $this->getOdometerData($booking->mileage, $booking->mileage),
                    'vrm' => $booking->registration_number,
                    'variant' => $vehicleData['variant'] ?? null,
                    'derivative' => $vehicleData['derivative'] ?? null,
                    'transmission_type' => $vehicleData['transmission'] ?? null,
                    'price' => null,
                ],
            ],

            'date_submitted' => $booking->created_at?->format('Y-m-d H:i:s'),

            'dealer' => [
                'franchise' => ['hash' => null],
                'group' => ['hash' => null],
                'location' => [
                    'hash' => $location?->data['ms-dynamics-dealership'] ?? null,
                ],
            ],

            'form' => [
                'customer' => [
                    'first_name' => $booking->first_name,
                    'last_name' => $booking->last_name,
                    'email' => $booking->email,
                    'phone' => [
                        'number' => $booking->phone_number,
                        'type' => null,
                    ],
                    'vehicle' => null,
                ],

                'enquiry' => [
                    'preferred_date' => $booking->booking_time?->format('Y-m-d'),
                    'preferred_date_approximate' => '',
                    'message' => $booking->data['message'] ?? null,
                    'enquiry_url' => null,
                    'source_url' => null,
                    'offer_price' => null,
                    'order_type' => null,
                    'referring_url' => null,
                    'group_software_hash' => 'abc123',
                ]
            ],

            'guid' => $booking->id,
            'type' => [
                'id' => null,
                'name' => 'Service Booking'
            ]
        ];
    }

    protected function mapReservation(Reservation $reservation): array
    {
        $vehicle = $reservation->vehicle()->withTrashed()->first();
        if ($vehicle) {
            $vehicle_url = Site::vehicleUrl($vehicle);
        } else {
            $vehicle_url = null;
        }

        $first_name = $reservation->first_name;
        $last_name = $reservation->last_name;

        if (empty($first_name) && empty($last_name) && !empty($reservation->name)) {
            $name_parts = explode(' ', (string) $reservation->name);
            $first_name = array_shift($name_parts);
            $last_name = implode(' ', $name_parts);
        }

        return [
            '_links' => [
                'self' => route(
                    'storm-enquiry',
                    [
                        'tenant' => tenant('id'),
                        'type' => $reservation->getMorphClass(),
                        'id' => $reservation->id,
                    ]
                ),
            ],

            'context' => [
                'language' => 'en',
                'offer_url' => null,
                'product_url' => $vehicle_url,
                'vehicle' => $this->mapVehicle($vehicle),
            ],

            'date_submitted' => $reservation->created_at?->format('Y-m-d H:i:s'),

            'dealer' => [
                'franchise' => [
                    'hash' => null
                ],
                'group' => [
                    'hash' => null
                ],
                'location' => [
                    'hash' => $vehicle?->dealership?->data['ms-dynamics-dealership'] ?? null,
                ],
            ],

            'form' => [
                'customer' => [
                    'first_name' => $first_name,
                    'last_name' => $last_name,
                    'email' => $reservation->email,
                    'phone' => [
                        'number' => $reservation->contact_number,
                        'type' => null,
                    ],
                    'vehicle' => null,
                ],

                'enquiry' => [
                    'message' => null,
                    'enquiry_url' => null,
                    'source_url' => null,
                    'offer_price' => $reservation->amount,
                    'order_type' => null,
                    'preferred_date' => '',
                    'preferred_date_approximate' => '',
                    'referring_url' => '',
                    'group_software_hash' => 'abc123',
                ],
            ],

            'guid' => $reservation->id,

            'type' => [
                'id' => null,
                'name' => 'Vehicle Reservation',
            ],
        ];
    }

    protected function mapCustomerVehicle(Enquiry $enquiry, array $params = []): ?array
    {
        $valuation_object = $enquiry->objects->where('object_type', 'valuation')->first();
        if ($valuation_object) {
            return $this->mapValuationVehicle($valuation_object->object);
        }

        $valuation_object = $enquiry->objects->where('object_type', 'service-booking')->first();
        if ($valuation_object) {
//            return $this->mapServiceBookingVehicle($valuation_object->object);
        }

        return $this->mapCustomerVehicleFromParams($params);
    }

    /**
     * Build form.customer.vehicle from form answers.
     *
     * Emits only the keys we have values for; absent fields are omitted rather
     * than set to null. Intentionally a narrower shape than mapValuationVehicle.
     */
    protected function mapCustomerVehicleFromParams(array $params): ?array
    {
        $vehicle = [];

        $map = [
            'customer_vehicle_registration'      => 'vrm',
            'customer_vehicle_make'              => 'manufacturer',
            'customer_vehicle_model'             => 'model',
            'customer_vehicle_service_due_date'  => 'next_service_date',
            'customer_vehicle_mot_due_date'      => 'next_mot_date',
        ];

        foreach ($map as $paramKey => $vehicleKey) {
            $value = $params[$paramKey] ?? null;
            if ($value !== null && $value !== '') {
                $vehicle[$vehicleKey] = $value;
            }
        }

        $mileage = $params['customer_vehicle_mileage'] ?? null;
        if ($mileage !== null && $mileage !== '') {
            $mileage = (int) $mileage;
            $vehicle['odometer'] = $this->getOdometerData($mileage, $mileage);
        }

        return $vehicle === [] ? null : $vehicle;
    }

    protected function mapValuationVehicle(VehicleValuation $valuation): ?array
    {
        return [
            'condition' => 'Used',
            'dealer' => null,
            'derivative' => null,
            'engine_size_litres' => null,
            'fuel_type' => $valuation->fuel_type,
            'manufacturer' => $valuation->make,
            'model' => $valuation->model,
            'next_mot_date' => null,
            'next_service_date' => null,
            'odometer' => $this->getOdometerData($valuation->mileage, $valuation->mileage),
            'transmission_type' => $valuation->transmissionType,
            'variant' => null,
            'vrm' => $valuation->registration,
        ];
    }

    protected function mapVehicle(?Vehicle $vehicle): ?array
    {
        if (!$vehicle) {
            return null;
        }

        return [
            'condition' => $vehicle?->is_new ? 'New' : 'Used',
            'dealer' => null,
            'derivative' => $vehicle?->derivative,
            'engine_size_litres' => $vehicle?->engine_size_cc
                ? round($vehicle?->engine_size_cc / 1000, 2)
                : null,
            'fuel_type' => $vehicle?->fuelType?->name,
            'manufacturer' => $vehicle?->make?->name,
            'model' => $vehicle?->model?->name,
            'next_mot_date' => null,
            'next_service_date' => null,
            'odometer' => $this->getOdometerData($vehicle?->odometer_km, $vehicle?->odometer_mi),
            'price' => $vehicle?->price,
            'transmission_type' => $vehicle?->transmissionType?->name,
            'variant' => null,
            'vrm' => $vehicle?->vrm_condensed,
        ];
    }

    protected function mapOffer(VehicleOffer $offer): ?array
    {
        return [
            'condition' => 'New',
            'dealer' => null,
            'derivative' => $offer->name,
            'engine_size_litres' => null,
            'fuel_type' => $offer->fuelType?->name,
            'manufacturer' => $offer->make?->name,
            'model' => $offer->model?->name,
            'next_mot_date' => null,
            'next_service_date' => null,
            'odometer' => $this->getOdometerData(0, 0),
            'price' => $offer->price,
            'transmission_type' => $offer->transmissionType?->name,
            'variant' => null,
            'vrm' => null,
        ];
    }
    protected function mapNewCar(NewCar $car): ?array
    {
        return [
            'condition' => 'New',
            'dealer' => null,
            'derivative' => $car->name,
            'engine_size_litres' => null,
            'fuel_type' => $car->fuelTypes()->pluck('name')->implode(','),
            'manufacturer' => $car->make?->name,
            'model' => $car->model?->name,
            'next_mot_date' => null,
            'next_service_date' => null,
            'odometer' => $this->getOdometerData(0, 0),
            'price' => $car->price,
            'transmission_type' => $car->transmissionType?->name,
            'variant' => null,
            'vrm' => null,
        ];
    }

    protected function getLocation(Enquiry $enquiry): ?Dealership
    {
        $related_object = $enquiry->objects->where('object_type', 'dealership')->first();
        if ($related_object) {
            return $related_object->object;
        }

        $related_vehicle = $enquiry->objects->where('object_type', 'vehicle')->first();
        if ($related_vehicle) {
            return $related_vehicle->object?->dealership;
        }

        $answers = collect($enquiry->details ?? [])->map(fn($answer) => $answer['answer'] ?? null);
        $answer_id = FormQuestion::query()
            ->whereIn('id', $answers->keys())
            ->get()
            ->keyBy('id')
            ->filter(fn($question) => ($question->data['meta']['options']['source'] ?? null) === 'dealerships')
            ->map(fn($question) => $question->id)
            ->first();

        return $answer_id ?
            Dealership::query()->find($answers[$answer_id])
            : null;
    }

    private function getOdometerData(?int $km, ?int $mi): array
    {
        $unit = Settings::get('automotive-distance_measurement', 'mi');

        $value = match ($unit) {
            'km' => $km ?? ($mi !== null ? (int)round($mi * 1.60934) : null),
            'mi' => $mi ?? ($km !== null ? (int)round($km / 1.60934) : null),
            default => $mi,
        };

        return [
            'current' => $value ?? null,
            'unit' => $unit
        ];
    }

    private function getCustomValuesArray(array $params): array
    {
        $custom_fields = StormMSDynamics::customFields();
        return collect($params)
            ->filter(fn($value, $key) => in_array($key, array_keys($custom_fields)))
            ->map(fn($value, $key) => [
                'key' => $custom_fields[$key],
                'value' => $value,
            ])
            ->values()
            ->toArray();
    }
}
