<?php

namespace App\Services;

use App\Models\EVData;
use App\Models\EVDataAttribute;
use App\VehicleType;
use Carbon\Carbon;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use Mtc\MercuryDataModels\Vehicle;

class EVDatabase
{
    public const PROVIDER = 'ev-database';

    public function __construct(
        private readonly TaxonomyMappingService $taxonomyMappingService
    ) {
        //
    }

    public function sync(): bool
    {
        try {
            $this->saveCollection($this->getData('m1/bev'), VehicleType::CAR->value);
            $this->saveCollection($this->getData('m1/phev'), VehicleType::CAR->value);
            $this->saveCollection($this->getData('n1/bev'), VehicleType::LCV->value);
        } catch (\Exception $exception) {
            Log::error('Failed to retrieve EV Database info: ' . $exception->getMessage());
            return false;
        }
        return true;
    }

    public function match(Vehicle $vehicle): ?array
    {
        $data = EVData::query()
            ->with('evDataAttributes')
            ->where('make_id', $vehicle->make_id)
            ->where('model_id', $vehicle->model_id)
            ->when(
                $vehicle->first_registration_date,
                fn($query) => $query->where('date_from', '<=', $vehicle->first_registration_date)
                    ->where(fn($endQuery) => $endQuery->whereNull('date_to')
                        ->orWhere('date_to', '>=', $vehicle->first_registration_date))
            )
            ->first();

        return $data?->evDataAttributes()
            ->pluck('attribute_value', 'attribute_key')
            ->toArray();
    }

    private function getData(string $type): Collection
    {
        $response = Http::get($this->endpoint($type));
        if ($response->successful()) {
            return collect($response->json());
        }
        Log::error('Failed to get EV Database data for ' . $type, [
            $response->body()
        ]);
        return collect();
    }

    private function saveCollection(Collection $data, string $type): void
    {
        $data->each(function ($entry) use ($type) {
            /** @var EVData $record */
            $record = EVData::query()->firstOrNew(['ev_db_id' => $entry['Vehicle_ID']]);
            $record->fill([
                'vehicle_type' => $type,
                'variant' => $entry['Vehicle_Model_Version'] ?? null,
                'date_from' => isset($entry['Availability_Date_From'])
                    ? Carbon::createFromFormat('m-Y', $entry['Availability_Date_From'])->startOfMonth()
                    : null,
                'date_to' => isset($entry['Availability_Date_To'])
                    ? Carbon::createFromFormat('m-Y', $entry['Availability_Date_To'])->endOfMonth()
                    : null,
            ]);

            if (empty($record->make_id) && !empty($entry['Vehicle_Make'])) {
                $record->make_id = $this->taxonomyMappingService->getMappedTaxonomy(
                    self::PROVIDER,
                    'make',
                    $entry['Vehicle_Make'],
                    $entry
                );
            }

            if (empty($record->model_id) && !empty($entry['Vehicle_Model'])) {
                $record->model_id = $this->taxonomyMappingService->getMappedTaxonomy(
                    self::PROVIDER,
                    'model',
                    $entry['Vehicle_Model'],
                    $entry,
                    $record->make_id
                );
            }

            $record->save();

            // Store all data keys as attributes
            foreach ($entry as $key => $value) {
                EVDataAttribute::query()->updateOrCreate(
                    [
                        'ev_data_id' => $record->id,
                        'attribute_key' => $key,
                    ],
                    [
                        'attribute_value' => is_array($value) ? json_encode($value) : (string) $value,
                    ]
                );
            }
        });
    }

    private function endpoint(string $type): string
    {
        $api_user = Config::get('services.ev_data.user_id');
        $api_key = Config::get('services.ev_data.key');
        return "https://ev-database.org/export_v31/$type/$api_user/$api_key";
    }
}
