<?php

declare(strict_types=1);

namespace PpPhp\Core\Designer\Contract;

final class DesignerStateNormalizer
{
    public function normalize(array $state): array
    {
        $state = array_replace_recursive(DesignerJsonSchema::defaultState(), $state);

        $state['version'] = (string) ($state['version'] ?? DesignerJsonSchema::VERSION);
        $state['active'] = $this->normalizeActive((array) ($state['active'] ?? []));
        $state['pages'] = $this->normalizePages((array) ($state['pages'] ?? []));
        $state['common'] = $this->normalizeCommon((array) ($state['common'] ?? []));
        $state['resources'] = $this->normalizeResources((array) ($state['resources'] ?? []));
        $state['theme'] = array_replace_recursive(['name' => 'default', 'mode' => 'light'], (array) ($state['theme'] ?? []));
        $state['settings'] = array_replace_recursive(['locked' => false, 'customCss' => '', 'customJs' => ''], (array) ($state['settings'] ?? []));
        $state['selection'] = $this->normalizeSelection((array) ($state['selection'] ?? []));
        $state['updatedAt'] = (string) ($state['updatedAt'] ?? date('c'));
        $state['updatedBy'] = (string) ($state['updatedBy'] ?? 'system');

        return $state;
    }

    public function ensurePage(array $state, string $table, string $pageType = 'list', string $pageName = ''): array
    {
        $state = $this->normalize($state);
        $pageName = $pageName !== '' ? $pageName : $pageType;

        if (!isset($state['pages'][$table])) {
            $state['pages'][$table] = [];
        }

        if (!isset($state['pages'][$table][$pageType])) {
            $state['pages'][$table][$pageType] = [
                'defaultPage' => $pageName,
                'pages' => [],
            ];
        }

        if (!isset($state['pages'][$table][$pageType]['pages'][$pageName])) {
            $state['pages'][$table][$pageType]['pages'][$pageName] = DesignerJsonSchema::defaultPage($table, $pageType, $pageName);
        }

        return $state;
    }

    public function normalizePage(array $page, string $table = '', string $pageType = 'list', string $pageName = ''): array
    {
        $pageName = $pageName !== '' ? $pageName : (string) ($page['name'] ?? $pageType);
        $page = array_replace_recursive(DesignerJsonSchema::defaultPage($table, $pageType, $pageName), $page);

        $page['components'] = array_values(array_map(
            fn (array $component): array => $this->normalizeComponent($component),
            array_filter((array) ($page['components'] ?? []), 'is_array')
        ));

        $page['resources'] = $this->normalizeResources((array) ($page['resources'] ?? []));

        return $page;
    }

    public function normalizeComponent(array $component): array
    {
        $id = (string) ($component['id'] ?? $component['name'] ?? $component['type'] ?? 'component');
        $type = (string) ($component['type'] ?? 'component');
        $label = (string) ($component['label'] ?? $component['name'] ?? $type);

        $component = array_replace_recursive(DesignerJsonSchema::defaultComponent($id, $type, $label), $component);
        $component['id'] = DesignerJsonSchema::safeId((string) $component['id']);
        $component['name'] = (string) ($component['name'] ?? $component['id']);

        if (isset($component['props']['cells']) && is_array($component['props']['cells'])) {
            foreach ($component['props']['cells'] as $cellIndex => $cell) {
                if (!is_array($cell)) {
                    continue;
                }

                $cell['id'] = DesignerJsonSchema::safeId((string) ($cell['id'] ?? 'cell_' . $cellIndex));
                $cell['components'] = array_values(array_map(
                    fn (array $child): array => $this->normalizeComponent($child),
                    array_filter((array) ($cell['components'] ?? []), 'is_array')
                ));
                $component['props']['cells'][$cellIndex] = $cell;
            }
        }

        if (isset($component['children']) && is_array($component['children'])) {
            $component['children'] = array_values(array_map(
                fn (array $child): array => $this->normalizeComponent($child),
                array_filter($component['children'], 'is_array')
            ));
        }

        return $component;
    }

    private function normalizeActive(array $active): array
    {
        return array_replace([
            'scope' => 'table',
            'table' => '',
            'pageType' => 'list',
            'pageName' => 'list',
        ], $active);
    }

    private function normalizePages(array $pages): array
    {
        foreach ($pages as $table => $pageTypes) {
            if (!is_array($pageTypes)) {
                unset($pages[$table]);
                continue;
            }

            foreach ($pageTypes as $pageType => $bucket) {
                if (!is_array($bucket)) {
                    unset($pages[$table][$pageType]);
                    continue;
                }

                $bucket['defaultPage'] = (string) ($bucket['defaultPage'] ?? $pageType);
                $bucket['pages'] = (array) ($bucket['pages'] ?? []);

                foreach ($bucket['pages'] as $pageName => $page) {
                    if (!is_array($page)) {
                        unset($bucket['pages'][$pageName]);
                        continue;
                    }

                    $bucket['pages'][$pageName] = $this->normalizePage($page, (string) $table, (string) $pageType, (string) $pageName);
                }

                $pages[$table][$pageType] = $bucket;
            }
        }

        return $pages;
    }

    private function normalizeCommon(array $common): array
    {
        foreach ($common as $pageName => $page) {
            if (!is_array($page)) {
                unset($common[$pageName]);
                continue;
            }

            $common[$pageName] = $this->normalizePage($page, '', (string) $pageName, (string) $pageName);
        }

        return $common;
    }

    private function normalizeResources(array $resources): array
    {
        return array_replace_recursive([
            'icons' => [],
            'css' => [],
            'js' => [],
            'fonts' => [],
            'images' => [],
        ], $resources);
    }

    private function normalizeSelection(array $selection): array
    {
        return array_replace_recursive(DesignerJsonSchema::emptySelection(), $selection);
    }
}
