<?php

namespace App\Services;

use App\Contracts\AddsDealershipFields;
use App\Crm\EnquiryDataToProviderData;
use App\Facades\Settings;
use App\Traits\CacheObject;
use App\Traits\FormatAsCurrency;
use Illuminate\Http\Client\Response;
use Illuminate\Support\Facades\Http;
use Mtc\Crm\Contracts\EnquiryActionModel;
use Mtc\Crm\Contracts\EnquiryModel;
use Mtc\MercuryDataModels\ApiNotification;
use Mtc\MercuryDataModels\Booking;
use Mtc\MercuryDataModels\NewCar;
use Mtc\MercuryDataModels\Vehicle;
use Mtc\MercuryDataModels\Tools\UiUrlGenerator;
use Mtc\MercuryDataModels\VehicleOffer;
use Mtc\VehicleReservations\Reservation;
use Mtc\VehicleValuation\Models\VehicleValuation;

class PinewoodCrmApi implements AddsDealershipFields
{
    use CacheObject;
    use FormatAsCurrency;
    use EnquiryDataToProviderData;

    private Response $response;

    public function getResponseAttribute(string $attribute): mixed
    {
        return $this->response->json($attribute);
    }


    public function sendLead(EnquiryModel $enquiry, EnquiryActionModel $action): bool
    {
        $locationId = null;
        $vehicle = $enquiry->objects->where('object_type', 'vehicle')->first()?->object;
        $dealership = $enquiry->objects->where('object_type', 'dealership')->first()?->object;

        if ($dealership) {
            $locationId = $dealership->data['pinewood-crm-location-id'] ?? null;
        }

        if ($vehicle && empty($locationId)) {
            $locationId = $vehicle->dealership?->data['pinewood-crm-location-id'] ?? null;
        }

        if (empty($locationId)) {
            $locationId = Settings::get('pinewood-fallback-location-id');
        }

        return $this->submitLead($this->mapEnquiry($enquiry), $locationId, $enquiry->getMorphClass(), $enquiry->id);
    }

    public function sendReservation(Reservation $reservation): bool
    {
        $locationId = $reservation->vehicle->dealership?->data['pinewood-crm-location-id']
            ?? Settings::get('pinewood-crm-fallback-location-id');

        $success = $this->submitLead(
            $this->mapReservation($reservation),
            $locationId,
            $reservation->getMorphClass(),
            $reservation->id
        );

        if ($success) {
            $reservation->update(['crm_reference' => $this->getResponseAttribute('Lead_UID')]);
            return true;
        }
        return false;
    }

    public function sendServiceBooking(Booking $booking): bool
    {
        $locationId = $booking->location?->data['pinewood-crm-location-id']
            ?? Settings::get('pinewood-crm-fallback-location-id');

        $success = $this->submitLead(
            $this->mapServiceBooking($booking),
            $locationId,
            $booking->getMorphClass(),
            $booking->id
        );

        if ($success) {
            $booking->update(['crm_reference' => $this->getResponseAttribute('Lead_UID')]);
            return true;
        }
        return false;
    }

    protected function mapEnquiry(EnquiryModel $enquiry): array
    {
        $params = $this->convertEnquiryToParams($enquiry, 'pinewood-field');

        foreach ($enquiry->objects as $object) {
            if (empty($object->object)) {
                continue;
            }
            $vehicle_data = match ($object->object_type) {
                'vehicle' => $this->mapVehicle($object->object),
                'offer' => $this->mapOffer($object->object),
                'new-car' => $this->mapNewCar($object->object),
                'valuation' => $this->mapValuation($object->object),
                default => [],
            };
            $params = array_merge($params, $vehicle_data);
        }

        if (empty($params['preferredContactMethods'])) {
            $methods = [];
        } elseif (is_string($params['preferredContactMethods'])) {
            $methods = explode(',', strtolower($params['preferredContactMethods']));
        } elseif (is_array($params['preferredContactMethods'])) {
            $methods = array_map(strtolower(...), $params['preferredContactMethods']);
        }
        $address = array_filter([
            "Address1" => $params['address1'] ?? null,
            "Address2" => $params['address2'] ?? null,
            "Address3" => $params['address3'] ?? null,
            "Country" => array_filter([
                "Description" => $params['country'] ?? null,
            ]),
            "County" => $params['county'] ?? null,
            "PostCode" => $params['postcode'] ?? null,
            "PostTown" => $params['city'] ?? null,
        ]);

        $vehicle_data = array_filter([
            "Make" => $params['vehicle_make'] ?? null,
            "Model" => $params['vehicle_model'] ?? null,
            "PriceRangeHigh" => $params['vehicle_price'] ?? null,
            "PriceRangeLow" => $params['vehicle_price'] ?? null,
            "RegistrationNumber" => $params['vehicle_vrm'] ?? null,
            "Specification" => $params['vehicle_derivative'] ?? null,
        ], fn ($item) => $item !== null);

        $data = array_filter([
            "ContactHistory" => array_filter([
                "ContactDate" => $enquiry->created_at->format('Y-m-d\TH:i:s\Z'),
                "Notes" => $params['notes'] ?? null,
                "VehicleType" => $params['vehicle_type'] ?? null,
            ]),
            "Customer" => array_filter([
                "Address" => !empty($address) ? $address : null,
                "AllowEmail" => in_array('email', $methods ?? []),
                "AllowForwarding" => in_array('forwarding', $methods ?? []),
                "AllowMail" => in_array('mail', $methods ?? []),
                "AllowSalesContact" => in_array('sales_contact', $methods ?? []),
                "AllowSMS" => in_array('sms', $methods ?? []),
                "CompanyName" => $params['company_name'] ?? null,
                "EmailAddress1" => $params['email'] ?? null,
                "Forename" => $params['first_name'] ?? null,
                "Surname" => $params['last_name'] ?? null,
                "ContactNumber_Mobile" => array_filter([
                    "Number" => $params['phone'] ?? null
                ]),
                "Title" => !empty($params['title'])
                    ? [
                        "Title" => $params['title'],
                    ]
                    : null,
            ], fn ($item) => $item !== null),
            "DesiredVehicle" => $vehicle_data ?: null,
            "EnquirySource" => [
                "EnquirySource" => "Website",
            ],
            "EnquiryType" => [
                "EnquiryType" => $enquiry->type?->name ?? 'Sales',
            ],
            "LeadReferenceID" => 'ENQ-' . $enquiry->id,
        ], fn ($item) => $item !== null);

        if ($enquiry->objects->where('object_type', 'valuation')->isNotEmpty()) {
            $data["ContactHistory"]["Notes"] = ($data["ContactHistory"]["Notes"] ?? '') . __('crm.part-ex-value', [
                'value' => $params['part_ex_value']
            ]);
            $data['PresentVehicle'] = array_filter([
                "Make" => $params['part_ex_make'] ?? null,
                "Model" => $params['part_ex_model'] ?? null,
                "RegistrationNumber" => $params['part_ex_vrm'] ?? '',
                "Specification" => $params['part_ex_derivative'] ?? null,
                "Odometer" => $params['part_ex_mileage'] ?? null,
                "EngineSize" => $params['part_ex_engine_size'] ?? null,
                "Colour" => $params['part_ex_colour'] ?? null,
                "RegistrationDate" => $params['part_ex_date_of_registration'] ?? null,
                "FuelType" => [
                    "FuelType" => $params['part_ex_fuel_type'] ?? null
                ],
                "TransmissionType" => [
                    "TransmissionType" => $params['part_ex_transmission'] ?? null
                ],
            ], fn ($item) => $item !== null);
        }

        $vehicleInfo = $this->buildEnquiryVehicleInfo($enquiry);
        $data["ContactHistory"]["Notes"] = ($data["ContactHistory"]["Notes"] ?? '')
            . __('crm.enquiry_resource_details', [
                'vehicle_info' => $vehicleInfo,
                'link' => UiUrlGenerator::make('crm/enquiries/view/' . $enquiry->id),
            ]);

        return $data;
    }

    protected function mapReservation(Reservation $reservation): array
    {
        $name_parts = explode(' ', $reservation->name);
        return array_filter([
            "ContactHistory" => [
                "ContactDate" => $reservation->created_at->format('Y-m-d\TH:i:s\Z'),
                "Notes" => __('crm.fuse.reservation_details', [
                    'amount' => $reservation->amount,
                    'confirmed_at' => $reservation->confirmed_at?->format('Y-m-d H:i:s'),
                    'payment_reference' => $reservation->invoice?->payments()
                        ->pluck('reference')->implode(','),
                    'vehicle_title' => $reservation->vehicle?->title,
                    'vehicle_reg' => $reservation->vehicle?->registration_number,
                    'vehicle_price' => $reservation->vehicle?->price,
                    'link' => UiUrlGenerator::make(
                        'reservations/view/' . $reservation->id
                    ),
                ]),
                "VehicleType" => $reservation->vehicle?->is_new ? 'New' : 'Used',
            ],
            "Customer" => array_filter([
                "AllowEmail" => true,
                "AllowSalesContact" => true,
                "AllowSMS" => true,
                "EmailAddress1" => $reservation->email,
                "Forename" => array_shift($name_parts),
                "Surname" => implode(' ', $name_parts),
                "ContactNumber_Mobile" => array_filter([
                    "Number" => $reservation->contact_number
                ]),
            ], fn ($item) => $item !== null),
            "DesiredVehicle" => array_filter([
                "Make" => $reservation->vehicle->make?->name,
                "Model" => $reservation->vehicle->model?->name,
                "PriceRangeHigh" => $reservation->vehicle->price,
                "PriceRangeLow" => $reservation->vehicle->price,
                "RegistrationNumber" => $reservation->vehicle->vrm_condensed,
                "Specification" => $reservation->vehicle->derivative,
            ]),
            "EnquirySource" => [
                "EnquirySource" => "Website",
            ],
            "EnquiryType" => [
                "EnquiryType" => 'Vehicle reservation',
            ],
            "LeadReferenceID" => 'RES-' . $reservation->id,
        ]);
    }
    protected function mapServiceBooking(Booking $booking): array
    {
        return array_filter([
            "ContactHistory" => [
                "ContactDate" => $booking->created_at?->format('Y-m-d\TH:i:s\Z'),
                "Notes" => __('crm.service_booking_details', [
                    'time' => $booking->booking_time,
                    'packages' => $booking->packages()->pluck('name')->implode(', '),
                    'registration' => $booking->registration_number,
                    'delivery' => $booking->deliveryOption?->name ?? '',
                    'details' => collect($booking->data ?? [])
                        ->map(fn ($value, $key) => "$key: $value")
                        ->implode(', '),
                    'notes' => $booking->notes,
                    'link' => UiUrlGenerator::make(
                        'service-booking/bookings/view/' . $booking->id
                    ),
                ]),
                "VehicleType" => 'Used',
            ],
            "Customer" => array_filter([
                "AllowEmail" => true,
                "AllowSalesContact" => true,
                "AllowSMS" => true,
                "EmailAddress1" => $booking->email,
                "Forename" => $booking->first_name,
                "Surname" => $booking->last_name,
                "ContactNumber_Mobile" => array_filter([
                    "Number" => $booking->phone_number
                ]),
            ], fn ($item) => $item !== null),
            'PresentVehicle' => array_filter([
                "Make" => $booking->vehicle_data['make'] ?? null,
                "Model" => $booking->vehicle_data['model'] ?? null,
                "RegistrationNumber" => $booking->registration_number ?? null,
                "Specification" => $booking->vehicle_data['derivative'] ?? null,
                "Odometer" => $booking->mileage ?? null,
                "EngineSize" => $booking->vehicle_data['engine_capacity_cc'] ?? null,
                "Colour" => $booking->vehicle_data['colour'] ?? null,
                "RegistrationDate" => $booking->vehicle_data['registration_date'] ?? null,
                "FuelType" => [
                    "FuelType" => $booking->vehicle_data['fuel_type'] ?? null
                ],
                "TransmissionType" => [
                    "TransmissionType" => $booking->vehicle_data['transmission'] ?? null
                ],
            ], fn ($item) => $item !== null) ?: null,
            "EnquirySource" => [
                "EnquirySource" => "Website",
            ],
            "EnquiryType" => [
                "EnquiryType" => 'Service booking',
            ],
            "LeadReferenceID" => 'SRV-' . $booking->id,
        ]);
    }

    protected function mapVehicle(Vehicle $vehicle): array
    {
        return [
            'vehicle_type' => $vehicle->is_new ? 'New' : 'Used',
            'vehicle_make' => $vehicle->make?->name,
            'vehicle_model' => $vehicle->model?->name,
            'vehicle_vrm' => $vehicle->vrm_condensed,
            'vehicle_price' => $vehicle->price,
            'vehicle_derivative' => $vehicle->derivative,
        ];
    }

    protected function mapValuation(VehicleValuation $valuation): array
    {
        return [
            'part_ex_value' => $valuation->adjusted_average_price ?? $valuation->average_price
                ?? $valuation->adjusted_retail_price ?? $valuation->retail_price,
            'part_ex_make' => $valuation->make,
            'part_ex_model' => $valuation->model,
            'part_ex_vrm' => $valuation->registration,
            'part_ex_mileage' => $valuation->mileage,
            'part_ex_derivative' => $valuation->derivative,
            'part_ex_engine_size' => $valuation->engine_size,
            'part_ex_fuel_type' => $valuation->fuel_type,
            'part_ex_fuel_transmission' => $valuation->transmission,
            'part_ex_colour' => $valuation->colour,
            'part_ex_date_of_registration' => $valuation->date_of_registration,
        ];
    }

    protected function mapOffer(VehicleOffer $vehicle): array
    {
        return [
            'vehicle_type' => 'New',
            'vehicle_make' => $vehicle->make?->name,
            'vehicle_model' => $vehicle->model?->name,
            'vehicle_vrm' => '',
            'vehicle_price' => $vehicle->price,
            'vehicle_derivative' => 'Offer: ' . $vehicle->name,
        ];
    }

    protected function mapNewCar(NewCar $vehicle): array
    {
        return [
            'vehicle_type' => 'New',
            'vehicle_make' => $vehicle->make?->name,
            'vehicle_model' => $vehicle->model?->name,
            'vehicle_vrm' => '',
            'vehicle_price' => $vehicle->price,
            'vehicle_derivative' => 'New Vehicle: ' . $vehicle->name,
        ];
    }

    protected function buildEnquiryVehicleInfo(EnquiryModel $enquiry): string
    {
        $vehicle = $enquiry->objects->where('object_type', 'vehicle')->first()?->object;
        if ($vehicle) {
            return 'Vehicle: ' . $vehicle->title
                . ' | Reg: ' . $vehicle->registration_number;
        }

        $offer = $enquiry->objects->where('object_type', 'offer')->first()?->object;
        if ($offer) {
            return 'Offer: ' . $offer->name;
        }

        $newCar = $enquiry->objects->where('object_type', 'new-car')->first()?->object;
        if ($newCar) {
            return 'New Vehicle: ' . $newCar->name;
        }

        return '';
    }

    protected function submitLead(array $lead_data, string $locationId, string $data_model, int $reference): bool
    {
        $url = 'https://api.pinewooddms.com/APIv2/CRM/Lead';
        $this->response = Http::withHeaders([
            'Accept' => 'application/json',
            'UserName' => Settings::get('pinewood-crm-username'),
            'Password' => Settings::get('pinewood-crm-password'),
            'OrganisationalUnit_UID' => $locationId,
            'Accept-Encoding' => 'gzip,deflate',
        ])
            ->withOptions(['verify' => false])
            ->post($url, $lead_data);

        ApiNotification::query()->create([
            'provider' => 'pinewood-crm',
            'processed' => $this->response->successful(),
            'headers' => ['OrganisationalUnit_UID' => $locationId],
            'data' => [
                'request' => $lead_data,
                'result' => $this->response->json(),
                'location' => $locationId,
                'status' => $this->response->status(),
            ],
            'data_model' => $data_model,
            'reference' => $reference,
        ]);

        return $this->response->successful();
    }

    public function dealershipAdditionalDataFields(): array
    {
        return [
            'pinewood-crm-location-id' => [
                'type' => 'text',
                'label' => 'Location ID within Pinewood CRM',
            ],
        ];
    }

    public function enabled(): bool
    {
        return Settings::get('pinewood-crm-enabled', false);
    }
}
