<?php

declare(strict_types=1);

namespace App\Support\Navigation;

use Illuminate\Http\Request;
use Illuminate\Session\Store;
use Illuminate\Support\Arr;

final class WorkspaceHubFilterStateResetter
{
    /**
     * @return list<string>
     */
    public function environmentLikeFilterKeys(): array
    {
        return WorkspaceHubRegistry::environmentLikeFilterKeys();
    }

    public function shouldResetForCleanWorkspaceHubEntry(?Request $request = null): bool
    {
        return WorkspaceHubRegistry::isCleanWorkspaceHubEntry($request);
    }

    public function neutralizeEnvironmentLikeQueryState(?Request $request = null): void
    {
        $request ??= request();
        $hasCanonicalEnvironmentFilter = WorkspaceHubRegistry::requestHasEnvironmentFilterQuery($request);

        foreach (WorkspaceHubRegistry::forbiddenQueryKeys() as $queryKey) {
            if ($queryKey === 'environment_id' && $hasCanonicalEnvironmentFilter) {
                continue;
            }

            $request->query->remove($queryKey);
        }
    }

    /**
     * @param  array<string, mixed>|null  $persistedFilters
     * @return array<string, mixed>
     */
    public function forgetPersistedEnvironmentLikeFilters(
        string $filtersSessionKey,
        ?Request $request = null,
        ?array $persistedFilters = null,
    ): array {
        $session = $this->session($request);

        $persistedFilters ??= $session->get($filtersSessionKey, []);

        if (! is_array($persistedFilters)) {
            $persistedFilters = [];
        }

        $persistedFilters = $this->forgetEnvironmentLikeFilterPaths($persistedFilters);

        if ($persistedFilters === []) {
            $session->forget($filtersSessionKey);
        } else {
            $session->put($filtersSessionKey, $persistedFilters);
        }

        return $persistedFilters;
    }

    public function forgetPersistedEnvironmentLikeFiltersForCleanWorkspaceHubEntry(
        string $filtersSessionKey,
        ?Request $request = null,
    ): void {
        if (! $this->shouldResetForCleanWorkspaceHubEntry($request)) {
            return;
        }

        $this->forgetPersistedEnvironmentLikeFilters($filtersSessionKey, $request);
    }

    /**
     * @param  array<string, mixed>|null  $filters
     * @return array<string, mixed>
     */
    public function clearLivewireTableFilterState(?array $filters): array
    {
        if (! is_array($filters)) {
            return [];
        }

        foreach ($this->environmentLikeFilterKeys() as $filterName) {
            if (! array_key_exists($filterName, $filters)) {
                continue;
            }

            $filterState = $filters[$filterName];

            if (is_array($filterState)) {
                $filters[$filterName] = ['value' => null];

                continue;
            }

            Arr::forget($filters, $filterName);
        }

        return $this->forgetNestedEnvironmentLikeFilterState($filters);
    }

    /**
     * @param  array<string, mixed>  $parameters
     * @return array<string, mixed>
     */
    public function cleanParameters(array $parameters): array
    {
        return WorkspaceHubRegistry::cleanParameters($parameters);
    }

    public function cleanUrl(string $url): string
    {
        return WorkspaceHubRegistry::cleanUrl($url);
    }

    /**
     * @param  array<string, mixed>  $state
     * @return array<string, mixed>
     */
    private function forgetEnvironmentLikeFilterPaths(array $state): array
    {
        foreach ($this->environmentLikeFilterKeys() as $filterName) {
            Arr::forget($state, $filterName);
        }

        return $this->forgetNestedEnvironmentLikeFilterState($state);
    }

    /**
     * @param  array<string, mixed>  $state
     * @return array<string, mixed>
     */
    private function forgetNestedEnvironmentLikeFilterState(array $state): array
    {
        foreach ($this->environmentLikeFilterKeys() as $filterName) {
            Arr::forget($state, "tableFilters.{$filterName}");
            Arr::forget($state, "tableDeferredFilters.{$filterName}");
        }

        foreach (['tableFilters', 'tableDeferredFilters'] as $tableStateKey) {
            if (data_get($state, $tableStateKey) === []) {
                Arr::forget($state, $tableStateKey);
            }
        }

        return $state;
    }

    private function session(?Request $request = null): Store
    {
        return ($request && $request->hasSession()) ? $request->session() : app('session.store');
    }
}
