<?php

namespace App\Modules\Leasing;

use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use App\Facades\Settings;
use Mtc\MercuryDataModels\BodyStyleType;
use Mtc\MercuryDataModels\FuelType;
use Mtc\MercuryDataModels\TransmissionType;
use Mtc\MercuryDataModels\VehicleMake;
use Mtc\MercuryDataModels\VehicleModel;

abstract class KeyloopFleetKompactImporterBase
{
    use DispatchesJobs;

    /**
     * An array of vehicle makes which are enabled for Keyloop leasing.
     * Keyed by the Keyloop make short code.
     * Elements contain the mtc make ID.
     * @var array|mixed[]
     */
    protected array $enabled_keyloop_makes;

    /**
     * An array of vehicle models which are enabled for Keyloop leasing.
     * Keyed by the Keyloop model short code.
     * Elements contain the mtc model ID.
     * @var array|mixed[]
     */
    protected array $enabled_keyloop_models;

    /**
     * array of vehicle body types, keyed by name.
     *
     * @var array|mixed[]
     */
    protected array $body_types;

    /**
     * array of vehicle fuel types, keyed by name.
     *
     * @var array|mixed[]
     */
    protected array $fuel_types;

    /**
     * array of vehicle transmission types, keyed by name.
     *
     * @var array|mixed[]
     */
    protected array $transmission_types;

    abstract protected function filter(Collection $data): bool;

    abstract protected function prepareForImport(): void;

    abstract protected function importItems(Collection $data): void;

    public function __construct(
        public readonly string $filename,
        public readonly int $sort_order = 999
    ) {
        $import_all = Settings::get('leasing-keyloop-fleet-kompact-import-all-makes-models') ?? false;

        $this->enabled_keyloop_makes = VehicleMake::query()
            ->when(!$import_all, fn ($query) => $query->where('keyloop_import_enabled', '=', true))
            ->whereNotNull('keyloop_id')
            ->get()
            ->mapWithKeys(fn ($make) => [$make['keyloop_id'] => $make['id']])
            ->toArray();

        $this->enabled_keyloop_models = [];

        collect($this->enabled_keyloop_makes)->each(function ($make_id, $make_code) use ($import_all) {
            $this->enabled_keyloop_models[$make_code] = VehicleModel::query()
                ->when(!$import_all, fn ($query) => $query->where('keyloop_import_enabled', '=', true))
                ->where('make_id', $make_id)
                ->get()
                ->mapWithKeys(fn ($model) => [$model['keyloop_id'] => $model['id']])
                ->toArray();
        });

        $this->addAdditionalAudiModels();

        $this->body_types = BodyStyleType::query()
            ->get()
            ->mapWithKeys(fn ($body_type) => [$body_type['name'] => $body_type['id']])
            ->toArray();

        $this->fuel_types = FuelType::query()
            ->get()
            ->mapWithKeys(fn ($fuel_type) => [$fuel_type['name'] => $fuel_type['id']])
            ->toArray();

        $this->transmission_types = TransmissionType::query()
            ->get()
            ->mapWithKeys(fn ($transmission_type) => [$transmission_type['name'] => $transmission_type['id']])
            ->toArray();
    }

    public function importFile(): void
    {
        $this->prepareForImport();

        $path = Storage::disk('local')->path($this->filename);
        $file = fopen($path, "r");
        $batch = [];
        $count = 0;

        $first_row = fgetcsv($file, 0, ",", escape: '\\');

        if (empty($first_row)) {
            return;
        }

        $headings = array_map(fn ($column) => Str::slug($column), $first_row);

        while (($data = fgetcsv($file, escape: '\\')) !== false) {
            $batch[] = collect($headings)
                ->flip()
                ->map(fn ($index) => $data[$index] ?? null);
            if (count($batch) == 100) {
                $this->importValidItems(collect($batch));
                $batch = [];
                dump(static::class . ' - Batch:' . $count++);
            }
        }

        // process the final partial batch
        $this->importValidItems(collect($batch));

        fclose($file);
    }

    /**
     * @param string $make_code
     * @return int|null
     */
    protected function getVehicleMake(string $make_code): ?int
    {
        return $this->enabled_keyloop_makes[$make_code] ?? null;
    }

    /**
     * @param string $model_code
     * @param string $make_code
     * @return int|null
     */
    protected function getVehicleModel(string $model_code, string $make_code): ?int
    {
        return $this->enabled_keyloop_models[$make_code][$model_code] ?? null;
    }

    protected function getUtf8String(?string $string): string
    {
        return empty($string)
            ? ''
            : mb_convert_encoding($string, 'UTF-8', 'ISO-8859-1');
    }

    private function importValidItems(Collection $collection)
    {
        // Trim the data.
        // Incoming data can include e.g. empty space character " " for variant ID.
        $items = $collection->map(fn ($row) => $row->map(fn ($item) => trim((string) $item)))
            ->filter(fn ($item) => $this->filter($item));

        if ($items->count() > 0) {
            $this->importItems($items);
        }
    }

    /**
     * Add additional 'SPORTBACK' and 'SPORTBACK E-' models for Audi.
     * Models will be added with existing parent vehicle model IDs,
     * so Q3 and Q3 SPORTBACK will both map to Autonomy's Q3 vehicle model.
     *
     * @return void
     */
    private function addAdditionalAudiModels(): void
    {
        if (array_key_exists('AUD', $this->enabled_keyloop_models)) {
            $models = [
                'Q3' => 'Q3 SPORTBACK',
                'Q4' => 'Q4 SPORTBACK E-',
                'Q5' => 'Q5 SPORTBACK',
                'Q6' => 'Q6 SPORTBACK E-',
                'Q8' => 'Q8 SPORTBACK E-',
            ];

            collect($models)
                ->filter(fn ($new_key, $keyloop_id)
                    => array_key_exists($keyloop_id, $this->enabled_keyloop_models['AUD']))
                ->each(fn ($new_key, $keyloop_id) =>
                    $this->enabled_keyloop_models['AUD'][$new_key] = $this->enabled_keyloop_models['AUD'][$keyloop_id]);
        }
    }
}
