<?php

namespace App\Modules\VehicleLabels;

use App\Facades\Settings;
use Carbon\Carbon;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
use Mtc\MercuryDataModels\Label;
use Mtc\MercuryDataModels\LabelRule;
use Mtc\MercuryDataModels\Vehicle;

class LabelRepository
{
    public function getAutomationOptions(): array
    {
        return $this->automationOptions()
            ->map(fn($option) => collect($option)->only(['id', 'name']))
            ->toArray();
    }

    public function getVehicleTypeOptions(): array
    {
        return [
            [
                'id' => 'any',
                'name' => 'Any'
            ],
            [
                'id' => 'car',
                'name' => 'Car'
            ],
            [
                'id' => 'lcv',
                'name' => 'LCV'
            ],
            [
                'id' => 'motorcycle',
                'name' => 'Motorcycle'
            ],
        ];
    }

    public function shouldAssign(Vehicle $vehicle, Label $label): bool
    {
        // Safe fallback. Assume applicable if setting does not exist.
        if (($label->data['applies_to_stock_vehicles'] ?? true) == false) {
            return false;
        }

        $exists = $vehicle->labels()->where('label_id', $label->id)->exists();
        $isApplicable = $this->conditionMatches($vehicle, $label->data['assign_when'] ?? null);

        $shouldCheckAdvancedRules = Settings::get('vehicle-labels-advanced-rules-enabled')
            && (
                empty($label->data['assign_when'])
                || $isApplicable
            );

        if ($shouldCheckAdvancedRules) {
            $isApplicable = $this->advancedConditionsMatch($vehicle, $label);
        }

        return !$exists && $isApplicable;
    }

    public function shouldRevoke(Vehicle $vehicle, Label $label): bool
    {
        // Safe fallback. Assume applicable if setting does not exist.
        if (($label->data['applies_to_stock_vehicles'] ?? true) == false) {
            return true;
        }

        $exists = $vehicle->labels()->where('label_id', $label->id)->exists();

        if (!$exists) {
            return true;
        }

        $isApplicable = $this->conditionMatches($vehicle, $label->data['revoke_when'] ?? null);

        if (
            Settings::get('vehicle-labels-advanced-rules-enabled')
            && $isApplicable == false
        ) {
            // if the advanced conditions do not match, the label is eligible for revoking
            $isApplicable = !$this->advancedConditionsMatch($vehicle, $label);
        }

        return $isApplicable;
    }

    private function advancedConditionsMatch(Vehicle $vehicle, Label $label): bool
    {
        $results = $this->evaluateAdvancedRules($vehicle, $label);

        return collect($results)->every(fn($result) => $result['passed']);
    }

    /**
     * Evaluate a single rule against a vehicle and return the result with vehicle value
     */
    private function evaluateRule(Vehicle $vehicle, LabelRule $rule, ?int $vehicleMileage, ?int $vehicleAge): array
    {
        $ruleValue = $rule->getValue();

        return match ($rule->condition_field) {
            'vehicle_price_min' => [
                'passed' => $vehicle->price >= $ruleValue,
                'vehicle_value' => $vehicle->price,
            ],
            'vehicle_price_max' => [
                'passed' => $vehicle->price <= $ruleValue,
                'vehicle_value' => $vehicle->price,
            ],
            'vehicle_mpg_min' => [
                'passed' => $vehicle->mpg >= $ruleValue,
                'vehicle_value' => $vehicle->mpg,
            ],
            'vehicle_mpg_max' => [
                'passed' => $vehicle->mpg <= $ruleValue,
                'vehicle_value' => $vehicle->mpg,
            ],
            'vehicle_mileage_min' => [
                'passed' => $vehicleMileage >= $ruleValue,
                'vehicle_value' => $vehicleMileage,
            ],
            'vehicle_mileage_max' => [
                'passed' => $vehicleMileage <= $ruleValue,
                'vehicle_value' => $vehicleMileage,
            ],
            'vehicle_days_in_stock_min' => [
                'passed' => $vehicle->daysInStock >= $ruleValue,
                'vehicle_value' => $vehicle->daysInStock,
            ],
            'vehicle_days_in_stock_max' => [
                'passed' => $vehicle->daysInStock <= $ruleValue,
                'vehicle_value' => $vehicle->daysInStock,
            ],
            'vehicle_age_min' => [
                'passed' => !empty($vehicle->first_registration_date) && ($vehicleAge >= $ruleValue),
                'vehicle_value' => $vehicleAge,
            ],
            'vehicle_age_max' => [
                'passed' => !empty($vehicle->first_registration_date) && ($vehicleAge <= $ruleValue),
                'vehicle_value' => $vehicleAge,
            ],
            'manufacture_year_min' => [
                'passed' => $vehicle->first_registration_date?->year >= $ruleValue,
                'vehicle_value' => $vehicle->first_registration_date?->year,
            ],
            'manufacture_year_max' => [
                'passed' => $vehicle->first_registration_date?->year <= $ruleValue,
                'vehicle_value' => $vehicle->first_registration_date?->year,
            ],
            'active_from' => [
                'passed' => Carbon::now() >= $ruleValue,
                'vehicle_value' => Carbon::now()->toDateString(),
            ],
            'active_to' => [
                'passed' => Carbon::now() < $ruleValue,
                'vehicle_value' => Carbon::now()->toDateString(),
            ],
            'transmission_id' => [
                'passed' => $vehicle->transmission_id == $ruleValue,
                'vehicle_value' => $vehicle->transmission_id,
            ],
            'fuel_type_id' => [
                'passed' => $vehicle->fuel_type_id == $ruleValue,
                'vehicle_value' => $vehicle->fuel_type_id,
            ],
            'vehicle_type' => [
                'passed' => $ruleValue == 'any' || $vehicle->type == $ruleValue,
                'vehicle_value' => $vehicle->type,
            ],
            'vehicle_category' => [
                'passed' => $vehicle->getCustom('vehicle_category') == $ruleValue,
                'vehicle_value' => $vehicle->getCustom('vehicle_category'),
            ],
            'vehicle_is_new' => [
                'passed' => $vehicle->is_new == $ruleValue,
                'vehicle_value' => $vehicle->is_new,
            ],
            'vrms_included' => [
                'passed' => in_array($vehicle->vrm_condensed, array_filter($ruleValue)),
                'vehicle_value' => $vehicle->vrm_condensed,
            ],
            'vrms_excluded' => [
                'passed' => !in_array($vehicle->vrm_condensed, array_filter($ruleValue)),
                'vehicle_value' => $vehicle->vrm_condensed,
            ],
            'vrm_is_empty' => [
                'passed' => empty($vehicle->vrm_condensed),
                'vehicle_value' => $vehicle->vrm_condensed,
            ],
            'make_ids' => [
                'passed' => in_array($vehicle->make_id, $ruleValue),
                'vehicle_value' => $vehicle->make_id,
            ],
            'model_ids' => [
                'passed' => in_array($vehicle->model_id, $ruleValue),
                'vehicle_value' => $vehicle->model_id,
            ],
            'dealership_ids' => [
                'passed' => in_array($vehicle->dealership_id, $ruleValue),
                'vehicle_value' => $vehicle->dealership_id,
            ],
            default => [
                'passed' => true,
                'vehicle_value' => null,
            ],
        };
    }

    /**
     * Evaluate all advanced rules for a label against a vehicle
     */
    private function evaluateAdvancedRules(Vehicle $vehicle, Label $label): array
    {
        $results = [];
        $vehicleMileage = Settings::get('automotive-distance_measurement') === 'mi'
            ? $vehicle->odometer_mi
            : $vehicle->odometer_km;
        $vehicleAge = $vehicle->first_registration_date
            ? Carbon::now()->diff($vehicle->first_registration_date)->y
            : null;

        $label->load('rules');

        foreach ($label->rules as $rule) {
            if ($rule->value_data_type != 'boolean' && empty($rule->condition_value)) {
                continue;
            }

            $evaluation = $this->evaluateRule($vehicle, $rule, $vehicleMileage, $vehicleAge);

            $results[] = [
                'rule' => $rule->friendly_name,
                'field' => $rule->condition_field,
                'passed' => $evaluation['passed'],
                'vehicle_value' => $evaluation['vehicle_value'],
                'rule_value' => $rule->getValue(),
                'reason' => $evaluation['passed']
                    ? 'Vehicle meets this condition'
                    : 'Vehicle does not meet this condition',
            ];
        }

        return $results;
    }

    private function conditionMatches(Vehicle $vehicle, ?string $param): bool
    {
        $matchedCondition = $this->automationOptions()
            ->filter(fn($condition) => $condition['id'] === $param)
            ->first();

        return $matchedCondition && $matchedCondition['condition']($vehicle);
    }

    /**
     * Test if a label would apply to a specific vehicle and return detailed rule matching results
     */
    public function testLabelAgainstVehicle(Vehicle $vehicle, Label $label): array
    {
        $results = [
            'would_apply' => false,
            'simple_condition' => null,
            'advanced_rules' => [],
            'summary' => [],
        ];

        // Check if label applies to stock vehicles
        if (($label->data['applies_to_stock_vehicles'] ?? true) == false) {
            $results['summary'][] = [
                'rule' => 'Applies to stock vehicles',
                'passed' => false,
                'reason' => 'Label is not configured to apply to stock vehicles',
            ];
            return $results;
        }

        // Check simple condition
        $simpleCondition = $label->data['assign_when'] ?? null;
        if ($simpleCondition) {
            $conditionPassed = $this->conditionMatches($vehicle, $simpleCondition);
            $conditionName = $this->automationOptions()
                ->filter(fn($condition) => $condition['id'] === $simpleCondition)
                ->first()['name'] ?? $simpleCondition;

            $results['simple_condition'] = [
                'condition' => $simpleCondition,
                'name' => $conditionName,
                'passed' => $conditionPassed,
            ];

            $results['summary'][] = [
                'rule' => 'Simple condition: ' . $conditionName,
                'passed' => $conditionPassed,
                'reason' => $conditionPassed ? 'Condition is met' : 'Condition is not met',
            ];

            if (!$conditionPassed) {
                return $results;
            }
        }

        // Check advanced rules if enabled
        if (Settings::get('vehicle-labels-advanced-rules-enabled')) {
            $advancedResults = $this->evaluateAdvancedRules($vehicle, $label);
            $results['advanced_rules'] = $advancedResults;

            foreach ($advancedResults as $ruleResult) {
                $results['summary'][] = $ruleResult;
            }

            $allAdvancedPassed = collect($advancedResults)->every(fn($r) => $r['passed']);
            $results['would_apply'] = $allAdvancedPassed;
        } else {
            // No advanced rules, simple condition determines result
            $results['would_apply'] = $results['simple_condition']['passed'] ?? true;
        }

        return $results;
    }

    private function automationOptions(): Collection
    {
        return collect([
            [
                'id' => 'available_date_in_future',
                'name' => 'Available Date is in future',
                'condition' => fn(Vehicle $vehicle) => $vehicle->available_date > Carbon::now(),
            ],
            [
                'id' => 'available_date_in_past',
                'name' => 'Available Date is in past',
                'condition' => fn(Vehicle $vehicle) => $vehicle->available_date < Carbon::now(),
            ],
            [
                'id' => 'is_reserved',
                'name' => 'Vehicle is reserved',
                'condition' => fn(Vehicle $vehicle) => $vehicle->is_reserved,
            ],
            [
                'id' => 'is_new',
                'name' => 'Vehicle is a new vehicle',
                'condition' => fn(Vehicle $vehicle) => $vehicle->is_new,
            ],
            [
                'id' => 'is_demo',
                'name' => 'Vehicle is an ex-demo vehicle',
                'condition' => fn(Vehicle $vehicle) => $vehicle->is_demo,
            ],
            [
                'id' => 'is_pre_reg',
                'name' => 'Vehicle is a Pre-Reg vehicle',
                'condition' => fn(Vehicle $vehicle) => $vehicle->is_pre_reg,
                'enabled' => Settings::get('vehicles-pre-reg-condition-enabled')
            ],
            [
                'id' => 'has_personalized_number_plate',
                'name' => 'Vehicle has a personalized number plate',
                'condition' => fn(Vehicle $vehicle) => $vehicle->personalized_number_plate,
            ],
            [
                'id' => 'has_reduced_price',
                'name' => 'Vehicle has a reduced(sale) price',
                'condition' => fn(Vehicle $vehicle) => $vehicle->price < $vehicle->original_price
                    && $vehicle->price > 0,
            ],
            [
                'id' => 'just_arrived',
                'name' => 'Just Arrived',
                'condition' => fn(Vehicle $vehicle) => $vehicle->created_at >= Carbon::now()->subDays(
                    Settings::get('vehicle-labels-just-arrived-days')
                ),
            ],
            [
                'id' => 'not_just_arrived',
                'name' => 'Not Just Arrived',
                'condition' => fn(Vehicle $vehicle) => $vehicle->created_at < Carbon::now()->subDays(
                    Settings::get('vehicle-labels-just-arrived-days')
                ),
            ],
        ])->filter(fn($condition) => $condition['enabled'] ?? true);
    }
}
