<?php

namespace App\Traits;

use App\Models\ImportCondition;
use App\Models\ImportConditionRule;
use Closure;
use Illuminate\Support\Collection;
use Mtc\MercuryDataModels\Contracts\HasMediaChecksums;
use Mtc\MercuryDataModels\Vehicle;

trait ImportChecksConditions
{
    protected Collection $conditions;

    public function shouldBePublished(
        Closure $integrationPublishLogic,
        string $provider,
        Vehicle $vehicle,
        ?int $importMap = null
    ): ?bool {
         $conditions = $this->getConditionsForProvider($provider, $importMap)
             ->filter(fn(ImportCondition $condition) => $condition->do_not_publish);
        if ($conditions->isEmpty()) {
            return $integrationPublishLogic();
        }

         $conditionsForbidPublish = $conditions
            ->filter(fn(ImportCondition $condition) => $this->conditionAppliesToVehicle($condition, $vehicle))
            ->isNotEmpty();

         return $conditionsForbidPublish
             ? false
             : $integrationPublishLogic();
    }

    public function skipImporting(
        string $provider,
        array $data,
        ?int $importMap = null
    ): ?bool {
         $conditions = $this->getConditionsForProvider($provider, $importMap)
             ->filter(fn(ImportCondition $condition) => $condition->do_not_import);
        if ($conditions->isEmpty()) {
            return false;
        }

         return $conditions
            ->filter(fn(ImportCondition $condition) => $this->conditionAppliesToVehicleData($condition, $data))
            ->isNotEmpty();
    }

    public function imageChecksumMismatch(array $images, HasMediaChecksums $model): bool
    {
        $current_checksum = $model[$model->imageChecksumAttribute()];
        array_unshift($images, count($images));
        return dechex(crc32(json_encode($images))) !== $current_checksum;
    }

    private function getConditionsForProvider(?string $provider, ?int $importMap): Collection
    {
        if (!isset($this->conditions)) {
            $this->conditions = ImportCondition::query()
                ->with('rules')
                ->where('active', 1)
                ->where(fn($query) => $query->whereNull('provider')
                    ->orWhere(fn($providerQuery) => $providerQuery
                        ->where('provider', $provider)
                        ->when($importMap, fn($importQuery) => $importQuery->where('import_map_id', $importMap))))
                ->get();
        }
        return $this->conditions;
    }

    private function conditionAppliesToVehicle(ImportCondition $condition, Vehicle $vehicle): bool
    {
        if ($condition->rules->isEmpty()) {
            return true;
        }

        return $condition->rules
            ->reject(fn(ImportConditionRule $rule) => $this->ruleApplies($rule, $vehicle))
            ->isEmpty();
    }
    private function conditionAppliesToVehicleData(ImportCondition $condition, array $data): bool
    {
        if ($condition->rules->isEmpty()) {
            return true;
        }

        // Make sure that vrm_condensed is available for checks
        if (!empty($data['registration_number']) && empty($data['vrm_condensed'])) {
            $data['vrm_condensed'] = $data['registration_number'];
        }

        return $condition->rules
            ->reject(fn(ImportConditionRule $rule) => $this->ruleAppliesToData($rule, $data))
            ->isEmpty();
    }

    private function ruleApplies(ImportConditionRule $rule, Vehicle $vehicle): bool
    {
        return match ($rule->condition) {
            'exists' => Vehicle::query()->where($rule->field, $vehicle->getAttribute($rule->field))->exists(),
            '=' => $rule->value == $vehicle->getAttribute($rule->field),
            '!=' => $rule->value != $vehicle->getAttribute($rule->field),
            '>' => $vehicle->getAttribute($rule->field) > $rule->value,
            '>=' => $vehicle->getAttribute($rule->field) >= $rule->value,
            '<' => $vehicle->getAttribute($rule->field) < $rule->value,
            '<=' => $vehicle->getAttribute($rule->field) <= $rule->value,
            'is_null' => empty($vehicle->getAttribute($rule->field)),
            default => throw new \Exception('Unknown condition check: ' . $rule->condition . json_encode([
                'tenant' => tenant('id'),
                'rule' => $rule,
            ])),
        };
    }

    private function ruleAppliesToData(ImportConditionRule $rule, array $data): bool
    {
        if (!isset($data[$rule->field])) {
            return $rule->condition === 'is_null';
        }

        return match ($rule->condition) {
            'exists' => Vehicle::query()->where('stock_provider', '!=', $this->getProviderName())
                ->where($rule->field, $data[$rule->field])
                ->exists(),
            '=' => $rule->value == $data[$rule->field],
            '!=' => $rule->value != $data[$rule->field],
            '>' => $data[$rule->field] > $rule->value,
            '>=' => $data[$rule->field] >= $rule->value,
            '<' => $data[$rule->field] < $rule->value,
            '<=' => $data[$rule->field] <= $rule->value,
            default => throw new \Exception('Unknown condition check: ' . $rule->condition . json_encode([
                'tenant' => tenant('id'),
                'rule' => $rule,
            ])),
        };
    }
}
