<?php

declare(strict_types=1);

namespace App\Support\Filament;

use App\Models\Tenant;
use App\Support\OperateHub\OperateHubShell;
use Illuminate\Http\Request;
use Illuminate\Session\Store;
use Illuminate\Support\Arr;

final class CanonicalAdminTenantFilterState
{
    private const STATE_PREFIX = 'filament.admin_tenant_filter_state';

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

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

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

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

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

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

        return (string) $persistedValue;
    }

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

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

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

        $activeTenant = $this->operateHubShell->activeEntitledTenant($request);
        $resolvedTenantId = $activeTenant instanceof Tenant ? (string) $activeTenant->getKey() : null;
        $stateKey = $this->stateKey($filtersSessionKey);
        $previousTenantId = $session->get($stateKey);

        if ($previousTenantId !== $resolvedTenantId) {
            foreach ($tenantSensitiveFilters as $filterName) {
                Arr::forget($persistedFilters, $filterName);
            }
        }

        if ($tenantFilterName !== null) {
            $tenantFilterValue = match ($tenantAttribute) {
                'external_id' => $activeTenant?->external_id,
                default => $resolvedTenantId,
            };

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

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

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

    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');
    }
}
