<?php

declare(strict_types=1);

namespace App\Support\Filament;

use App\Models\ManagedEnvironment;
use App\Support\Navigation\WorkspaceHubFilterStateResetter;
use App\Support\Navigation\WorkspaceHubRegistry;
use App\Support\OperateHub\OperateHubShell;
use Illuminate\Http\Request;
use Illuminate\Session\Store;
use Illuminate\Support\Arr;

final class CanonicalAdminEnvironmentFilterState
{
    private const STATE_PREFIX = 'filament.admin_environment_filter_state';

    public function __construct(
        private readonly OperateHubShell $operateHubShell,
        private readonly WorkspaceHubFilterStateResetter $workspaceHubFilterStateResetter,
    ) {}

    public function currentFilterValue(
        string $filtersSessionKey,
        ?array $tableFilters = null,
        ?Request $request = null,
        ?string $environmentFilterName = 'managed_environment_id',
    ): ?string {
        if ($environmentFilterName === null) {
            return null;
        }

        $tableFilterValue = data_get($tableFilters ?? [], "{$environmentFilterName}.value");

        if (is_scalar($tableFilterValue) && (string) $tableFilterValue !== '') {
            return (string) $tableFilterValue;
        }

        $persistedFilters = $this->session($request)->get($filtersSessionKey, []);
        $persistedValue = data_get(is_array($persistedFilters) ? $persistedFilters : [], "{$environmentFilterName}.value");

        if (! is_scalar($persistedValue) || (string) $persistedValue === '') {
            return null;
        }

        return (string) $persistedValue;
    }

    /**
     * @param  array<int, string>  $environmentSensitiveFilters
     */
    public function sync(
        string $filtersSessionKey,
        array $environmentSensitiveFilters = [],
        ?Request $request = null,
        ?string $environmentFilterName = 'managed_environment_id',
        string $environmentAttribute = 'id',
    ): void {
        $session = $this->session($request);

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

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

        if (WorkspaceHubRegistry::isCleanWorkspaceHubEntry($request)) {
            $persistedFilters = $this->forgetEnvironmentLikeFilters(
                $filtersSessionKey,
                $request,
                $persistedFilters,
            );
        }

        $activeEnvironment = $this->operateHubShell->activeEntitledTenant($request);
        $resolvedEnvironmentId = $activeEnvironment instanceof ManagedEnvironment ? (string) $activeEnvironment->getKey() : null;
        $stateKey = $this->stateKey($filtersSessionKey);
        $previousEnvironmentId = $session->get($stateKey);

        if ($previousEnvironmentId !== $resolvedEnvironmentId) {
            foreach ($environmentSensitiveFilters as $filterName) {
                Arr::forget($persistedFilters, $filterName);
            }
        }

        if ($environmentFilterName !== null) {
            $environmentFilterValue = match ($environmentAttribute) {
                'external_id' => $activeEnvironment?->external_id,
                default => $resolvedEnvironmentId,
            };

            if ($environmentFilterValue !== null) {
                data_set($persistedFilters, "{$environmentFilterName}.value", $environmentFilterValue);
            } else {
                Arr::forget($persistedFilters, $environmentFilterName);
            }
        }

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

        $session->put($stateKey, $resolvedEnvironmentId);
    }

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

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

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

        $persistedFilters = $this->workspaceHubFilterStateResetter
            ->forgetPersistedEnvironmentLikeFilters($filtersSessionKey, $request, $persistedFilters);

        $session->forget($this->stateKey($filtersSessionKey));

        return $persistedFilters;
    }

    public function forgetEnvironmentLikeFiltersForCleanWorkspaceHubEntry(
        string $filtersSessionKey,
        ?Request $request = null,
    ): void {
        if (! WorkspaceHubRegistry::isCleanWorkspaceHubEntry($request)) {
            return;
        }

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

    private function stateKey(string $filtersSessionKey): string
    {
        return self::STATE_PREFIX.'.'.md5($filtersSessionKey);
    }

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