<?php

namespace App;

use App\Facades\Settings;
use App\Http\Requests\SearchRequest;
use Illuminate\Support\Collection;
use Mtc\ContentManager\Models\Template;
use Mtc\MercuryDataModels\BodyStyleType;
use Mtc\MercuryDataModels\Dealership;
use Mtc\MercuryDataModels\Enquiry;
use Mtc\MercuryDataModels\Form;
use Mtc\MercuryDataModels\Franchise;
use Mtc\MercuryDataModels\FuelType;
use Mtc\MercuryDataModels\GlobalContent;
use Mtc\MercuryDataModels\Menu;
use Mtc\MercuryDataModels\NewCar;
use Mtc\MercuryDataModels\OfferType;
use Mtc\MercuryDataModels\Page;
use Mtc\MercuryDataModels\TransmissionType;
use Mtc\MercuryDataModels\Vehicle;
use Mtc\MercuryDataModels\VehicleMake;
use Mtc\MercuryDataModels\VehicleModel;
use Mtc\MercuryDataModels\VehicleAttribute;
use Mtc\MercuryDataModels\VehicleAttributeValue;
use Mtc\MercuryDataModels\VehicleOffer;
use App\Models\ImportMap;

class AdminSearchRepository
{
    public function search(SearchRequest $request)
    {
        $type = $request->input('type') ?? 'all';
        return collect([
            'enquiries' => in_array($type, ['all', 'enquiry']) ? $this->enquiries($request) : null,
            'vehicles' => in_array($type, ['all', 'vehicle']) ? $this->vehicles($request) : null,
            'pages' => in_array($type, ['all', 'page']) ? $this->pages($request) : null,
            'offers' => in_array($type, ['all', 'offer']) ? $this->offers($request) : null,
            'new-car' => in_array($type, ['all', 'new-car']) ? $this->newCars($request) : null,
            'global' => in_array($type, ['all', 'global']) ? $this->globalContent($request) : null,
            'menu' => in_array($type, ['all', 'global']) ? $this->menus($request) : null,
            'dealership' => in_array($type, ['all', 'global']) ? $this->dealerships($request) : null,
            'form' => in_array($type, ['all', 'global']) ? $this->form($request) : null,
        ])
            ->filter()
            ->flatten(1)
            ->unique();
    }

    public function getSectionFilters(string $type): array
    {
        return match ($type) {
            'vehicles' => $this->getVehicleSectionFilters(),
            'car-configurator' => $this->getCarConfiguratorFilters(),
            'valuations' => $this->getValuationSectionFilters(),
            'offers' => $this->getOfferSectionFilters(),
            'new-vehicles', 'new-cars' => $this->getNewCarSectionFilters(),
            'content', 'pages' => $this->getPageSectionFilters(),
            'lease-vehicles' => $this->getLeaseVehicleSectionFilters(),
            default => [],
        };
    }

    public function getValuationSectionFilters(): array
    {
        return [
            [
                'value' => 'created_at',
                'name' => 'Date requested',
                'range' => true,
                'range_type' => 'date',
                'min' => null,
                'max' => null,
            ],
        ];
    }

    public function getVehicleSectionFilters(): array
    {
        return collect([
            $this->stockProvider(),
            [
                'value' => 'status',
                'name' => 'Status',
                'choices' => [
                    [
                        'id' => 'draft',
                        'name' => 'Draft/Unpublished',
                        'type' => 'status',
                    ],
                    [
                        'id' => 'is_published',
                        'name' => 'Published',
                        'type' => 'status',
                    ],
                    [
                        'id' => 'featured',
                        'name' => 'Featured',
                        'type' => 'status',
                    ],
                    [
                        'id' => 'is_reserved',
                        'name' => 'Reserved',
                        'type' => 'status',
                    ],
                    [
                        'id' => 'is_sold',
                        'name' => 'Sold',
                        'type' => 'status',
                    ],
                    [
                        'id' => 'deleted_at',
                        'name' => 'Archived',
                        'type' => 'status',
                    ],
                ],
            ],
            [
                'value' => 'type',
                'name' => 'Offer Type',
                'choices' => collect(VehicleType::cases())->map(fn (VehicleType $value) => [
                    'id' => $value->value,
                    'name' => $value->name,
                    'type' => 'type',
                ])
            ],
            [
                'value' => 'condition',
                'name' => 'Condition',
                'choices' => collect([
                    [
                        'id' => 'used',
                        'name' => 'Used',
                        'type' => 'age_type',
                    ],
                    [
                        'id' => 'is_demo',
                        'name' => 'Ex-Demo',
                        'type' => 'age_type',
                    ],
                    [
                        'id' => 'is_new',
                        'name' => 'New',
                        'type' => 'age_type',
                    ],
                    [
                        'id' => 'is_pre_reg',
                        'name' => 'Pre-Reg',
                        'type' => 'age_type',
                        'enabled' => Settings::get('vehicles-pre-reg-condition-enabled'),
                    ]
                ])->filter(fn ($dataField) => $dataField['enabled'] ?? true),
            ],
            $this->dealership(),
            $this->make('vehicles'),
            $this->model('vehicles'),
            $this->bodyStyle('vehicles'),
            $this->fuelType('vehicles'),
            $this->transmission('vehicles'),
            $this->price(),
            $this->imageCount(),
            $this->hasFinance(),
            $this->vatApplicable(),
            $this->autoTraderStatus(),
            ...$this->filterableVehicleAttributes(),
        ])
            ->filter(fn ($item) => $item['enabled'] ?? true)
            ->values()
            ->toArray();
    }


    public function getCarConfiguratorFilters(): array
    {
        return [
            [
                'value' => 'status',
                'name' => 'Status',
                'choices' => [
                    [
                        'id' => 'draft',
                        'name' => 'Draft/Unpublished',
                        'type' => 'status',
                    ],
                    [
                        'id' => 'active',
                        'name' => 'Published',
                        'type' => 'status',
                    ],
                    [
                        'id' => 'deleted_at',
                        'name' => 'Archived',
                        'type' => 'status',
                    ],
                ],
            ],
            $this->make('carConfigurations'),
            $this->model('carConfigurations'),
        ];
    }

    public function getOfferSectionFilters(): array
    {
        return [
            [
                'value' => 'status',
                'name' => 'Status',
                'choices' => [
                    [
                        'id' => 'draft',
                        'name' => 'Draft/Unpublished',
                        'type' => 'status',
                    ],
                    [
                        'id' => 'published',
                        'name' => 'Published',
                        'type' => 'status',
                    ],
                    [
                        'id' => 'featured',
                        'name' => 'Featured',
                        'type' => 'status',
                    ],
                    [
                        'id' => 'deleted_at',
                        'name' => 'Archived',
                        'type' => 'status',
                    ],
                ],
            ],
            [
                'value' => 'type_id',
                'name' => 'Offer Type',
                'choices' => OfferType::query()
                    ->whereHas('offers')
                    ->get()
                    ->map(fn (OfferType $value) => [
                        'id' => $value->id,
                        'name' => $value->name,
                        'type' => 'type',
                    ])
            ],
            $this->dealership(),
            $this->franchise(),
            $this->make('offers'),
            $this->model('offers'),
            $this->bodyStyle('offers'),
            $this->fuelType('offers'),
            $this->transmission('offers'),
            $this->price(),
            $this->imageCount(),
        ];
    }

    public function getNewCarSectionFilters(): array
    {
        return [
            [
                'value' => 'status',
                'name' => 'Status',
                'choices' => [
                    [
                        'id' => 'draft',
                        'name' => 'Draft/Unpublished',
                        'type' => 'status',
                    ],
                    [
                        'id' => 'published',
                        'name' => 'Published',
                        'type' => 'status',
                    ],
                    [
                        'id' => 'featured',
                        'name' => 'Featured',
                        'type' => 'status',
                    ],
                    [
                        'id' => 'deleted_at',
                        'name' => 'Archived',
                        'type' => 'status',
                    ],
                ],
            ],
            $this->franchise(),
            $this->make('newCars'),
            $this->model('newCars'),
            $this->bodyStyle('newCars'),
            $this->fuelType('newCars'),
            $this->transmission('newCars'),
            $this->price(),
        ];
    }

    public function getPageSectionFilters(): array
    {
        return [
            [
                'value' => 'status',
                'name' => 'Status',
                'choices' => [
                    [
                        'id' => 'draft',
                        'name' => 'Draft/Unpublished',
                        'type' => 'status',
                    ],
                    [
                        'id' => 'published',
                        'name' => 'Published',
                        'type' => 'status',
                    ],
                    [
                        'id' => 'featured',
                        'name' => 'Featured',
                        'type' => 'status',
                    ],
                    [
                        'id' => 'deleted_at',
                        'name' => 'Archived',
                        'type' => 'status',
                    ],
                ],
            ],
            [
                'value' => 'category',
                'name' => 'Type',
                'choices' => array_filter([
                    [
                        'id' => 'null',
                        'name' => __('pages.types.content_page'),
                        'type' => 'category',
                    ],
                    Settings::get('app-content-news-enabled')
                        ? [
                        'id' => 'news',
                        'name' => __('pages.types.news'),
                        'type' => 'category',
                    ]
                        : null,
                    Settings::get('app-content-blog-enabled')
                        ? [
                        'id' => 'blog',
                        'name' => __('pages.types.blog'),
                        'type' => 'category',
                    ]
                        : null,
                ]),
            ],
            $this->franchise(),
            [
                'value' => 'template_id',
                'name' => 'Template',
                'choices' => Template::query()
                    ->whereHas('pages')
                    ->select(['name', 'id'])
                    ->get()
                    ->map(function ($entry) {
                        $entry['type'] = 'template_id';
                        $entry->setVisible(['name', 'id', 'type']);
                        return $entry;
                    })
                    ->prepend(['name' => '(Empty)', 'id' => 'null']),
            ]
        ];
    }

    private function getLeaseVehicleSectionFilters(): array
    {
        return [
            [
                'value' => 'status',
                'name' => 'Status',
                'choices' => [
                    [
                        'id' => 'featured',
                        'name' => 'Featured',
                        'type' => 'status',
                    ],
                ],
            ],
            $this->make('leaseVehicles'),
            $this->model('leaseVehicles'),
            $this->bodyStyle('leaseVehicles'),
            $this->fuelType('leaseVehicles'),
            $this->transmission('leaseVehicles'),
        ];
    }

    private function enquiries(SearchRequest $request): Collection
    {
        return Enquiry::query()
            ->where('title', 'like', $request->getTerm())
            ->get();
    }

    private function vehicles(SearchRequest $request): Collection
    {
        return Vehicle::query()
            ->whereFullText('search_content', $request->getTerm())
            ->orWhere('vrm_condensed', $request->getTerm(false))
            ->orWhere('registration_number', $request->getTerm(false))
            ->get();
    }

    private function pages(SearchRequest $request): Collection
    {
        return Page::query()
            ->with('categories')
            ->whereFullText('search_content', $request->getTerm())
            ->orWhere('title', 'like', $request->getTerm())
            ->get();
    }

    private function newCars(SearchRequest $request): Collection
    {
        return NewCar::query()
            ->whereFullText('search_content', $request->getTerm())
            ->orWhere('name', 'like', $request->getTerm())
            ->get();
    }

    private function offers(SearchRequest $request): Collection
    {
        return VehicleOffer::query()
            ->whereFullText('search_content', $request->getTerm())
            ->orWhere('name', 'like', $request->getTerm())
            ->get();
    }

    private function globalContent(SearchRequest $request): Collection
    {
        return GlobalContent::query()
            ->where('name', 'like', $request->getTerm())
            ->get();
    }

    private function menus(SearchRequest $request): Collection
    {
        return Menu::query()
            ->where('title', 'like', $request->getTerm())
            ->get();
    }

    private function dealerships(SearchRequest $request): Collection
    {
        return Dealership::query()
            ->where('name', 'like', $request->getTerm())
            ->get();
    }

    private function form(SearchRequest $request): Collection
    {
        return Form::query()
            ->where('name', 'like', $request->getTerm())
            ->get();
    }

    private function price(): array
    {
        return [
            'value' => 'price',
            'name' => 'Price',
            'range' => true,
            'min' => null,
            'max' => null,
        ];
    }


    private function imageCount(): array
    {
        return [
            'value' => 'image_count',
            'name' => 'Image Count',
            'range' => true,
            'min' => null,
            'max' => null,
        ];
    }

    private function dealership(): array
    {
        return [
            'value' => 'dealership_id',
            'name' => 'Location',
            'choices' => Dealership::query()
                ->select(['name', 'id'])
                ->get()
                ->map(function ($entry) {
                    $entry['type'] = 'dealership_id';
                    $entry->setVisible(['name', 'id', 'type']);
                    return $entry;
                })
                ->prepend(['name' => '(Empty)', 'id' => 'null']),
        ];
    }

    private function franchise(): array
    {
        return [
            'value' => 'franchise_id',
            'name' => 'Franchise',
            'choices' => Franchise::query()
                ->select(['name', 'id'])
                ->get()
                ->map(function ($entry) {
                    $entry['type'] = 'franchise_id';
                    $entry->setVisible(['name', 'id', 'type']);
                    return $entry;
                })
                ->prepend(['name' => '(Empty)', 'id' => 'null']),
        ];
    }

    private function make(string $relationship): array
    {
        return [
            'value' => 'make_id',
            'name' => 'Make',
            'choices' => VehicleMake::query()
                ->whereHas($relationship, fn ($query) => $query->withTrashed())
                ->select(['name', 'id'])
                ->get()
                ->map(function ($entry) {
                    $entry['type'] = 'make_id';
                    $entry->setVisible(['name', 'id', 'type']);
                    return $entry;
                })
                ->prepend(['name' => '(Empty)', 'id' => 'null']),
        ];
    }

    private function model(string $relationship): array
    {
        return [
            'value' => 'model_id',
            'name' => 'Model',
            'choices' => VehicleModel::query()
                ->whereHas($relationship, fn ($query) => $query->withTrashed())
                ->select(['name', 'id'])
                ->get()
                ->map(function ($entry) {
                    $entry['type'] = 'model_id';
                    $entry->setVisible(['name', 'id', 'type']);
                    return $entry;
                })
                ->prepend(['name' => '(Empty)', 'id' => 'null']),
        ];
    }

    private function bodyStyle(string $relationship): array
    {
        return [
            'value' => 'body_style_id',
            'name' => 'Body Style/Type',
            'choices' => BodyStyleType::query()
                ->whereHas($relationship, fn ($query) => $query->withTrashed())
                ->select(['name', 'id'])
                ->get()
                ->map(function ($entry) {
                    $entry['type'] = 'body_style_id';
                    $entry->setVisible(['name', 'id', 'type']);
                    return $entry;
                })
                ->prepend(['name' => '(Empty)', 'id' => 'null']),
        ];
    }

    private function fuelType(string $relationship): array
    {
        return [
            'value' => 'fuel_type_id',
            'name' => 'Fuel Type',
            'choices' => FuelType::query()
                ->whereHas($relationship, fn ($query) => $query->withTrashed())
                ->select(['name', 'id'])
                ->get()
                ->map(function ($entry) {
                    $entry['type'] = 'fuel_type_id';
                    $entry->setVisible(['name', 'id', 'type']);
                    return $entry;
                })
                ->prepend(['name' => '(Empty)', 'id' => 'null']),
        ];
    }

    private function transmission(string $relationship): array
    {
        return [
            'value' => 'transmission_id',
            'name' => 'Transmission',
            'choices' => TransmissionType::query()
                ->whereHas($relationship, fn ($query) => $query->withTrashed())
                ->select(['name', 'id'])
                ->get()
                ->map(function ($entry) {
                    $entry['type'] = 'transmission_id';
                    $entry->setVisible(['name', 'id', 'type']);
                    return $entry;
                })
                ->prepend(['name' => '(Empty)', 'id' => 'null']),
        ];
    }

    private function vatApplicable(): array
    {
        return [
            'value' => 'is_vat_applicable',
            'name' => 'VAT Applicable',
            'choices' => [
                [
                    'id' => 'yes',
                    'name' => 'Yes',
                    'type' => 'is_vat_applicable',
                ],
                [
                    'id' => 'no',
                    'name' => 'No',
                    'type' => 'is_vat_applicable',
                ],
            ]
        ];
    }

    private function autoTraderStatus(): array
    {
        return [
            'value' => 'auto_trader_status',
            'name' => 'AutoTrader Status',
            'enabled' => Settings::get('sales-channels-auto-trader-enabled', false),
            'choices' => [
                [
                    'id' => 'advert_yes',
                    'name' => 'Advert Published',
                    'type' => 'auto_trader_status',
                ],
                [
                    'id' => 'advert_no',
                    'name' => 'Advert Not Published',
                    'type' => 'auto_trader_status',
                ],
                [
                    'id' => 'profile_yes',
                    'name' => 'Profile Published',
                    'type' => 'auto_trader_status',
                ],
                [
                    'id' => 'profile_no',
                    'name' => 'Profile Not Published',
                    'type' => 'auto_trader_status',
                ],
            ]
        ];
    }

    private function stockProvider(): array
    {
        $importMaps = ImportMap::query()
            ->where('type', 'vehicle')
            ->whereHas('fields')
            ->select(['id', 'name'])
            ->get()
            ->map(fn (ImportMap $map) => [
                'id' => 'import-map-' . $map->id,
                'name' => $map->name,
                'type' => 'stock_provider',
            ]);

        return [
            'value' => 'stock_provider',
            'name' => 'Stock Provider',
            'enabled' => $importMaps->isNotEmpty(),
            'choices' => $importMaps,
        ];
    }

    private function filterableVehicleAttributes(): array
    {
        return VehicleAttribute::query()
            ->where('admin_filterable', 1)
            ->where('model', 'vehicle')
            ->orderBy('order')
            ->get()
            ->map(function (VehicleAttribute $attribute) {
                $type = 'attribute:' . $attribute->slug;

                if ($attribute->type === 'boolean') {
                    return [
                        'value' => $type,
                        'name' => $attribute->name,
                        'choices' => [
                            ['id' => 'yes', 'name' => 'Yes', 'type' => $type],
                            ['id' => 'no', 'name' => 'No', 'type' => $type],
                        ],
                    ];
                }

                if (in_array($attribute->type, ['number', 'integer'])) {
                    return [
                        'value' => $type,
                        'name' => $attribute->name,
                        'range' => true,
                        'min' => null,
                        'max' => null,
                    ];
                }

                // Text-based: show distinct values as choices
                $values = VehicleAttributeValue::query()
                    ->where('attribute_id', $attribute->id)
                    ->where('owner_type', 'vehicle')
                    ->whereNotNull('value_text')
                    ->where('value_text', '!=', '')
                    ->select('value_text')
                    ->distinct()
                    ->orderBy('value_text')
                    ->pluck('value_text');

                return [
                    'value' => $type,
                    'name' => $attribute->name,
                    'choices' => $values->map(fn (string $value) => [
                        'id' => $value,
                        'name' => $value,
                        'type' => $type,
                    ])->values(),
                ];
            })
            ->toArray();
    }

    private function hasFinance(): array
    {
        return [
            'value' => 'has_finance',
            'name' => 'Has Finance',
            'choices' => [
                [
                    'id' => 'yes',
                    'name' => 'With Finance',
                    'type' => 'has_finance',
                ],
                [
                    'id' => 'no',
                    'name' => 'Without Finance',
                    'type' => 'has_finance',
                ],
            ]
        ];
    }
}
