<?php

namespace App\Services;

use App\Crm\Config\FuseCrmConfig;
use App\Crm\EnquiryDataToProviderData;
use App\Facades\Site;
use App\Traits\CacheObject;
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\NewCar;
use Mtc\MercuryDataModels\Vehicle;
use Mtc\MercuryDataModels\VehicleOffer;
use Mtc\VehicleReservations\Reservation;

class FuseCrmApi
{
    use CacheObject;
    use EnquiryDataToProviderData;

    private Response $response;

    public function __construct(protected readonly FuseCrmConfig $config)
    {
        //
    }

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


    public function sendLead(EnquiryModel $enquiry, EnquiryActionModel $action): bool
    {
        return $this->submitLead($this->mapEnquiry($enquiry));
    }

    public function sendReservation(Reservation $reservation): bool
    {
        return $this->submitLead($this->mapReservation($reservation));
    }

    public function syncReservedStatus(Reservation $reservation): bool
    {
        $proposalId = $reservation->crm_reference;
        $registration = str_replace(' ', '', $reservation->vehicle->registration_number);
        $reservationId = $reservation->id;

        return $this->markAsVehicleOfInterest($proposalId, $registration, $reservationId)
            && $this->markAsReserved($proposalId, $registration, $reservationId);
    }

    private function markAsVehicleOfInterest(string $proposalId, string $registration, ?int $reservationId = null): bool
    {
        $voiResponse = Http::withHeaders([
            'X-Fuse-Apikey' => $this->config->syncReservationApiKey(),
        ])->post($this->syncEndpoint(), [
            'proposalId' => $proposalId,
            'registration' => $registration,
            'reserve' => false,
            'voi' => true,
        ]);

        ApiNotification::query()->create([
            'provider' => 'fuse-crm-voi',
            'processed' => $voiResponse->successful(),
            'reference' => $reservationId,
            'headers' => ['X-Fuse-Apikey' => $this->config->syncReservationApiKey()],
            'data' => [
                'reservation_id' => $reservationId,
                'proposal_id' => $proposalId,
                'http_status' => $voiResponse->status(),
                'request' => [
                    'proposalId' => $proposalId,
                    'registration' => $registration,
                    'reserve' => false,
                    'voi' => true,
                ],
                'result' => $voiResponse->body(),
                'endpoint' => $this->syncEndpoint(),
            ],
            'data_model' => FuseCrmApi::class,
        ]);

        return $voiResponse->successful();
    }

    private function markAsReserved(string $proposalId, string $registration, ?int $reservationId = null): bool
    {
        $reserveResponse = Http::withHeaders([
            'X-Fuse-Apikey' => $this->config->syncReservationApiKey(),
        ])->post($this->syncEndpoint(), [
            'proposalId' => $proposalId,
            'registration' => $registration,
            'reserve' => true,
            'voi' => false,
        ]);

        ApiNotification::query()->create([
            'provider' => 'fuse-crm-reserve',
            'processed' => $reserveResponse->successful(),
            'reference' => $reservationId,
            'headers' => ['X-Fuse-Apikey' => $this->config->syncReservationApiKey()],
            'data' => [
                'reservation_id' => $reservationId,
                'proposal_id' => $proposalId,
                'http_status' => $reserveResponse->status(),
                'request' => [
                    'proposalId' => $proposalId,
                    'registration' => $registration,
                    'reserve' => true,
                    'voi' => false,
                ],
                'result' => $reserveResponse->body(),
                'endpoint' => $this->syncEndpoint(),
            ],
            'data_model' => FuseCrmApi::class,
        ]);

        return $reserveResponse->successful();
    }

    private function syncEndpoint(): string
    {
        return rtrim($this->config->syncReservationApiDomain(), '/') . '/api/stock-list/vehicle/reserve-or-save-voi';
    }

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

        foreach ($enquiry->objects as $object) {
            // The morph target can be null when the related record has since been deleted.
            if (! $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),
                default => [],
            };
            $params = array_merge($params, $vehicle_data);
            if ($object->object_type === 'valuation') {
                $params['customer_comments'] = ($params['customer_comments'] ?? '')
                    . __('crm.fuse.valuation_of_vehicle', [
                        'vrm' => $object->object->registration,
                        'mileage' => $object->object->mileage,
                        'make' => $object->object->make,
                        'model' => $object->object->model,
                        'price' => $object->object->adjusted_average_price ?? $object->object->average_price
                                ?? $object->object->adjusted_retail_price ?? $object->object->retail_price,
                        'condition' => $object->object->cosmetic_condition ?? 'null',
                    ]);
            }
        }

        $params['website'] = Site::url();
        $params['source_url'] = Site::url($enquiry->data['meta']['source_url'] ?? '');
        $params['utm_campaign'] = $enquiry->data['meta']['utm_campaign'] ?? null;
        $params['utm_content'] = $enquiry->data['meta']['utm_content'] ?? null;
        $params['utm_medium'] = $enquiry->data['meta']['utm_medium'] ?? null;
        $params['utm_source'] = $enquiry->data['meta']['utm_source'] ?? null;
        $params['utm_term'] = $enquiry->data['meta']['utm_term'] ?? null;
        $params['agreeMarketing'] = ($params['agreeMarketing'] ?? null) ? true : false;
        if (isset($params['preferredContactMethods'])) {
            if (is_array($params['preferredContactMethods'])) {
                $methods = $params['preferredContactMethods'];
            } else {
                $methods = explode(',', strtolower((string) $params['preferredContactMethods']));
            }
            if (in_array('sms', $methods)) {
                $params['preferredContactSMS'] = true;
            }
            if (in_array('phone', $methods)) {
                $params['preferredContactPhone'] = true;
            }
            if (in_array('email', $methods)) {
                $params['preferredContactEmail'] = true;
            }
            unset($params['preferredContactMethods']);
        }
        return $params;
    }

    protected function mapReservation(Reservation $reservation): array
    {
        $name_parts = explode(' ', $reservation->name);
        return [
            'forename' => array_shift($name_parts),
            'surname' => implode(' ', $name_parts),
            'email' => $reservation->email,
            'phone' => $reservation->contact_number,
            'customer_comments' => __('crm.reservation_details', [
                'amount' => $reservation->amount,
                'confirmed_at' => $reservation->confirmed_at?->format('d/m/Y H:i'),
                'payment_reference' => $reservation->invoice?->payments()->pluck('reference')->implode(','),
            ]),
            'car_or_van' => $reservation->vehicle->type,
            'sale_type' => $reservation->vehicle->is_new ? 'New' : 'Used',
            'loan_amount' => $reservation->vehicle->price,
            'vehicle_interest' => $reservation->vehicle->make->name,
            'vehicle_model' => $reservation->vehicle->model->name,
            'vehicle_type' => $reservation->vehicle->vrm_condensed,
            'vehicle_cap_id' => $reservation->vehicle->cap_id,
            'website' => Site::url(),
            'source_url' => Site::vehicleUrl($reservation->vehicle),
            'utm_campaign' => $reservation->data['meta']['utm_campaign'] ?? null,
            'utm_content' => $reservation->data['meta']['utm_content'] ?? null,
            'utm_medium' => $reservation->data['meta']['utm_medium'] ?? null,
            'utm_source' => $reservation->data['meta']['utm_source'] ?? null,
            'utm_term' => $reservation->data['meta']['utm_term'] ?? null,
        ];
    }

    protected function mapVehicle(Vehicle $vehicle): array
    {
        return [
            'car_or_van' => $vehicle->type,
            'sale_type' => $vehicle->is_new ? 'New' : 'Used',
            'loan_amount' => $vehicle->price,
            'vehicle_interest' => $vehicle->make?->name,
            'vehicle_model' => $vehicle->model?->name,
            'vehicle_type' => $vehicle->vrm_condensed,
            'vehicle_cap_id' => $vehicle->cap_id,
            'reg_number_enquired_on' => $vehicle->registration_number,
        ];
    }

    protected function mapOffer(VehicleOffer $vehicle): array
    {
        return [
            'sale_type' => 'New',
            'vehicle_interest' => $vehicle->make?->name,
            'vehicle_model' => $vehicle->model?->name,
            'vehicle_type' => $vehicle->name,
            'vehicle_cap_id' => $vehicle->cap_id,
        ];
    }

    protected function mapNewCar(NewCar $vehicle): array
    {
        return [
            'sale_type' => 'New',
            'loan_amount' => $vehicle->price,
            'vehicle_interest' => $vehicle->make->name,
            'vehicle_model' => $vehicle->model->name,
            'vehicle_type' => $vehicle->name,
        ];
    }

    protected function submitLead(array $lead_data): bool
    {
        $this->response = Http::withHeaders([
            'Authorization' => 'Bearer ' . $this->accessToken()
        ])->post($this->endpoint('enquiry'), $lead_data);

        ApiNotification::query()->create([
            'provider' => 'fuse-crm',
            'processed' => $this->response->successful(),
            'headers' => ['Authorization' => 'Bearer' . $this->accessToken()],
            'data' => [
                'request' => $lead_data,
                'result' => $this->response->body(),
                'endpoint' => $this->endpoint('enquiry'),
            ],
            'data_model' => FuseCrmApi::class,
        ]);

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

    private function accessToken(): string
    {
        return $this->cache('fuse-access-token', 55, function () {
            $response = Http::asForm()->post($this->endpoint('token'), [
                'grant_type' => 'client_credentials',
                'client_id' => $this->config->clientId(),
                'client_secret' => $this->config->clientSecret(),
            ]);
            return $response->successful()
                ? $response->json('access_token')
                : throw new \Exception('Failed to authenticate Fuse CRM, status ' . $response->status() . ':'
                    . json_encode($response->json()));
        });
    }

    private function endpoint(string $path): string
    {
        return rtrim((string) $this->config->apiDomain(), '/') . '/api/' . ltrim($path, '/');
    }
}
