<?php
/**
 * Global variable reads from Bricks options.
 *
 * @package LolaCoreForBricks
 */

declare(strict_types=1);

namespace LolaCoreForBricks\Gateways;

use LolaCoreForBricks\Index\IndexReader;
use LolaCoreForBricks\Support\BricksMetaKeys;
use LolaCoreForBricks\Support\CoveragePayload;
use LolaCoreForBricks\Support\PaginatedList;

/**
 * Reads bricks_global_variables, categories, and color palette.
 */
class VariableGateway
{
    /**
     * @param array<string, mixed> $params
     * @return array<string, mixed>
     */
    public function getGlobalVariables(array $params): array
    {
        $category = isset($params['category']) ? (string) $params['category'] : '';
        $limit    = (int) ($params['limit'] ?? 50);
        $offset   = (int) ($params['offset'] ?? 0);

        $variables  = $this->normalizeVariables(get_option(BricksMetaKeys::OPTION_GLOBAL_VARIABLES, []));
        $categories = $this->categoryMap(get_option('bricks_global_variables_categories', []));

        $items = [];
        foreach ($variables as $variable) {
            if ($category !== '' && ($variable['category'] ?? '') !== $category) {
                continue;
            }

            $items[] = array_merge($variable, [
                'category_label' => $categories[$variable['category'] ?? ''] ?? '',
            ]);
        }

        $page = PaginatedList::slice($items, $limit, $offset);

        return [
            'variables'  => $page['items'],
            'categories' => $this->formatCategories($categories),
            'palette'    => $this->extractPalette($variables),
            'total'      => $page['total'],
            'truncated'  => $page['truncated'],
            'limit'      => $page['limit'],
            'offset'     => $page['offset'],
        ];
    }

    /**
     * @param array<string, mixed> $params
     * @return array<string, mixed>
     */
    public function getVariableUsage(array $params): array
    {
        $variable = trim((string) ($params['variable'] ?? ''));
        $limit    = (int) ($params['limit'] ?? 50);
        $offset   = (int) ($params['offset'] ?? 0);

        if ($variable === '') {
            return ['error' => 'missing_variable'];
        }

        $variable = ltrim($variable, '-');
        $edges    = (new IndexReader())->usageOf(BricksMetaKeys::REF_VARIABLE, $variable);
        $grouped  = $this->groupUsageByKind($edges);
        $page     = PaginatedList::slice($grouped['items'], $limit, $offset);

        return [
            'variable'   => $variable,
            'references' => $page['items'],
            'summary'    => $grouped['summary'],
            'total'      => $page['total'],
            'truncated'  => $page['truncated'],
            'limit'      => $page['limit'],
            'offset'     => $page['offset'],
            'coverage'   => CoveragePayload::forResponse(),
        ];
    }

    /**
     * @param mixed $raw
     * @return array<int, array<string, mixed>>
     */
    private function normalizeVariables(mixed $raw): array
    {
        if (!is_array($raw)) {
            return [];
        }

        $items = [];
        foreach ($raw as $variable) {
            if (!is_array($variable)) {
                continue;
            }

            $name = (string) ($variable['name'] ?? $variable['id'] ?? '');
            if ($name === '') {
                continue;
            }

            $items[] = [
                'name'     => $name,
                'value'    => (string) ($variable['value'] ?? ''),
                'type'     => (string) ($variable['type'] ?? 'custom'),
                'category' => (string) ($variable['category'] ?? ''),
            ];
        }

        return $items;
    }

    /**
     * @param array<int, array<string, mixed>> $variables
     * @return array<int, array<string, string>>
     */
    private function extractPalette(array $variables): array
    {
        $palette = [];
        foreach ($variables as $variable) {
            if (($variable['type'] ?? '') !== 'color') {
                continue;
            }

            $palette[] = [
                'name'  => (string) $variable['name'],
                'value' => (string) $variable['value'],
            ];
        }

        return $palette;
    }

    /**
     * @param array<int, array<string, mixed>> $edges
     * @return array{items: array<int, array<string, mixed>>, summary: array<string, int>}
     */
    private function groupUsageByKind(array $edges): array
    {
        $summary = [
            'elements'     => 0,
            'classes'      => 0,
            'theme_styles' => 0,
            'other'        => 0,
        ];

        $items = [];
        foreach ($edges as $edge) {
            $area = (string) ($edge['area'] ?? '');
            $kind = match ($area) {
                BricksMetaKeys::AREA_CLASS_SETTINGS => 'classes',
                BricksMetaKeys::AREA_THEME_STYLE    => 'theme_styles',
                BricksMetaKeys::AREA_CONTENT,
                BricksMetaKeys::AREA_HEADER,
                BricksMetaKeys::AREA_FOOTER,
                BricksMetaKeys::AREA_GLOBAL_ELEMENT => 'elements',
                default                             => 'other',
            };

            ++$summary[$kind];

            $postId = (int) ($edge['post_id'] ?? 0);
            $items[] = [
                'kind'         => $kind,
                'post_id'      => $postId,
                'post_title'   => $postId > 0 ? (string) get_the_title($postId) : 'globals',
                'area'         => $area,
                'element_id'   => $edge['element_id'] ?? null,
                'element_name' => $edge['element_name'] ?? null,
            ];
        }

        return ['items' => $items, 'summary' => $summary];
    }

    /**
     * @param mixed $raw
     * @return array<string, string>
     */
    private function categoryMap(mixed $raw): array
    {
        if (!is_array($raw)) {
            return [];
        }

        $map = [];
        foreach ($raw as $category) {
            if (!is_array($category) || empty($category['id'])) {
                continue;
            }

            $map[(string) $category['id']] = (string) ($category['name'] ?? $category['id']);
        }

        return $map;
    }

    /**
     * @param array<string, string> $categories
     * @return array<int, array<string, string>>
     */
    private function formatCategories(array $categories): array
    {
        $items = [];
        foreach ($categories as $id => $name) {
            $items[] = ['id' => $id, 'name' => $name];
        }

        return $items;
    }
}
