<?php

namespace App;

use App\Models\ImportCondition;
use Illuminate\Support\Collection;
use Mtc\MercuryDataModels\BodyStyleType;
use Mtc\MercuryDataModels\Dealership;
use Mtc\MercuryDataModels\Franchise;
use Mtc\MercuryDataModels\FuelType;
use Mtc\MercuryDataModels\Label;
use Mtc\MercuryDataModels\TransmissionType;
use Mtc\MercuryDataModels\VehicleAttribute;
use Mtc\MercuryDataModels\VehicleMake;
use Mtc\MercuryDataModels\VehicleModel;

class ImportConditionRepository
{
    /**
     * Prefix used to namespace dynamic vehicle attribute fields so they never
     * collide with real vehicle columns / relations in condition rules.
     */
    public const ATTRIBUTE_FIELD_PREFIX = 'attribute.';

    protected static array $vehicle_fields = [
        [
            'name' => 'type',
            'type' => 'enum',
        ],
        [
            'name' => 'vrm_condensed',
            'type' => 'value_field',
        ],
        [
            'name' => 'vin',
            'type' => 'value_field',
        ],
        [
            'name' => 'make_id',
            'type' => 'related_model',
        ],
        [
            'name' => 'model_id',
            'type' => 'related_model',
        ],
        [
            'name' => 'dealership_id',
            'type' => 'related_model',
        ],
        [
            'name' => 'body_style_id',
            'type' => 'related_model',
        ],
        [
            'name' => 'fuel_type_id',
            'type' => 'related_model',
        ],
        [
            'name' => 'transmission_id',
            'type' => 'related_model',
        ],
        [
            'name' => 'image_count',
            'type' => 'relation_count',
        ],
        [
            'name' => 'finance_count',
            'type' => 'relation_count',
        ],
        [
            'name' => 'price',
            'type' => 'value_field',
        ],
        [
            'name' => 'monthly_price',
            'type' => 'value_field',
        ],
        [
            'name' => 'age',
            'type' => 'value_field',
        ],
        [
            'name' => 'age_months',
            'type' => 'value_field',
        ],
        [
            'name' => 'odometer',
            'type' => 'value_field',
        ],
        [
            'name' => 'label',
            'type' => 'related_model',
        ],
        [
            'name' => 'condition',
            'type' => 'enum',
        ],
    ];

    protected static array $new_car_fields = [
        [
            'name' => 'make_id',
            'type' => 'related_model',
        ],
        [
            'name' => 'model_id',
            'type' => 'related_model',
        ],
        [
            'name' => 'franchise_id',
            'type' => 'related_model',
        ],
        [
            'name' => 'dealership_id',
            'type' => 'related_model',
        ],
        [
            'name' => 'body_style_id',
            'type' => 'related_model',
        ],
        [
            'name' => 'fuel_type_id',
            'type' => 'related_model',
        ],
        [
            'name' => 'image_count',
            'type' => 'relation_count',
        ],
        [
            'name' => 'price',
            'type' => 'value_field',
        ],
    ];

    protected static array $conditions = [
        [
            'value' => '=',
            'applicable_to' => [
                'related_model',
                'relation_count',
                'value_field',
                'enum',
            ]
        ],
        [
            'value' => '!=',
            'applicable_to' => [
                'related_model',
                'relation_count',
                'value_field',
                'enum',
            ]
        ],
        [
            'value' => '>',
            'applicable_to' => [
                'relation_count',
                'value_field',
            ]
        ],
        [
            'value' => '>=',
            'applicable_to' => [
                'relation_count',
                'value_field',
            ]
        ],
        [
            'value' => '<',
            'applicable_to' => [
                'relation_count',
                'value_field',
            ]
        ],
        [
            'value' => '<=',
            'applicable_to' => [
                'relation_count',
                'value_field',
            ]
        ],
        [
            'value' => 'is_null',
            'applicable_to' => [
                'relation_count',
                'value_field',
            ]
        ],
        [
            'value' => 'exists',
            'applicable_to' => [
                'value_field',
            ]
        ],
        [
            'value' => 'in',
            'applicable_to' => [
                'related_model',
                'value_field',
                'enum',
            ]
        ],
        [
            'value' => 'not_in',
            'applicable_to' => [
                'related_model',
                'value_field',
                'enum',
            ]
        ],
    ];

    public function update(ImportCondition $condition, array $input): void
    {
        $condition->update($input);
        $rules = collect($input['rules'] ?? [])
            ->map(fn ($rule) => $this->normalizeRuleValue($rule));

        // Remove rules not in list
        $condition->rules()
            ->whereNotIn('id', $rules->pluck('id'))
            ->delete();

        // Add/Update rules
        $rules->each(fn ($rule) => $condition->rules()->updateOrCreate([ 'id' => $rule['id'] ], $rule));
    }

    /**
     * Normalize rule value - convert arrays to JSON for in/not_in conditions.
     */
    private function normalizeRuleValue(array $rule): array
    {
        if (is_array($rule['value'] ?? null)) {
            $rule['value'] = json_encode($rule['value']);
        }

        return $rule;
    }

    public function getFields(?string $type = null): Collection
    {
        $fields = $type === 'new_car' ? self::$new_car_fields : self::$vehicle_fields;

        return collect($fields)
            ->map(fn ($field) => [
                'id' => $field['name'],
                'name' => __('vehicles.' . $field['name']),
            ])
            ->concat($this->getAttributeFields())
            ->values();
    }

    /**
     * Vehicle attributes exposed as selectable, free-text condition fields.
     */
    protected function getAttributeFields(): Collection
    {
        return VehicleAttribute::query()
            ->where('model', 'vehicle')
            ->orderBy('name')
            ->get(['name', 'slug'])
            ->map(fn (VehicleAttribute $attribute) => [
                'id' => self::ATTRIBUTE_FIELD_PREFIX . $attribute->slug,
                'name' => $attribute->name,
            ]);
    }

    public static function isAttributeField(string $field): bool
    {
        return str_starts_with($field, self::ATTRIBUTE_FIELD_PREFIX);
    }

    public function getConditions(?string $field, ?string $type = null): Collection
    {
        if (empty($field)) {
            return collect();
        }

        $fields = $type === 'new_car' ? self::$new_car_fields : self::$vehicle_fields;

        // Attributes are always free-text value fields (entered comma-separated for in/not_in).
        $field_type = $this->isAttributeField($field)
            ? 'value_field'
            : collect($fields)->firstWhere('name', $field)['type'] ?? null;

        if (empty($field_type)) {
            return collect();
        }

        return collect(self::$conditions)
            ->filter(fn ($condition) => in_array($field_type, $condition['applicable_to']))
            // Attributes resolve to a stored string, so only equality/list/null checks apply –
            // numeric comparisons and "exists" (which builds a raw column query) are excluded.
            ->when(
                $this->isAttributeField($field),
                fn ($conditions) => $conditions->whereIn('value', ['=', '!=', 'in', 'not_in', 'is_null'])
            )
            ->map(fn ($condition) => [
                'id' => $condition['value'],
                'name' => __('labels.conditions.' . $condition['value']),
            ])
            ->values();
    }

    public function getValues(?string $field, ?string $condition): Collection
    {
        if (empty($field)) {
            return collect();
        }

        return match ($field) {
            'type' => collect(VehicleType::cases())
                ->map(fn (VehicleType $value) => [
                    'id' => $value->value,
                    'name' => $value->name,
                ]),
            'make_id' => VehicleMake::query()->select('id', 'name')->get(),
            'model_id' => VehicleModel::query()->select('id', 'name')->get(),
            'dealership_id' => Dealership::query()->select('id', 'name')->get(),
            'franchise_id' => Franchise::query()->select('id', 'name')->get(),
            'fuel_type_id' => FuelType::query()->select('id', 'name')->get(),
            'transmission_id' => TransmissionType::query()->select('id', 'name')->get(),
            'body_style_id' => BodyStyleType::query()->select('id', 'name')->get(),
            'label' => Label::query()->select('id', 'name')->where('active', true)->get(),
            'condition' => collect([
                ['id' => 1, 'name' => 'New'],
                ['id' => 0, 'name' => 'Used'],
            ]),
            default => collect(),
        };
    }

    public function getValue(string $field, $id)
    {
        return match ($field) {
            'make_id' => VehicleMake::query()->find($id)?->name ?? '',
            'model_id' => VehicleModel::query()->find($id)?->name ?? '',
            'dealership_id' => Dealership::query()->find($id)?->name ?? '',
            'franchise_id' => Franchise::query()->find($id)?->name ?? '',
            'fuel_type_id' => FuelType::query()->find($id)?->name ?? '',
            'transmission_id' => TransmissionType::query()->find($id)?->name ?? '',
            'body_style_id' => BodyStyleType::query()->find($id)?->name ?? '',
            'label' => Label::query()->find($id)?->name ?? '',
            'condition' => (int) $id === 1 ? 'New' : 'Used',
            default => $id,
        };
    }
}
