<?php

declare(strict_types=1);

namespace Dealerdirect\Agreements\Utils;

use Dealerdirect\Agreements\DataObjects\Vehicle;
use Dealerdirect\Generic\Enums\SiteReference;

final class VehicleData
{
    private const FIELD_BODY_TYPE = 'body_type';
    private const FIELD_BRAND_MODEL = 'brand-model';
    private const FIELD_BICYCLE_TYPE = 'type';
    private const FIELD_ENGINE_POSITION = 'engine_position';
    private const FIELD_BATTERY_WATTAGE = 'battery_wattage';
    private const FIELD_COLOR = 'color';
    private const FIELD_COLORS = 'colors';
    private const FIELD_CYLINDERS = 'cylinders';
    private const FIELD_CONSTRUCTION_YEAR_AND_ODOMETER = 'construction_year_and_odometer';
    private const FIELD_ENGINE_CAPACITY = 'engine_capacity';
    private const FIELD_ENGINE_POWER = 'engine_power';
    private const FIELD_FUEL = 'fuel';
    private const FIELD_AMOUNT_OF_GEARS = 'amount_of_gears';
    private const FIELD_INSPECTION_VALID_UNTIL = 'inspection_valid_until';
    private const FIELD_LICENSE_PLATE = 'license_plate';
    private const FIELD_MAINTENANCE_HISTORY = 'maintenance_history';
    private const FIELD_MARGIN_VAT = 'margin_vat';
    private const FIELD_OLD_NEW_MODEL = 'old_new_model';
    private const FIELD_REGISTRATION_POSSIBLE = 'registration_possible';
    private const FIELD_TRANSMISSION = 'transmission';
    private const FIELD_UPHOLSTERY = 'upholstery';
    private const FIELD_VEHICLE_TRIM = 'vehicle_trim';
    private const FIELD_VIN = 'vin';
    private const FIELD_WOK_NOTIFICATION = 'wok_notification';

    public static function for(Translator $translator, Vehicle $vehicle, SiteReference $siteReference): array
    {
        return match ($siteReference) {
            SiteReference::CAR_MARKTPLAATS_NL,
            SiteReference::CAR_NL => self::forCarNl($translator, $vehicle),

            SiteReference::CAR_BE_NL => self::forCarBe($translator, $vehicle),

            SiteReference::MOTORBIKE_NL,
            SiteReference::SCOOTER_NL => self::forMotorbikeNl($translator, $vehicle),

            SiteReference::MOTORBIKE_BE,
            SiteReference::MOTORBIKE_DE => self::forMotorbike($translator, $vehicle),

            SiteReference::BICYCLE_NL => self::forBicycle($translator, $vehicle),

            default => throw new \InvalidArgumentException("Unsupported site reference: {$siteReference->value}"),
        };
    }

    public static function forCarNl(Translator $translator, Vehicle $vehicle): array
    {
        return self::render($translator, $vehicle, [
            self::FIELD_BRAND_MODEL,
            self::FIELD_LICENSE_PLATE,
            self::FIELD_CONSTRUCTION_YEAR_AND_ODOMETER,
            self::FIELD_OLD_NEW_MODEL,
            self::FIELD_BODY_TYPE,
            self::FIELD_VEHICLE_TRIM,
            self::FIELD_ENGINE_CAPACITY,
            self::FIELD_ENGINE_POWER,
            self::FIELD_FUEL,
            self::FIELD_COLOR,
            self::FIELD_TRANSMISSION,
            self::FIELD_MAINTENANCE_HISTORY,
            self::FIELD_INSPECTION_VALID_UNTIL,
            self::FIELD_UPHOLSTERY,
            self::FIELD_WOK_NOTIFICATION,
            self::FIELD_REGISTRATION_POSSIBLE,
            self::FIELD_MARGIN_VAT,
        ]);
    }

    public static function forCarBe(Translator $translator, Vehicle $vehicle): array
    {
        return self::render($translator, $vehicle, [
            self::FIELD_BRAND_MODEL,
            self::FIELD_VIN,
            self::FIELD_CONSTRUCTION_YEAR_AND_ODOMETER,
            self::FIELD_OLD_NEW_MODEL,
            self::FIELD_BODY_TYPE,
            self::FIELD_VEHICLE_TRIM,
            self::FIELD_ENGINE_CAPACITY,
            self::FIELD_ENGINE_POWER,
            self::FIELD_FUEL,
            self::FIELD_COLOR,
            self::FIELD_TRANSMISSION,
            self::FIELD_MAINTENANCE_HISTORY,
            self::FIELD_UPHOLSTERY,
            self::FIELD_MARGIN_VAT,
        ]);
    }

    public static function forMotorbikeNl(Translator $translator, Vehicle $vehicle): array
    {
        return self::render($translator, $vehicle, [
            self::FIELD_BRAND_MODEL,
            self::FIELD_LICENSE_PLATE,
            self::FIELD_CONSTRUCTION_YEAR_AND_ODOMETER,
            self::FIELD_BODY_TYPE,
            self::FIELD_VEHICLE_TRIM,
            self::FIELD_CYLINDERS,
            self::FIELD_ENGINE_POWER,
            self::FIELD_FUEL,
            self::FIELD_COLORS,
            self::FIELD_TRANSMISSION,
            self::FIELD_MAINTENANCE_HISTORY,
            self::FIELD_WOK_NOTIFICATION,
            self::FIELD_REGISTRATION_POSSIBLE,
            self::FIELD_MARGIN_VAT,
        ]);
    }

    public static function forMotorbike(Translator $translator, Vehicle $vehicle): array
    {
        return self::render($translator, $vehicle, [
            self::FIELD_BRAND_MODEL,
            self::FIELD_VIN,
            self::FIELD_CONSTRUCTION_YEAR_AND_ODOMETER,
            self::FIELD_BODY_TYPE,
            self::FIELD_VEHICLE_TRIM,
            self::FIELD_ENGINE_CAPACITY,
            self::FIELD_ENGINE_POWER,
            self::FIELD_FUEL,
            self::FIELD_COLORS,
            self::FIELD_TRANSMISSION,
            self::FIELD_MAINTENANCE_HISTORY,
            self::FIELD_MARGIN_VAT,
        ]);
    }

    public static function forBicycle(Translator $translator, Vehicle $vehicle): array
    {
        return self::render($translator, $vehicle, [
            self::FIELD_BRAND_MODEL,
            self::FIELD_BICYCLE_TYPE,
            self::FIELD_CONSTRUCTION_YEAR_AND_ODOMETER,
            self::FIELD_ENGINE_POSITION,
            self::FIELD_BATTERY_WATTAGE,
            self::FIELD_AMOUNT_OF_GEARS, // TODO: Check this..
            self::FIELD_COLORS,
            self::FIELD_MAINTENANCE_HISTORY,
        ]);
    }

    private static function render(Translator $translator, Vehicle $vehicle, array $keys): array
    {
        $data = [];
        foreach ($keys as $key) {
            $label = $translator->get("labels.$key");

            $data[$label] = self::data($translator, $vehicle, $key);
        }

        return $data;
    }

    private static function data(Translator $translator, Vehicle $vehicle, string $key): string|int
    {
        return match ($key) {
            self::FIELD_BODY_TYPE => self::getBodyType($translator, $vehicle),
            self::FIELD_BRAND_MODEL => self::getBrandModel($vehicle),
            self::FIELD_BICYCLE_TYPE => self::getBicycleType($translator, $vehicle),
            self::FIELD_ENGINE_POSITION => self::getEnginePosition($translator, $vehicle),
            self::FIELD_BATTERY_WATTAGE => self::getBatteryWattage($translator, $vehicle),
            self::FIELD_COLOR => self::getColor($translator, $vehicle),
            self::FIELD_COLORS => self::getColor($translator, $vehicle),
            self::FIELD_CYLINDERS => self::getCylinders($translator, $vehicle),
            self::FIELD_CONSTRUCTION_YEAR_AND_ODOMETER => self::getConstructionYearAndOdometer($vehicle),
            self::FIELD_ENGINE_CAPACITY => self::getEngineCapacity($vehicle),
            self::FIELD_ENGINE_POWER => self::getEnginePower($vehicle),
            self::FIELD_FUEL => self::getFuel($translator, $vehicle),
            self::FIELD_AMOUNT_OF_GEARS => $vehicle->amountOfGears ?? $translator->get('labels.unknown'),
            self::FIELD_INSPECTION_VALID_UNTIL => self::getInspectionValidUntil($translator, $vehicle),
            self::FIELD_LICENSE_PLATE => $vehicle->licensePlate ?? '',
            self::FIELD_MAINTENANCE_HISTORY => self::getMaintenanceHistory($translator, $vehicle),
            self::FIELD_MARGIN_VAT => self::getMarginVat($translator, $vehicle),
            self::FIELD_OLD_NEW_MODEL => self::getOldNewModel($translator, $vehicle),
            self::FIELD_REGISTRATION_POSSIBLE => self::getRegistrationPossible($translator, $vehicle),
            self::FIELD_TRANSMISSION => self::getTransmission($translator, $vehicle),
            self::FIELD_UPHOLSTERY => self::getUpholstery($translator, $vehicle),
            self::FIELD_VEHICLE_TRIM => $vehicle->vehicleTrim ?: $translator->get('labels.unknown'),
            self::FIELD_VIN => $vehicle->vin ?? '',
            self::FIELD_WOK_NOTIFICATION => self::getWokNotification($translator, $vehicle),

            default => throw new \InvalidArgumentException("Unsupported field: $key"),
        };
    }

    private static function getBrandModel(Vehicle $vehicle): string
    {
        return "{$vehicle->brand} {$vehicle->model}";
    }

    private static function getBicycleType(Translator $translator, Vehicle $vehicle): string
    {
        if (empty($vehicle->bicycleType)) {
            return $translator->get('labels.unknown');
        }

        return $translator->get("bicycle.bicycle_type.{$vehicle->bicycleType}");
    }

    private static function getEnginePosition(Translator $translator, Vehicle $vehicle): string
    {
        if (empty($vehicle->enginePosition)) {
            return $translator->get('labels.unknown');
        }

        return $translator->get("bicycle.engine_position.{$vehicle->enginePosition}");
    }

    private static function getBatteryWattage(Translator $translator, Vehicle $vehicle): string
    {
        if (empty($vehicle->batteryWattage)) {
            return $translator->get('labels.unknown');
        }

        return $translator->get("bicycle.battery_wattage.{$vehicle->batteryWattage}");
    }

    private static function getConstructionYearAndOdometer(Vehicle $vehicle): string
    {
        return GeneralUtils::combineValues(' / ', [$vehicle->constructionYear, $vehicle->getOdometerReading()]);
    }

    private static function getOldNewModel(Translator $translator, Vehicle $vehicle): string
    {
        return $translator->get(
            sprintf('general.oldNewModel.%d', $vehicle->oldNewModel ?? 0)
        );
    }

    private static function getBodyType(Translator $translator, Vehicle $vehicle): string
    {
        return $translator->get(
            sprintf('vehicle.bodytype.%d', $vehicle->bodyType)
        );
    }

    private static function getEngineCapacity(Vehicle $vehicle): string
    {
        return $vehicle->engineCapacity
            ? sprintf('%s cc', GeneralUtils::formatNumber($vehicle->engineCapacity))
            : '';
    }

    private static function getEnginePower(Vehicle $vehicle): string
    {
        return GeneralUtils::combineValues(' / ', array_map(
            fn(int $enginePower) => GeneralUtils::formatNumber($enginePower) . ' kW',
            $vehicle->enginePowers
        ));
    }

    private static function getFuel(Translator $translator, Vehicle $vehicle): string
    {
        return $translator->get(sprintf('general.fuel.%d', $vehicle->fuel));
    }

    private static function getColor(Translator $translator, Vehicle $vehicle): string
    {
        $colors = array_filter($vehicle->colors);

        return GeneralUtils::combineValues(' / ', array_map(
            fn(int $color) => $translator->get("general.color.$color"),
            $colors
        ));
    }

    private static function getCylinders(Translator $translator, Vehicle $vehicle): string
    {
        return $translator->get('purchase_agreement.cylinders', [
            'cylinders' => $vehicle->cylinderAmount ?? 0
        ]);
    }

    private static function getTransmission(Translator $translator, Vehicle $vehicle): string
    {
        return $translator->get(
            sprintf('vehicle.transmission.%d', $vehicle->transmission)
        );
    }

    private static function getMaintenanceHistory(Translator $translator, Vehicle $vehicle): string
    {
        return $translator->get(
            sprintf('general.serviceHistoryBooklet.%d', (int) $vehicle->maintenanceHistory)
        );
    }

    private static function getInspectionValidUntil(Translator $translator, Vehicle $vehicle): string
    {
        return $vehicle->inspectionValidUntil?->format('d-m-Y') ?? $translator->get('labels.unknown');
    }

    private static function getUpholstery(Translator $translator, Vehicle $vehicle): string
    {
        return $translator->get(
            sprintf('vehicle.upholstery.%d', $vehicle->upholstery ?? 0)
        );
    }

    private static function getWokNotification(Translator $translator, Vehicle $vehicle): string
    {
        return self::translateYesNo($translator, $vehicle->wokNotification);
    }

    private static function getRegistrationPossible(Translator $translator, Vehicle $vehicle): string
    {
        return self::translateYesNo($translator, $vehicle->registrationPossible);
    }

    private static function getMarginVat(Translator $translator, Vehicle $vehicle): string
    {
        return $translator->get(
            sprintf('general.valueaddedtax.%d', (int) $vehicle->marginVat)
        );
    }

    private static function translateYesNo(Translator $translator, $value): string
    {
        return match ($value) {
            1, true, 'true' => $translator->get('labels.yes'),
            0, false, 'false' => $translator->get('labels.no'),
            default => $translator->get('labels.unknown'),
        };
    }
}
