<?php

declare(strict_types=1);

namespace Dealerdirect\Agreements\Tests\Traits;

use Dealerdirect\Agreements\DataObjects\Agent;
use Dealerdirect\Agreements\DataObjects\Conditions;
use Dealerdirect\Agreements\DataObjects\Contact;
use Dealerdirect\Agreements\DataObjects\PurchaseAgreement;
use Dealerdirect\Agreements\DataObjects\SalesAgreement;
use Dealerdirect\Agreements\DataObjects\Vehicle;
use Dealerdirect\Agreements\Enums\Locale;
use DealerDirect\Generic\Category as Enums;

trait DataObjectFixtures
{
    /**
     * @param array<int,array<string,mixed>>|null $checklist
     */
    protected static function fixtureSalesAgreement(
        ?Locale $locale = null,
        ?string $vehicleType = null,
        ?int $lotId = null,
        ?int $deliverId = null,
        ?int $siteReference = null,
        ?Contact $consumer = null,
        ?Vehicle $vehicle = null,
        ?Conditions $conditions = null,
        ?Contact $company = null,
        ?Agent $salesAgent = null,
        ?array $checklist = null,
        ?string $internalComments = null,
        ?string $consumerComments = null,
        ?bool $pickUp = null,
        ?\DateTime $soldDate = null,
        ?int $salesPrice = null,
        ?int $salesFee = null,
    ): SalesAgreement {
        return new SalesAgreement(
            locale: $locale ?? Locale::NL_NL,
            vehicleType: $vehicleType ?? Enums\VehicleType::CAR,
            lotId: $lotId ?? 12345,
            deliverId: $deliverId ?? 1234,
            siteReference: $siteReference ?? Enums\Site::REF_CAR_NL,
            consumer: $consumer ?? self::fixtureConsumer(),
            vehicle: $vehicle ?? self::fixtureVehicle(),
            company: $company ?? self::fixtureCompany(),
            salesAgent: $salesAgent ?? self::fixtureAgent(),
            internalComments: $internalComments ?? '',
            consumerComments: $consumerComments ?? '',
            pickUp: $pickUp ?? true,
            soldDate: $soldDate ?? new \DateTime(),
            salesPrice: $salesPrice ?? 8000,
            salesFee: $salesFee ?? 500,
        );
    }

    protected static function fixturePurchaseAgreement(
        ?Locale $locale = null,
        ?string $vehicleType = null,
        ?int $lotId = null,
        ?int $deliverId = null,
        ?int $siteReference = null,
        ?int $callGroupId = null,
        ?Contact $company = null,
        ?Contact $consumer = null,
        ?Vehicle $vehicle = null,
        ?Agent $salesAgent = null,
        ?int $pickUp = null,
        ?\DateTime $soldDate = null,
        ?int $salesPrice = null,
        ?int $salesFee = null,
    ): PurchaseAgreement {
        return new PurchaseAgreement(
            locale: $locale ?? Locale::NL_NL,
            vehicleType: $vehicleType ?? Enums\VehicleType::CAR,
            lotId: $lotId ?? 12345,
            deliverId: $deliverId ?? 1234,
            siteReference: $siteReference ?? Enums\Site::REF_CAR_NL,
            callGroupId: $callGroupId ?? 123,
            company: $company ?? self::fixtureCompany(),
            consumer: $consumer ?? self::fixtureConsumer(),
            vehicle: $vehicle ?? self::fixtureVehicle(),
            salesAgent: $salesAgent ?? self::fixtureAgent(),
            pickUp: $pickUp ?? 1,
            soldDate: $soldDate ?? new \DateTime(),
            salesPrice: $salesPrice ?? 8000,
            salesFee: $salesFee ?? 500,
            internalComments: '',
            consumerComments: '',
        );
    }

    /**
     * @param string[]|null $emails
     */
    protected static function fixtureConsumer(
        ?array $emails = null,
    ): Contact {
        return new Contact(
            id: 1,
            firstName: 'Sjaak',
            lastName: 'Afhaak',
            salutation: null,
            name: 'Sjaak Afhaak',
            companyNameSeller: 'Cafe foo bar',
            streetName: 'Main Street',
            houseNumber: '123',
            zipCode: '1234 AB',
            city: 'Amsterdam',
            country: Enums\Country::NETHERLANDS,
            phoneNumbers: ['+31612345678'],
            emails: $emails ?? ['a.b@c.de'],
        );
    }

    protected static function fixtureVehicle(
        ?int $constructionYear = null,
        ?int $bodyType = null,
        ?int $odoMeterReading = 130000,
        ?int $odoMeterReadingUnit = null,
        ?int $bicycleType = null,
        ?int $enginePosition = null,
        ?int $batteryWattage = null,
        ?int $upholstery = null,
    ): Vehicle {
        $colors = array_filter(Enums\Color::getAll(), fn (int $color) => $color % 2 !== 0);
        $colorId = self::randomItem($colors);

        return new Vehicle(
            brand: 'Volkswagen',
            model: 'Golf',
            bodyType: $bodyType ?? self::randomItem(Enums\VehicleTypeCarBodyType::getAll()),
            vehicleTrim: 'Highline',
            engineCapacity: 1400,
            enginePowers: [110],
            fuel: self::randomItem(Enums\Fuel::getAll()),
            transmission: self::randomItem(Enums\VehicleTypeCarTransmission::getAll()),
            odometerReading: $odoMeterReading,
            odometerReadingUnit: $odoMeterReadingUnit ?? Enums\DistanceUnit::KM,
            constructionYear: $constructionYear ?? self::randomItem(range(1990, (int) date('Y'))),
            colors: [$colorId],
            inspectionValidUntil: new \DateTime('+4 months'),
            firstAscriptionDate: new \DateTime('-5 years'),
            paintType: self::randomItem(Enums\PaintworkType::getAll()),
            upholstery: $upholstery ?? self::randomItem(Enums\Upholstery::getAll()),
            marginVat: self::randomItem(Enums\ValueAddedTax::getAll()),
            options: self::randomItem(Enums\VehicleTypeCarOptions::getAll(), 10),
            licensePlate: 'AB-12-CD',
            vin: null,
            registrationPossible: 1,
            wokNotification: 0,
            maintenanceHistory: 1,
            bicycleType: $bicycleType,
            enginePosition: $enginePosition,
            batteryWattage: $batteryWattage,
            amountOfGears: null,
            oldNewModel: self::randomItem(Enums\OldNewModel::getAll()),
            image: null,
            conditions: self::fixtureConditions(),
            checklist: null,
            cylinderAmount: null,
        );
    }

    protected static function fixtureConditions(): Conditions
    {
        return new Conditions(
            exterior: self::randomItem(Enums\VehicleTypeCarCondition::getAll()),
            technical: self::randomItem(Enums\VehicleTypeCarCondition::getAll()),
            drivable: self::randomItem(Enums\Driveable::getAll()),
            damageFree: self::randomItem(Enums\DamageFree::getAll()),
            interior: self::randomItem(Enums\VehicleTypeCarCondition::getAll()),
            tireProfile: self::randomItem(Enums\VehicleTypeCarCondition::getAll()),
            frontTireProfile: self::randomItem(Enums\VehicleTypeMotorCondition::getAll()),
            rearTireProfile: self::randomItem(Enums\VehicleTypeMotorCondition::getAll()),
            propulsion: self::randomItem(Enums\VehicleTypeMotorCondition::getAll()),
            general: self::randomItem(Enums\VehicleTypeMotorCondition::getAll()),
            battery: self::randomItem(Enums\VehicleTypeMotorCondition::getAll()),
        );
    }

    /**
     * @param string[] $emails
     */
    protected static function fixtureCompany(
        ?array $emails = null,
    ): Contact {
        return new Contact(
            id: 1,
            firstName: null,
            lastName: null,
            salutation: null,
            name: 'Autoboer B.V.',
            companyNameSeller: null,
            streetName: 'Sub Street',
            houseNumber: '123',
            zipCode: '1234 AB',
            city: 'Amsterdam',
            country: Enums\Country::NETHERLANDS,
            phoneNumbers: ['+31612345678'],
            emails: $emails ?? ['autoboer@joejoe.nl'],
        );
    }

    protected static function fixtureAgent(): Agent
    {
        return new Agent(9, 'Benny Doof');
    }

    /**
     * @param mixed[] $array
     */
    abstract protected static function randomItem(array $array, int $amount = 1): mixed;
}
