<?php

namespace App\Imports;

use App\Master\Models\CapVehicle;
use App\Master\Models\VehicleMake;
use App\Master\Models\VehicleModel;
use Illuminate\Support\Collection;
use Maatwebsite\Excel\Concerns\ToCollection;
use Maatwebsite\Excel\Concerns\WithBatchInserts;
use Maatwebsite\Excel\Concerns\WithChunkReading;

class CapVehicleImport implements ToCollection, WithChunkReading, WithBatchInserts
{
    protected int $imported = 0;
    protected int $failed = 0;
    protected array $makeCache = [];
    protected array $modelCache = [];

    public function __construct(
        protected readonly string $type
    ) {
        $this->loadMakeCache();
        $this->loadModelCache();
    }

    protected function loadMakeCache(): void
    {
        $this->makeCache = VehicleMake::query()
            ->pluck('id', 'name')
            ->mapWithKeys(fn ($id, $name) => [strtolower($name) => $id])
            ->toArray();
    }

    protected function loadModelCache(): void
    {
        $this->modelCache = VehicleModel::query()
            ->select('id', 'make_id', 'name')
            ->get()
            ->groupBy('make_id')
            ->map(fn ($models) => $models->pluck('id', 'name')
                ->mapWithKeys(fn ($id, $name) => [strtolower($name) => $id]))
            ->toArray();
    }

    protected function findMakeId(string $manufacturer): ?int
    {
        $key = strtolower(trim($manufacturer));

        return $this->makeCache[$key] ?? null;
    }

    protected function findModelId(?int $makeId, string $modelName): ?int
    {
        if ($makeId === null) {
            return null;
        }

        $key = strtolower(trim($modelName));
        $makeModels = $this->modelCache[$makeId] ?? [];

        return $makeModels[$key] ?? null;
    }

    public function collection(Collection $rows): void
    {
        foreach ($rows as $row) {
            try {
                if ($this->isValidRow($row)) {
                    $this->createOrUpdateVehicle($row);
                    $this->imported++;
                }
            } catch (\Exception $e) {
                $this->failed++;
            }
        }
    }

    protected function isValidRow(Collection $row): bool
    {
        return $row->count() >= 12
            && !empty($row[0])
            && !empty($row[1]);
    }

    protected function createOrUpdateVehicle(Collection $row): void
    {
        $manufacturer = trim($row[2] ?? '');
        $shortModel = trim($row[3] ?? '');

        $makeId = $this->findMakeId($manufacturer);
        $modelId = $this->findModelId($makeId, $shortModel);

        CapVehicle::query()->updateOrCreate(
            [
                'cap_code' => trim($row[0]),
                'type' => $this->type,
            ],
            [
                'cap_id' => (int) trim($row[1]),
                'manufacturer' => $manufacturer,
                'short_model' => $shortModel,
                'model' => trim($row[4] ?? ''),
                'model_introduced' => $this->parseYear($row[5] ?? null),
                'model_discontinued' => $this->parseYear($row[6] ?? null),
                'short_derivative' => trim($row[7] ?? ''),
                'derivative' => trim($row[8] ?? ''),
                'derivative_introduced_year' => $this->parseYear($row[9] ?? null),
                'derivative_discontinued_year' => $this->parseYear($row[10] ?? null),
                'available_new_vehicle' => $this->parseBoolean($row[11] ?? null),
                'make_id' => $makeId,
                'model_id' => $modelId,
            ]
        );
    }

    protected function parseYear($value): ?int
    {
        if (empty($value)) {
            return null;
        }

        $year = (int) trim($value);
        return $year > 0 ? $year : null;
    }

    protected function parseBoolean($value): bool
    {
        if (empty($value)) {
            return false;
        }

        $value = strtolower(trim($value));
        return in_array($value, ['1', 'true', 'yes', 'y'], true);
    }

    public function chunkSize(): int
    {
        return 1000;
    }

    public function batchSize(): int
    {
        return 500;
    }

    public function getImportedCount(): int
    {
        return $this->imported;
    }

    public function getFailedCount(): int
    {
        return $this->failed;
    }
}
