<?php
/**
 * Governance diagnostic handlers for Bricks design-system cleanup.
 *
 * @package LolaCoreForBricks
 */

declare(strict_types=1);

namespace LolaCoreForBricks\Handlers;

use LolaCoreForBricks\BricksEnv;
use LolaCoreForBricks\Governance\ClassSimilarity;
use LolaCoreForBricks\Governance\DeadCodeFinder;
use LolaCoreForBricks\Governance\GovernanceResponse;
use LolaCoreForBricks\Governance\ThemeStyleConflicts;
use LolaCoreForBricks\Support\BricksMetaKeys;
use LolaCoreForBricks\Support\PaginatedList;

/**
 * Executes B3 governance read abilities.
 */
class GovernanceHandler
{
    public function __construct(
        private readonly ?DeadCodeFinder $deadCodeFinder = null,
        private readonly ?ClassSimilarity $classSimilarity = null,
        private readonly ?ThemeStyleConflicts $themeStyleConflicts = null
    ) {
    }

    /**
     * @param array<string, mixed> $params
     * @return array<string, mixed>
     */
    public function findUnusedClasses(array $params = []): array
    {
        $guard = $this->environmentGuard();
        if ($guard !== null) {
            return $guard;
        }

        $data = ($this->deadCodeFinder ?? new DeadCodeFinder())->findUnusedClasses($params);

        return $this->wrap('Unused class scan is ready.', GovernanceResponse::withCoverage($data));
    }

    /**
     * @param array<string, mixed> $params
     * @return array<string, mixed>
     */
    public function findDuplicateClasses(array $params = []): array
    {
        $guard = $this->environmentGuard();
        if ($guard !== null) {
            return $guard;
        }

        $threshold = isset($params['threshold']) ? (float) $params['threshold'] : ClassSimilarity::DEFAULT_THRESHOLD;
        $limit     = (int) ($params['limit'] ?? 50);
        $offset    = (int) ($params['offset'] ?? 0);

        $classes = $this->loadActiveClasses();
        $groups  = ($this->classSimilarity ?? new ClassSimilarity())->findDuplicateGroups($classes, $threshold);
        $page    = PaginatedList::slice($groups, $limit, $offset);

        return $this->wrap(
            'Duplicate class scan is ready.',
            GovernanceResponse::withCoverage([
                'threshold'         => $threshold,
                'duplicate_groups'  => $page['items'],
                'total'             => $page['total'],
                'truncated'         => $page['truncated'],
                'limit'             => $page['limit'],
                'offset'            => $page['offset'],
            ])
        );
    }

    /**
     * @param array<string, mixed> $params
     * @return array<string, mixed>
     */
    public function findUnusedVariables(array $params = []): array
    {
        $guard = $this->environmentGuard();
        if ($guard !== null) {
            return $guard;
        }

        $data = ($this->deadCodeFinder ?? new DeadCodeFinder())->findUnusedVariables($params);

        return $this->wrap('Unused variable scan is ready.', GovernanceResponse::withCoverage($data));
    }

    /**
     * @param array<string, mixed> $params
     * @return array<string, mixed>
     */
    public function findOrphanComponents(array $params = []): array
    {
        $guard = $this->environmentGuard();
        if ($guard !== null) {
            return $guard;
        }

        $data = ($this->deadCodeFinder ?? new DeadCodeFinder())->findOrphanComponents($params);

        return $this->wrap('Orphan component scan is ready.', GovernanceResponse::withCoverage($data));
    }

    /**
     * @param array<string, mixed> $params
     * @return array<string, mixed>
     */
    public function findThemeStyleConflicts(array $params = []): array
    {
        $guard = $this->environmentGuard();
        if ($guard !== null) {
            return $guard;
        }

        $data = ($this->themeStyleConflicts ?? new ThemeStyleConflicts())->findConflicts($params);

        return $this->wrap('Theme style conflict scan is ready.', GovernanceResponse::withCoverage($data));
    }

    /**
     * @return array<int, array<string, mixed>>
     */
    private function loadActiveClasses(): array
    {
        $raw = get_option(BricksMetaKeys::OPTION_GLOBAL_CLASSES, []);
        if (!is_array($raw)) {
            return [];
        }

        $classes = [];
        foreach ($raw as $class) {
            if (is_array($class) && !empty($class['id'])) {
                $classes[] = $class;
            }
        }

        return $classes;
    }

    /**
     * @param array<string, mixed> $data
     * @return array<string, mixed>
     */
    private function wrap(string $message, array $data): array
    {
        return array_merge(
            [
                'success' => true,
                'message' => $message,
            ],
            $data
        );
    }

    /**
     * @return array<string, mixed>|null
     */
    private function environmentGuard(): ?array
    {
        if (!BricksEnv::userCanReadDesignSystem()) {
            return [
                'success' => false,
                'message' => 'I need administrator access to run Bricks governance diagnostics.',
            ];
        }

        if (!BricksEnv::isAvailable() || !BricksEnv::meetsFloor()) {
            return [
                'success' => false,
                'message' => 'Bricks is not available on this site yet. Activate Bricks '
                    . BricksEnv::FLOOR_VERSION . ' or newer, then try again.',
            ];
        }

        return null;
    }
}
