<?php

namespace App\Console\Commands;

use App\Facades\Feature;
use App\Facades\Settings;
use App\Facades\Site;
use Illuminate\Console\Command;
use Illuminate\Database\Eloquent\Builder;
use Mtc\MercuryDataModels\CarConfiguratorModel;
use Mtc\MercuryDataModels\Contracts\ModelWithUrlPath;
use Mtc\MercuryDataModels\Dealership;
use Mtc\MercuryDataModels\Franchise;
use Mtc\MercuryDataModels\NewCar;
use Mtc\MercuryDataModels\Page;
use Mtc\MercuryDataModels\Property;
use Mtc\MercuryDataModels\PropertyCategory;
use Mtc\MercuryDataModels\Vehicle;
use Mtc\MercuryDataModels\VehicleMake;
use Mtc\MercuryDataModels\VehicleModel;
use Mtc\MercuryDataModels\VehicleOffer;
use Spatie\Sitemap\Sitemap;
use Spatie\Sitemap\Tags\Url;

class MakeSitemap extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'make:sitemap';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Generate sitemap.xml for a site';

    private Sitemap $sitemap;

    /**
     * Execute the console command.
     */
    public function handle()
    {
        if (!Feature::isEnabled('sitemap')) {
            return self::SUCCESS;
        }

        $this->sitemap = Sitemap::create();
        Page::query()->active()->get()
            ->each(fn(Page $page) => $this->addToSitemap($page));

        if (Feature::isEnabled('new-vehicles')) {
            NewCar::query()->active()->get()->each(fn(NewCar $page) => $this->addToSitemap($page));

            VehicleOffer::query()->active()->get()
                ->each(fn(VehicleOffer $page) => $this->addToSitemap($page));
        }

        if (Feature::isEnabled('dealerships')) {
            Dealership::query()->where('active', 1)->get()->each(fn(Dealership $page) => $this->addToSitemap($page));
        }


        if (Settings::get('seo-sitemap-include-srp')) {
            match (Settings::get('seo-sitemap-srp-type')) {
                'fixed-path' => $this->fixedPathSrp(ltrim(Settings::get('seo-sitemap-srp-path'), '/')),
                'path-plus-franchise' => $this->franchisePlusPathSrp(ltrim(Settings::get('seo-sitemap-srp-path'), '/')),
                default => $this->conditionTypeSrp(),
            };
        }

        if (Settings::get('seo-sitemap-include-fpa')) {
            Vehicle::query()->active()->get()
                ->each(fn(Vehicle $page) => $this->addToSitemap($page));
        }

        if (Feature::isEnabled('car-configurator')) {
            CarConfiguratorModel::query()->where('active', 1)->get()
                ->each(fn(CarConfiguratorModel $page) => $this->addToSitemap($page));
        }

        collect(explode("\n", Settings::get('seo-sitemap-fixed-urls', '')))
            ->filter()
            ->each(fn($url) => $this->sitemap->add(
                Url::create(Site::url($url))
                    ->setPriority($this->calculatePriority($url))
            ));

        $this->addPropertyCategoryEntries();

        $this->sitemap->writeToDisk('file-storage', tenant('id') . '/sitemap.xml', true);
        return self::SUCCESS;
    }

    /**
     * Add property entries from categories that have sitemap enabled.
     */
    private function addPropertyCategoryEntries(): void
    {
        PropertyCategory::query()
            ->where('active', 1)
            ->get()
            ->filter(fn(PropertyCategory $category) => ($category->data['sitemap_enabled'] ?? false))
            ->each(function (PropertyCategory $category) {
                $basePath = ltrim($category->data['sitemap_base_path'] ?? $category->slug, '/');

                $category->properties()
                    ->where('active', 1)
                    ->get()
                    ->each(function (Property $property) use ($basePath) {
                        $path = '/' . $basePath . '/' . $property->slug;
                        $this->sitemap->add(
                            Url::create(Site::url($path))
                                ->setLastModificationDate($property->updated_at)
                                ->setPriority($this->calculatePriority($path))
                        );
                    });
            });
    }

    private function addToSitemap(ModelWithUrlPath $page): void
    {
        $path = $page->urlPath();
        $this->sitemap->add(
            Url::create(Site::url($path))
                ->setLastModificationDate($page->updated_at)
                ->setPriority($this->calculatePriority($path))
        );
    }

    /**
     * Calculate priority based on URL depth.
     * Homepage and first level pages get 1.0, each additional level reduces by 0.1
     * Minimum priority is 0.1
     */
    private function calculatePriority(string $path): float
    {
        $path = trim($path, '/');

        // Homepage
        if (empty($path) || $path === 'home') {
            return 1.0;
        }

        $depth = substr_count($path, '/') + 1;
        $priority = 1.0 - (($depth - 1) * 0.1);

        return max(0.1, $priority);
    }

    /**
     * SRP is a single fixed path - no differentiation between condition (new/used) or type (car/lcv),
     * no franchise specific urls
     */
    private function fixedPathSrp(string $srpPath, array $exclude_makes = [], ?int $only_make = null): void
    {
        if (empty($only_make)) {
            $this->sitemap->add(
                Url::create(Site::url($srpPath))
                    ->setChangeFrequency('daily')
                    ->setPriority($this->calculatePriority($srpPath))
            );
        }
        if (Settings::get('seo-sitemap-include-srp-makes')) {
            VehicleMake::query()
                ->when(!empty($exclude_makes), fn($query) => $query->whereNotIn('id', $exclude_makes))
                ->when($only_make, fn($query) => $query->where('id', $only_make))
                ->whereHas('vehicles', fn($query) => $query->active())->get()
                ->each(function (VehicleMake $make) use ($srpPath) {
                    $makePath = '/' . $srpPath . '/' . $make->slug;
                    $this->sitemap->add(
                        Url::create(Site::url($makePath))
                            ->setChangeFrequency('daily')
                            ->setPriority($this->calculatePriority($makePath))
                    );
                    if (Settings::get('seo-sitemap-include-srp-models')) {
                        VehicleModel::query()
                            ->where('make_id', $make->id)
                            ->whereHas('vehicles', fn($query) => $query->active())->get()
                            ->each(function (VehicleModel $model) use ($srpPath, $make) {
                                $modelPath = '/' . $srpPath . '/' . $make->slug . '/' . $model->slug;
                                $this->sitemap->add(
                                    Url::create(Site::url($modelPath))
                                        ->setChangeFrequency('daily')
                                        ->setPriority($this->calculatePriority($modelPath))
                                );
                            });
                    }
                });
        }
    }

    private function franchisePlusPathSrp(string $srpPath): void
    {
        $franchises = Franchise::query()->get();
        $this->fixedPathSrp($srpPath, $franchises->pluck('make_id')->toArray());
        $franchises->each(fn(Franchise $franchise) => $this->fixedPathSrp(
            $franchise->slug . '/' . $srpPath,
            [],
            $franchise->make_id
        ));
    }

    private function conditionTypeSrp(): void
    {
        $types = array_filter([
            'used-cars' => Vehicle::query()->active()->where('type', 'car')->used()->exists(),
            'used-vans' => Vehicle::query()->active()->where('type', 'lcv')->used()->exists(),
            'used-motorcycles' => Vehicle::query()->active()->where('type', 'motorcycle')->used()->exists(),
            'new-cars' => Vehicle::query()->active()->where('type', 'car')->new()->exists(),
            'new-vans' => Vehicle::query()->active()->where('type', 'lcv')->new()->exists(),
            'new-motorcycles' => Vehicle::query()->active()->where('type', 'motorcycle')->new()->exists(),
        ]);

        foreach ($types as $type => $has_records) {
            if ($type === 'new-cars' && Settings::get('seo-sitemap-new-cars-called-stock')) {
                $srpPath = 'new-stock';
            } else {
                $srpPath = $type;
            }
            $this->sitemap->add(
                Url::create(Site::url($srpPath))
                    ->setChangeFrequency('daily')
                    ->setPriority($this->calculatePriority($srpPath))
            );

            if (Settings::get('seo-sitemap-include-srp-makes')) {
                VehicleMake::query()
                    ->whereHas('vehicles', fn($query) => $this->setConditionQuery($type, $query->active()))->get()
                    ->each(function (VehicleMake $make) use ($srpPath, $type) {
                        $makePath = '/' . $srpPath . '/' . $make->slug;
                        $this->sitemap->add(
                            Url::create(Site::url($makePath))
                                ->setChangeFrequency('daily')
                                ->setPriority($this->calculatePriority($makePath))
                        );

                        if (Settings::get('seo-sitemap-include-srp-models')) {
                            VehicleModel::query()
                                ->where('make_id', $make->id)
                                ->whereHas('vehicles', fn($query) => $this->setConditionQuery($type, $query->active()))
                                ->get()
                                ->each(function (VehicleModel $model) use ($srpPath, $make) {
                                    $modelPath = '/' . $srpPath . '/' . $make->slug . '/' . $model->slug;
                                    $this->sitemap->add(
                                        Url::create(Site::url($modelPath))
                                            ->setChangeFrequency('daily')
                                            ->setPriority($this->calculatePriority($modelPath))
                                    );
                                });
                        }
                    });
            }
        }
    }

    private function setConditionQuery(string $type, Builder $query)
    {
        return match ($type) {
            'used-cars' => $query->where('type', 'car')->used(),
            'used-vans' => $query->where('type', 'lcv')->used(),
            'used-motorcycles' => $query->where('type', 'motorcycle')->used(),
            'new-cars' => $query->where('type', 'car')->new(),
            'new-vans' => $query->where('type', 'lcv')->new(),
            'new-motorcycles' => $query->where('type', 'motorcycle')->new(),
            default => throw new \Exception('Unrecognized condition type'),
        };
    }
}
