<?php

// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedNamespaceFound -- APD is the established namespace shared with the Pro add-on and retained for backward compatibility.
namespace APD\Theme;

use APD\PostTypes\ThemePostType;

defined('ABSPATH') || exit;

final class DesignerTheme
{
    public const DRAFT_OPTION = 'apd_designer_theme_draft';
    public const PUBLISHED_OPTION = 'apd_designer_theme_published';
    public const LIBRARY_OPTION = 'apd_designer_theme_library';
    public const DRAFTS_OPTION = 'apd_designer_theme_drafts';
    public const STORAGE_VERSION_OPTION = 'apd_designer_theme_storage_version';
    public const POST_META = '_apd_designer_theme_payload';
    public const LEGACY_ID_META = '_apd_designer_theme_legacy_id';
    public const FALLBACK_THEME_ID = '0';
    public const VERSION = 1;
    public const STORAGE_VERSION = 2;

    private ?array $usageCounts = null;

    public function library() : array
    {
        $themes = [];
        foreach ($this->themePosts(['publish']) as $post) {
            $themeId = (string) $post->ID;
            $themes[$themeId] = array_merge(['id' => $themeId], $this->payloadForPost($post));
        }

        if ($themes === []) {
            $themeId = $this->ensureDefaultThemePost();
            if ($themeId > 0) {
                $post = get_post($themeId);
                if ($post instanceof \WP_Post) {
                    $themes[(string) $themeId] = array_merge(
                        ['id' => (string) $themeId],
                        $this->payloadForPost($post)
                    );
                }
            }
        }

        if ($themes === []) {
            $themes[self::FALLBACK_THEME_ID] = array_merge(
                ['id' => self::FALLBACK_THEME_ID],
                $this->defaultPayload()
            );
        }

        return $themes;
    }

    public function choices() : array
    {
        $defaultThemeId = $this->defaultThemeId();
        return array_map(static function (array $theme) use ($defaultThemeId) : array {
            $themeId = (string) ($theme['id'] ?? '');
            return [
                'id' => $themeId,
                'name' => (string) ($theme['name'] ?? ''),
                'preset' => (string) ($theme['preset'] ?? 'light'),
                'colors' => (array) ($theme['colors'] ?? []),
                'isDefault' => $themeId === $defaultThemeId,
                'editUrl' => $themeId !== self::FALLBACK_THEME_ID
                    ? (string) get_edit_post_link((int) $themeId, '')
                    : '',
            ];
        }, $this->library());
    }

    public function defaultThemeId() : string
    {
        $themes = $this->library();
        $settings = (array) get_option('apd_settings', []);
        $themeId = $this->sanitizeThemeId($settings['default_designer_theme_id'] ?? '');
        return isset($themes[$themeId]) ? $themeId : (string) array_key_first($themes);
    }

    public function hasTheme(string $themeId) : bool
    {
        $themeId = $this->sanitizeThemeId($themeId);
        return $themeId !== ''
            && get_post_type((int) $themeId) === ThemePostType::TYPE
            && get_post_status((int) $themeId) === 'publish';
    }

    public function draft(?string $themeId = null) : array
    {
        $themeId = $this->resolveThemeId($themeId, true);
        $post = get_post((int) $themeId);
        return $post instanceof \WP_Post ? $this->payloadForPost($post) : $this->defaultPayload();
    }

    public function published(?string $themeId = null) : array
    {
        $themeId = $this->resolveThemeId($themeId);
        $post = get_post((int) $themeId);
        if ($post instanceof \WP_Post && $post->post_type === ThemePostType::TYPE) {
            return $this->payloadForPost($post);
        }

        $themes = $this->library();
        $theme = reset($themes);
        return $this->normalizeStored(is_array($theme) ? $theme : []);
    }

    public function saveDraft(array $payload, ?string $themeId = null) : array
    {
        $themeId = $this->resolveThemeId($themeId, true);
        return $this->savePostPayload((int) $themeId, $payload);
    }

    public function publish(array $payload, ?string $themeId = null) : array
    {
        $themeId = $this->resolveThemeId($themeId, true);
        $theme = $this->savePostPayload((int) $themeId, $payload);
        wp_update_post(['ID' => (int) $themeId, 'post_status' => 'publish']);
        return $theme;
    }

    public function create(string $name, string $preset = 'light') : string
    {
        $presets = self::presets();
        $preset = sanitize_key($preset);
        if (! isset($presets[$preset])) {
            $preset = 'light';
        }

        $theme = $this->normalizeSubmitted([
            'name' => $name,
            'preset' => $preset,
            'colors' => $presets[$preset]['colors'],
        ]);
        $postId = wp_insert_post([
            'post_type' => ThemePostType::TYPE,
            'post_status' => 'publish',
            'post_title' => $theme['name'],
        ]);
        if (is_wp_error($postId) || (int) $postId <= 0) {
            return self::FALLBACK_THEME_ID;
        }
        update_post_meta((int) $postId, self::POST_META, $theme);
        return (string) $postId;
    }

    public function duplicate(string $themeId) : string
    {
        $source = $this->published($themeId);
        $copyName = sprintf(/* translators: Placeholder values are populated from the current Asuka Designer record. */ __('%s copy', 'asuka-product-designer'), (string) $source['name']);
        $copy = $this->normalizeSubmitted(array_merge($source, ['name' => $copyName]));
        $postId = wp_insert_post([
            'post_type' => ThemePostType::TYPE,
            'post_status' => 'publish',
            'post_title' => $copyName,
        ]);
        if (is_wp_error($postId) || (int) $postId <= 0) {
            return self::FALLBACK_THEME_ID;
        }
        update_post_meta((int) $postId, self::POST_META, $copy);
        return (string) $postId;
    }

    public function delete(string $themeId) : bool
    {
        $themeId = $this->sanitizeThemeId($themeId);
        $themes = $this->library();
        if (
            ! isset($themes[$themeId])
            || count($themes) <= 1
            || $themeId === $this->defaultThemeId()
            || $this->usageCount($themeId) > 0
        ) {
            return false;
        }
        return (bool) wp_delete_post((int) $themeId, true);
    }

    public function savePostPayload(int $postId, array $payload) : array
    {
        if ($postId <= 0 || get_post_type($postId) !== ThemePostType::TYPE) {
            return $this->defaultPayload();
        }

        $title = trim((string) get_the_title($postId));
        if ($title !== '') {
            $payload['name'] = $title;
        }
        $theme = $this->normalizeSubmitted($payload);
        update_post_meta($postId, self::POST_META, $theme);
        return $theme;
    }

    public function migrateLegacyStorage() : void
    {
        if ((int) get_option(self::STORAGE_VERSION_OPTION, 0) >= self::STORAGE_VERSION) {
            return;
        }

        $existing = $this->themePosts(['publish', 'draft', 'private', 'pending', 'future']);
        $legacyLibrary = get_option(self::LIBRARY_OPTION, []);
        if (! is_array($legacyLibrary) || $legacyLibrary === []) {
            $legacyPublished = get_option(self::PUBLISHED_OPTION, null);
            $legacyLibrary = [
                'store-theme' => is_array($legacyPublished)
                    ? $legacyPublished
                    : $this->defaultPayload(),
            ];
        }

        $legacyMap = [];
        if ($existing === []) {
            foreach ($legacyLibrary as $legacyId => $payload) {
                if (! is_array($payload)) {
                    continue;
                }
                $theme = $this->normalizeStored($payload);
                $postId = wp_insert_post([
                    'post_type' => ThemePostType::TYPE,
                    'post_status' => 'publish',
                    'post_title' => $theme['name'],
                ]);
                if (is_wp_error($postId) || (int) $postId <= 0) {
                    continue;
                }
                update_post_meta((int) $postId, self::POST_META, $theme);
                update_post_meta((int) $postId, self::LEGACY_ID_META, sanitize_key((string) $legacyId));
                $legacyMap[sanitize_key((string) $legacyId)] = (string) $postId;
            }
        } else {
            foreach ($existing as $post) {
                $legacyId = sanitize_key((string) get_post_meta($post->ID, self::LEGACY_ID_META, true));
                if ($legacyId === '') {
                    foreach ($legacyLibrary as $candidateId => $candidatePayload) {
                        if (
                            is_array($candidatePayload)
                            && $this->sanitizeName($candidatePayload['name'] ?? '') === $this->sanitizeName($post->post_title)
                        ) {
                            $legacyId = sanitize_key((string) $candidateId);
                            break;
                        }
                    }
                }
                if ($legacyId === '' && count($existing) === 1 && count($legacyLibrary) === 1) {
                    $legacyId = sanitize_key((string) array_key_first($legacyLibrary));
                }

                if ($legacyId !== '') {
                    $legacyMap[$legacyId] = (string) $post->ID;
                    update_post_meta($post->ID, self::LEGACY_ID_META, $legacyId);
                }

                $stored = get_post_meta($post->ID, self::POST_META, true);
                if (is_string($stored)) {
                    $stored = json_decode($stored, true);
                }
                if (! is_array($stored) || $stored === []) {
                    $payload = $legacyId !== '' && is_array($legacyLibrary[$legacyId] ?? null)
                        ? $legacyLibrary[$legacyId]
                        : $this->defaultPayload();
                    $theme = $this->normalizeStored($payload);
                    if (trim($post->post_title) !== '') {
                        $theme['name'] = $post->post_title;
                    }
                    update_post_meta($post->ID, self::POST_META, $theme);
                }
            }
        }

        $settings = (array) get_option('apd_settings', []);
        $oldDefault = sanitize_key((string) ($settings['default_designer_theme_id'] ?? 'store-theme'));
        if (isset($legacyMap[$oldDefault])) {
            $settings['default_designer_theme_id'] = $legacyMap[$oldDefault];
        } else {
            $first = $this->themePosts(['publish']);
            if ($first !== []) {
                $settings['default_designer_theme_id'] = (string) $first[0]->ID;
            }
        }
        update_option('apd_settings', $settings, false);

        if ($legacyMap !== []) {
            foreach (get_posts([
                'post_type' => ['apd_product_config', 'apd_template'],
                'post_status' => 'any',
                'posts_per_page' => -1,
                'fields' => 'ids',
                'meta_key' => '_apd_theme', // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key -- One-time migration must discover legacy theme assignments.
                'meta_compare' => 'EXISTS',
                'no_found_rows' => true,
            ]) as $postId) {
                $payload = json_decode((string) get_post_meta((int) $postId, '_apd_theme', true), true);
                $legacyId = is_array($payload) ? sanitize_key((string) ($payload['themeId'] ?? '')) : '';
                if ($legacyId === '' || ! isset($legacyMap[$legacyId])) {
                    continue;
                }
                $payload['themeId'] = $legacyMap[$legacyId];
                update_post_meta((int) $postId, '_apd_theme', wp_slash((string) wp_json_encode($payload)));
            }
        }

        update_option(self::STORAGE_VERSION_OPTION, self::STORAGE_VERSION, false);
    }

    public function usageCount(string $themeId) : int
    {
        $themeId = $this->sanitizeThemeId($themeId);
        if ($themeId === '') {
            return 0;
        }

        if ($this->usageCounts === null) {
            $this->usageCounts = [];
            $ids = get_posts([
                'post_type' => ['apd_product_config', 'apd_template'],
                'post_status' => 'any',
                'posts_per_page' => -1,
                'fields' => 'ids',
                'meta_key' => '_apd_theme', // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key -- Usage counts are memoized for the request after this assignment scan.
                'meta_compare' => 'EXISTS',
                'no_found_rows' => true,
            ]);
            foreach ($ids as $postId) {
                $payload = json_decode((string) get_post_meta((int) $postId, '_apd_theme', true), true);
                $assignedThemeId = is_array($payload) ? $this->sanitizeThemeId($payload['themeId'] ?? '') : '';
                if ($assignedThemeId !== '') {
                    $this->usageCounts[$assignedThemeId] = ($this->usageCounts[$assignedThemeId] ?? 0) + 1;
                }
            }
        }
        return (int) ($this->usageCounts[$themeId] ?? 0);
    }

    public function runtimeTheme(?array $theme = null) : array
    {
        $theme = $theme === null ? $this->published() : $this->normalizeStored($theme);

        return [
            'preset' => (string) $theme['preset'],
            'colors' => (array) $theme['colors'],
        ];
    }

    /**
     * A product/template with an explicit preset owns its whole theme. A local
     * color-only payload extends the globally published theme instead.
     */
    public function resolveRuntimeTheme(array $localTheme) : array
    {
        $referencedThemeId = $this->sanitizeThemeId($localTheme['themeId'] ?? '');
        $global = $referencedThemeId !== '' && $this->hasTheme($referencedThemeId)
            ? $this->runtimeTheme($this->published($referencedThemeId))
            : $this->runtimeTheme();
        $localPreset = sanitize_key((string) ($localTheme['preset'] ?? ''));
        $localColors = $this->sanitizePartialColors($localTheme['colors'] ?? []);

        if (array_key_exists($localPreset, self::presets())) {
            return [
                'preset' => $localPreset,
                'colors' => $localColors,
            ];
        }

        if ($localColors !== []) {
            $global['colors'] = array_replace((array) $global['colors'], $localColors);
        }

        return $global;
    }

    public static function sections() : array
    {
        return [
            'workspace' => [
                'label' => __('Workspace', 'asuka-product-designer'),
                'description' => __('Shell, navigation, panels, canvas, and overlays.', 'asuka-product-designer'),
                'icon' => 'layout',
            ],
            'content' => [
                'label' => __('Content', 'asuka-product-designer'),
                'description' => __('Thumbnails, text hierarchy, and structural borders.', 'asuka-product-designer'),
                'icon' => 'editor-textcolor',
            ],
            'brand' => [
                'label' => __('Brand and states', 'asuka-product-designer'),
                'description' => __('Primary identity and semantic feedback colors.', 'asuka-product-designer'),
                'icon' => 'art',
            ],
            'controls' => [
                'label' => __('Controls', 'asuka-product-designer'),
                'description' => __('Buttons, fields, and compact icon actions.', 'asuka-product-designer'),
                'icon' => 'admin-settings',
            ],
        ];
    }

    public static function tokens() : array
    {
        return [
            'layout.appBg' => self::token('workspace', 'Foundation', __('Application background', 'asuka-product-designer'), __('Outer workspace surrounding the designer.', 'asuka-product-designer')),
            'layout.shellBg' => self::token('workspace', 'Foundation', __('Designer shell', 'asuka-product-designer'), __('Main designer frame and structural surface.', 'asuka-product-designer')),
            'layout.sidebarBg' => self::token('workspace', 'Navigation', __('Sidebar background', 'asuka-product-designer'), __('Persistent module navigation surface.', 'asuka-product-designer')),
            'layout.sidebarItemBg' => self::token('workspace', 'Navigation', __('Sidebar item', 'asuka-product-designer'), __('Default module navigation item.', 'asuka-product-designer')),
            'layout.sidebarItemHoverBg' => self::token('workspace', 'Navigation', __('Sidebar item hover', 'asuka-product-designer'), __('Pointer and keyboard hover feedback.', 'asuka-product-designer')),
            'layout.sidebarItemActiveBg' => self::token('workspace', 'Navigation', __('Sidebar item active', 'asuka-product-designer'), __('Selected module navigation item.', 'asuka-product-designer')),
            'layout.panelBg' => self::token('workspace', 'Panels', __('Panel background', 'asuka-product-designer'), __('Module panel content surface.', 'asuka-product-designer')),
            'layout.panelHeaderBg' => self::token('workspace', 'Panels', __('Panel header', 'asuka-product-designer'), __('Module panel heading surface.', 'asuka-product-designer')),
            'layout.toolbarBg' => self::token('workspace', 'Panels', __('Toolbar background', 'asuka-product-designer'), __('Top and contextual toolbar surface.', 'asuka-product-designer')),
            'layout.canvasStageBg' => self::token('workspace', 'Canvas', __('Canvas stage', 'asuka-product-designer'), __('Workspace behind the active 2D or 3D view.', 'asuka-product-designer')),
            'layout.overlayBackdrop' => self::token('workspace', 'Canvas', __('Overlay backdrop', 'asuka-product-designer'), __('Backdrop behind modal and focused tools.', 'asuka-product-designer')),

            'thumbnail.bg' => self::token('content', 'Thumbnails', __('Thumbnail background', 'asuka-product-designer'), __('Default view thumbnail surface.', 'asuka-product-designer')),
            'thumbnail.activeBg' => self::token('content', 'Thumbnails', __('Active thumbnail', 'asuka-product-designer'), __('Selected view thumbnail surface.', 'asuka-product-designer')),
            'thumbnail.activeBorder' => self::token('content', 'Thumbnails', __('Active thumbnail border', 'asuka-product-designer'), __('Outline identifying the current view.', 'asuka-product-designer')),
            'text.primary' => self::token('content', 'Typography', __('Primary text', 'asuka-product-designer'), __('Headings, labels, and important values.', 'asuka-product-designer')),
            'text.secondary' => self::token('content', 'Typography', __('Secondary text', 'asuka-product-designer'), __('Descriptions and supporting labels.', 'asuka-product-designer')),
            'text.tertiary' => self::token('content', 'Typography', __('Tertiary text', 'asuka-product-designer'), __('Hints, placeholders, and quiet metadata.', 'asuka-product-designer')),
            'text.inverse' => self::token('content', 'Typography', __('Inverse text', 'asuka-product-designer'), __('Text displayed on strong colored surfaces.', 'asuka-product-designer')),
            'border.subtle' => self::token('content', 'Borders', __('Subtle border', 'asuka-product-designer'), __('Low-emphasis separators and frames.', 'asuka-product-designer')),
            'border.default' => self::token('content', 'Borders', __('Default border', 'asuka-product-designer'), __('Standard component outlines.', 'asuka-product-designer')),
            'border.strong' => self::token('content', 'Borders', __('Strong border', 'asuka-product-designer'), __('High-emphasis structural outlines.', 'asuka-product-designer')),
            'border.focus' => self::token('content', 'Borders', __('Focus border', 'asuka-product-designer'), __('Keyboard and input focus indication.', 'asuka-product-designer')),

            'accent.primary' => self::token('brand', 'Brand', __('Primary accent', 'asuka-product-designer'), __('Main interactive and brand color.', 'asuka-product-designer')),
            'accent.primarySoft' => self::token('brand', 'Brand', __('Soft primary accent', 'asuka-product-designer'), __('Tint used behind selected and highlighted content.', 'asuka-product-designer')),
            'accent.success' => self::token('brand', 'Feedback', __('Success', 'asuka-product-designer'), __('Positive confirmations and available states.', 'asuka-product-designer')),
            'accent.warning' => self::token('brand', 'Feedback', __('Warning', 'asuka-product-designer'), __('Attention and non-blocking warning states.', 'asuka-product-designer')),
            'accent.danger' => self::token('brand', 'Feedback', __('Danger', 'asuka-product-designer'), __('Destructive and error states.', 'asuka-product-designer')),

            'button.primary.bg' => self::token('controls', 'Primary button', __('Background', 'asuka-product-designer'), __('Primary command surface.', 'asuka-product-designer')),
            'button.primary.text' => self::token('controls', 'Primary button', __('Text', 'asuka-product-designer'), __('Primary command label.', 'asuka-product-designer')),
            'button.primary.border' => self::token('controls', 'Primary button', __('Border', 'asuka-product-designer'), __('Primary command outline.', 'asuka-product-designer')),
            'button.primary.hoverBg' => self::token('controls', 'Primary button', __('Hover background', 'asuka-product-designer'), __('Primary command hover feedback.', 'asuka-product-designer')),
            'button.secondary.bg' => self::token('controls', 'Secondary button', __('Background', 'asuka-product-designer'), __('Secondary command surface.', 'asuka-product-designer')),
            'button.secondary.text' => self::token('controls', 'Secondary button', __('Text', 'asuka-product-designer'), __('Secondary command label.', 'asuka-product-designer')),
            'button.secondary.border' => self::token('controls', 'Secondary button', __('Border', 'asuka-product-designer'), __('Secondary command outline.', 'asuka-product-designer')),
            'button.secondary.hoverBg' => self::token('controls', 'Secondary button', __('Hover background', 'asuka-product-designer'), __('Secondary command hover feedback.', 'asuka-product-designer')),
            'button.ghost.text' => self::token('controls', 'Ghost button', __('Text', 'asuka-product-designer'), __('Quiet command label.', 'asuka-product-designer')),
            'button.ghost.hoverBg' => self::token('controls', 'Ghost button', __('Hover background', 'asuka-product-designer'), __('Quiet command hover feedback.', 'asuka-product-designer')),
            'button.danger.bg' => self::token('controls', 'Danger button', __('Background', 'asuka-product-designer'), __('Destructive command surface.', 'asuka-product-designer')),
            'button.danger.text' => self::token('controls', 'Danger button', __('Text', 'asuka-product-designer'), __('Destructive command label.', 'asuka-product-designer')),
            'button.danger.border' => self::token('controls', 'Danger button', __('Border', 'asuka-product-designer'), __('Destructive command outline.', 'asuka-product-designer')),
            'button.danger.hoverBg' => self::token('controls', 'Danger button', __('Hover background', 'asuka-product-designer'), __('Destructive command hover feedback.', 'asuka-product-designer')),
            'input.bg' => self::token('controls', 'Fields', __('Input background', 'asuka-product-designer'), __('Form field surface.', 'asuka-product-designer')),
            'input.text' => self::token('controls', 'Fields', __('Input text', 'asuka-product-designer'), __('Entered form value.', 'asuka-product-designer')),
            'input.border' => self::token('controls', 'Fields', __('Input border', 'asuka-product-designer'), __('Form field outline.', 'asuka-product-designer')),
            'input.placeholder' => self::token('controls', 'Fields', __('Input placeholder', 'asuka-product-designer'), __('Empty field helper text.', 'asuka-product-designer')),
            'input.focusRing' => self::token('controls', 'Fields', __('Input focus ring', 'asuka-product-designer'), __('Focus halo around active fields.', 'asuka-product-designer')),
            'iconButton.bg' => self::token('controls', 'Icon button', __('Background', 'asuka-product-designer'), __('Compact action surface.', 'asuka-product-designer')),
            'iconButton.text' => self::token('controls', 'Icon button', __('Icon', 'asuka-product-designer'), __('Compact action glyph color.', 'asuka-product-designer')),
            'iconButton.border' => self::token('controls', 'Icon button', __('Border', 'asuka-product-designer'), __('Compact action outline.', 'asuka-product-designer')),
            'iconButton.hoverBg' => self::token('controls', 'Icon button', __('Hover background', 'asuka-product-designer'), __('Compact action hover feedback.', 'asuka-product-designer')),
        ];
    }

    public static function presets() : array
    {
        $defaults = self::defaultColors();
        $definitions = [
            'light' => [
                'label' => __('Asuka Light', 'asuka-product-designer'),
                'description' => __('Bright, neutral, and optimized for product workflows.', 'asuka-product-designer'),
                'colors' => [],
            ],
            'dark' => [
                'label' => __('Deep Navy', 'asuka-product-designer'),
                'description' => __('A high-contrast dark workspace with calm blue accents.', 'asuka-product-designer'),
                'colors' => self::darkColors(),
            ],
            'figma' => [
                'label' => __('Product Blue', 'asuka-product-designer'),
                'description' => __('Compact neutral surfaces with a crisp cyan-blue accent.', 'asuka-product-designer'),
                'colors' => [
                    'layout.appBg' => '#f3f4f8', 'layout.shellBg' => '#ffffff', 'layout.sidebarBg' => '#ffffff',
                    'layout.sidebarItemBg' => 'transparent', 'layout.sidebarItemHoverBg' => 'rgba(15, 23, 42, 0.04)',
                    'layout.sidebarItemActiveBg' => 'rgba(13, 153, 255, 0.10)', 'layout.panelBg' => '#ffffff',
                    'layout.panelHeaderBg' => '#ffffff', 'layout.toolbarBg' => '#ffffff', 'layout.canvasStageBg' => '#f7f8fb',
                    'thumbnail.activeBorder' => '#0d99ff', 'accent.primary' => '#0d99ff',
                    'accent.primarySoft' => 'rgba(13, 153, 255, 0.12)', 'border.subtle' => '#eceff4',
                    'border.default' => '#dde3ec', 'button.primary.bg' => '#0d99ff', 'button.primary.border' => '#0d99ff',
                    'button.primary.hoverBg' => '#0b87e1', 'button.secondary.bg' => '#ffffff', 'button.secondary.border' => '#dde3ec',
                ],
            ],
            'linear' => [
                'label' => __('Graphite', 'asuka-product-designer'),
                'description' => __('A refined graphite workspace with soft indigo actions.', 'asuka-product-designer'),
                'colors' => self::linearColors(),
            ],
            'canva' => [
                'label' => __('Creative Violet', 'asuka-product-designer'),
                'description' => __('Friendly white surfaces with an expressive violet identity.', 'asuka-product-designer'),
                'colors' => [
                    'layout.appBg' => '#f4f6fb', 'layout.shellBg' => '#ffffff', 'layout.sidebarBg' => '#ffffff',
                    'layout.panelBg' => '#ffffff', 'layout.canvasStageBg' => '#eef1f7', 'accent.primary' => '#7c3aed',
                    'accent.primarySoft' => 'rgba(124,58,237,0.14)', 'thumbnail.activeBorder' => '#7c3aed',
                    'button.primary.bg' => '#7c3aed', 'button.primary.border' => '#7c3aed', 'button.primary.hoverBg' => '#6d28d9',
                ],
            ],
            'minimal' => [
                'label' => __('Quiet Minimal', 'asuka-product-designer'),
                'description' => __('Soft separators and restrained contrast for embedded stores.', 'asuka-product-designer'),
                'colors' => [
                    'layout.appBg' => '#f8fafc', 'layout.shellBg' => '#ffffff', 'layout.sidebarBg' => '#ffffff',
                    'layout.panelBg' => '#ffffff', 'layout.canvasStageBg' => '#f8fafc', 'border.subtle' => '#eef2f7',
                    'border.default' => '#e5eaf2', 'border.strong' => '#d6dee9', 'button.secondary.bg' => '#ffffff',
                    'button.secondary.hoverBg' => '#f9fafb',
                ],
            ],
        ];

        foreach ($definitions as $id => $definition) {
            $definitions[$id]['colors'] = array_replace($defaults, (array) $definition['colors']);
        }

        return $definitions;
    }

    public static function defaultColors() : array
    {
        return [
            'layout.appBg' => '#f5f7fb', 'layout.shellBg' => '#ffffff', 'layout.sidebarBg' => '#ffffff',
            'layout.sidebarItemBg' => '#ffffff', 'layout.sidebarItemHoverBg' => 'rgba(37, 99, 235, 0.05)',
            'layout.sidebarItemActiveBg' => 'rgba(37, 99, 235, 0.08)', 'layout.panelBg' => '#ffffff',
            'layout.panelHeaderBg' => 'rgba(248, 250, 252, 0.92)', 'layout.toolbarBg' => 'rgba(255, 255, 255, 0.96)',
            'layout.canvasStageBg' => '#eef2f7', 'layout.overlayBackdrop' => 'rgba(15, 23, 42, 0.24)',
            'thumbnail.bg' => '#ffffff', 'thumbnail.activeBg' => 'rgba(37, 99, 235, 0.10)',
            'thumbnail.activeBorder' => '#2563eb', 'text.primary' => '#0f172a', 'text.secondary' => '#64748b',
            'text.tertiary' => '#94a3b8', 'text.inverse' => '#ffffff', 'border.subtle' => '#e8edf5',
            'border.default' => '#d7dfeb', 'border.strong' => '#b8c4d7', 'border.focus' => '#2563eb',
            'accent.primary' => '#2563eb', 'accent.primarySoft' => 'rgba(37, 99, 235, 0.12)',
            'accent.success' => '#16a34a', 'accent.warning' => '#f59e0b', 'accent.danger' => '#dc2626',
            'button.primary.bg' => '#2563eb', 'button.primary.text' => '#ffffff', 'button.primary.border' => '#2563eb',
            'button.primary.hoverBg' => '#1d4ed8', 'button.secondary.bg' => '#ffffff',
            'button.secondary.text' => '#0f172a', 'button.secondary.border' => '#d7dfeb',
            'button.secondary.hoverBg' => '#f8fafc', 'button.ghost.text' => '#334155',
            'button.ghost.hoverBg' => 'rgba(15, 23, 42, 0.05)', 'button.danger.bg' => '#dc2626',
            'button.danger.text' => '#ffffff', 'button.danger.border' => '#dc2626',
            'button.danger.hoverBg' => '#b91c1c', 'input.bg' => '#ffffff', 'input.text' => '#0f172a',
            'input.border' => '#d7dfeb', 'input.placeholder' => '#94a3b8',
            'input.focusRing' => 'rgba(37, 99, 235, 0.18)', 'iconButton.bg' => '#ffffff',
            'iconButton.text' => '#334155', 'iconButton.border' => '#d7dfeb', 'iconButton.hoverBg' => '#f8fafc',
        ];
    }

    private static function darkColors() : array
    {
        return [
            'layout.appBg' => '#07152f', 'layout.shellBg' => '#09162d', 'layout.sidebarBg' => '#081327',
            'layout.sidebarItemBg' => '#0b1a33', 'layout.sidebarItemHoverBg' => 'rgba(96, 165, 250, 0.10)',
            'layout.sidebarItemActiveBg' => 'rgba(59, 130, 246, 0.18)', 'layout.panelBg' => '#09162d',
            'layout.panelHeaderBg' => '#0b1a33', 'layout.toolbarBg' => '#09162d', 'layout.canvasStageBg' => '#071229',
            'layout.overlayBackdrop' => 'rgba(2, 6, 23, 0.58)', 'thumbnail.bg' => '#0b1a33',
            'thumbnail.activeBg' => 'rgba(59, 130, 246, 0.18)', 'thumbnail.activeBorder' => '#60a5fa',
            'text.primary' => '#e5eefc', 'text.secondary' => '#a9bddb', 'text.tertiary' => '#7d95b8',
            'text.inverse' => '#ffffff', 'border.subtle' => '#183055', 'border.default' => '#25416a',
            'border.strong' => '#36598d', 'border.focus' => '#60a5fa', 'accent.primary' => '#60a5fa',
            'accent.primarySoft' => 'rgba(96, 165, 250, 0.16)', 'accent.success' => '#34d399',
            'accent.warning' => '#fbbf24', 'accent.danger' => '#f87171', 'button.primary.bg' => '#3b82f6',
            'button.primary.text' => '#ffffff', 'button.primary.border' => '#3b82f6',
            'button.primary.hoverBg' => '#2563eb', 'button.secondary.bg' => '#0c1c37',
            'button.secondary.text' => '#e5eefc', 'button.secondary.border' => '#23416a',
            'button.secondary.hoverBg' => '#102243', 'button.ghost.text' => '#c6d5ee',
            'button.ghost.hoverBg' => 'rgba(255, 255, 255, 0.06)', 'button.danger.bg' => '#ef4444',
            'button.danger.text' => '#ffffff', 'button.danger.border' => '#ef4444',
            'button.danger.hoverBg' => '#dc2626', 'input.bg' => '#0c1c37', 'input.text' => '#e5eefc',
            'input.border' => '#23416a', 'input.placeholder' => '#7d95b8',
            'input.focusRing' => 'rgba(96, 165, 250, 0.24)', 'iconButton.bg' => '#0c1c37',
            'iconButton.text' => '#d9e7fb', 'iconButton.border' => '#23416a', 'iconButton.hoverBg' => '#102243',
        ];
    }

    private static function linearColors() : array
    {
        return [
            'layout.appBg' => '#08090d', 'layout.shellBg' => '#0c0d12', 'layout.sidebarBg' => '#0d0f14',
            'layout.sidebarItemBg' => '#101218', 'layout.sidebarItemHoverBg' => 'rgba(148, 163, 184, 0.10)',
            'layout.sidebarItemActiveBg' => 'rgba(94, 106, 210, 0.22)', 'layout.panelBg' => '#15171d',
            'layout.panelHeaderBg' => '#1b1d24', 'layout.toolbarBg' => '#101117', 'layout.canvasStageBg' => '#050609',
            'layout.overlayBackdrop' => 'rgba(0, 0, 0, 0.52)', 'thumbnail.bg' => '#101218',
            'thumbnail.activeBg' => 'rgba(94, 106, 210, 0.18)', 'thumbnail.activeBorder' => '#7b83eb',
            'text.primary' => '#f7f8fb', 'text.secondary' => '#c5cad6', 'text.tertiary' => '#8f96a6',
            'text.inverse' => '#ffffff', 'border.subtle' => '#2a2d36', 'border.default' => '#3a3f4c',
            'border.strong' => '#545b6e', 'border.focus' => '#7b83eb', 'accent.primary' => '#7b83eb',
            'accent.primarySoft' => 'rgba(123, 131, 235, 0.20)', 'accent.success' => '#38d996',
            'accent.warning' => '#f8c35c', 'accent.danger' => '#ff7b7b', 'button.primary.bg' => '#5e6ad2',
            'button.primary.text' => '#ffffff', 'button.primary.border' => '#6f78e8',
            'button.primary.hoverBg' => '#6b75e4', 'button.secondary.bg' => '#20232c',
            'button.secondary.text' => '#f7f8fb', 'button.secondary.border' => '#414756',
            'button.secondary.hoverBg' => '#2a2e39', 'button.ghost.text' => '#d7dbe5',
            'button.ghost.hoverBg' => 'rgba(255, 255, 255, 0.08)', 'button.danger.bg' => '#d84f57',
            'button.danger.text' => '#ffffff', 'button.danger.border' => '#e46b72',
            'button.danger.hoverBg' => '#c74149', 'input.bg' => '#101218', 'input.text' => '#f7f8fb',
            'input.border' => '#3a3f4c', 'input.placeholder' => '#8f96a6',
            'input.focusRing' => 'rgba(123, 131, 235, 0.28)', 'iconButton.bg' => '#20232c',
            'iconButton.text' => '#e7eaf2', 'iconButton.border' => '#414756', 'iconButton.hoverBg' => '#2a2e39',
        ];
    }

    private static function translatedGroup(string $group) : string
    {
        return match ($group) {
            'Foundation' => __('Foundation', 'asuka-product-designer'),
            'Navigation' => __('Navigation', 'asuka-product-designer'),
            'Panels' => __('Panels', 'asuka-product-designer'),
            'Canvas' => __('Canvas', 'asuka-product-designer'),
            'Thumbnails' => __('Thumbnails', 'asuka-product-designer'),
            'Typography' => __('Typography', 'asuka-product-designer'),
            'Borders' => __('Borders', 'asuka-product-designer'),
            'Brand' => __('Brand', 'asuka-product-designer'),
            'Feedback' => __('Feedback', 'asuka-product-designer'),
            'Primary button' => __('Primary button', 'asuka-product-designer'),
            'Secondary button' => __('Secondary button', 'asuka-product-designer'),
            'Ghost button' => __('Ghost button', 'asuka-product-designer'),
            'Danger button' => __('Danger button', 'asuka-product-designer'),
            'Fields' => __('Fields', 'asuka-product-designer'),
            'Icon button' => __('Icon button', 'asuka-product-designer'),
            default => $group,
        };
    }

    private static function token(string $section, string $group, string $label, string $description) : array
    {
        return [
            'section' => $section,
            'group' => self::translatedGroup($group),
            'label' => $label,
            'description' => $description,
        ];
    }

    private function resolveThemeId(?string $themeId, bool $allowUnpublished = false) : string
    {
        $themeId = $this->sanitizeThemeId($themeId ?? '');
        if ($themeId !== '' && get_post_type((int) $themeId) === ThemePostType::TYPE) {
            if ($allowUnpublished || get_post_status((int) $themeId) === 'publish') {
                return $themeId;
            }
        }
        return $this->defaultThemeId();
    }

    private function sanitizeThemeId(mixed $themeId) : string
    {
        $themeId = absint($themeId);
        return $themeId > 0 ? (string) $themeId : '';
    }

    /** @return \WP_Post[] */
    private function themePosts(array $statuses) : array
    {
        if (! post_type_exists(ThemePostType::TYPE)) {
            return [];
        }

        return get_posts([
            'post_type' => ThemePostType::TYPE,
            'post_status' => $statuses,
            'posts_per_page' => -1,
            'orderby' => ['menu_order' => 'ASC', 'title' => 'ASC', 'ID' => 'ASC'],
            'order' => 'ASC',
            'no_found_rows' => true,
        ]);
    }

    private function payloadForPost(\WP_Post $post) : array
    {
        $payload = get_post_meta($post->ID, self::POST_META, true);
        if (is_string($payload)) {
            $decoded = json_decode($payload, true);
            $payload = is_array($decoded) ? $decoded : [];
        }
        $payload = is_array($payload) ? $payload : [];
        if (trim($post->post_title) !== '') {
            $payload['name'] = $post->post_title;
        }
        return $this->normalizeStored($payload);
    }

    private function ensureDefaultThemePost() : int
    {
        static $creating = false;
        if ($creating || ! post_type_exists(ThemePostType::TYPE)) {
            return 0;
        }

        $creating = true;
        $theme = $this->defaultPayload();
        $postId = wp_insert_post([
            'post_type' => ThemePostType::TYPE,
            'post_status' => 'publish',
            'post_title' => $theme['name'],
        ]);
        if (! is_wp_error($postId) && (int) $postId > 0) {
            update_post_meta((int) $postId, self::POST_META, $theme);
            $settings = (array) get_option('apd_settings', []);
            $settings['default_designer_theme_id'] = (string) $postId;
            update_option('apd_settings', $settings, false);
        }
        $creating = false;
        return is_wp_error($postId) ? 0 : (int) $postId;
    }

    private function defaultPayload() : array
    {
        return [
            'version' => self::VERSION,
            'name' => __('Store theme', 'asuka-product-designer'),
            'preset' => 'light',
            'colors' => self::defaultColors(),
            'updatedAt' => '',
            'updatedBy' => 0,
        ];
    }

    private function normalizeStored(array $payload) : array
    {
        $preset = sanitize_key((string) ($payload['preset'] ?? 'light'));
        $presets = self::presets();
        if (! isset($presets[$preset])) {
            $preset = 'light';
        }
        $colors = array_replace($presets[$preset]['colors'], $this->sanitizePartialColors($payload['colors'] ?? []));

        return [
            'version' => self::VERSION,
            'name' => $this->sanitizeName($payload['name'] ?? __('Store theme', 'asuka-product-designer')),
            'preset' => $preset,
            'colors' => $colors,
            'updatedAt' => sanitize_text_field((string) ($payload['updatedAt'] ?? '')),
            'updatedBy' => absint($payload['updatedBy'] ?? 0),
        ];
    }

    private function normalizeSubmitted(array $payload) : array
    {
        $theme = $this->normalizeStored($payload);
        $theme['updatedAt'] = current_time('mysql', true);
        $theme['updatedBy'] = get_current_user_id();
        return $theme;
    }

    private function sanitizePartialColors(mixed $colors) : array
    {
        if (! is_array($colors)) {
            return [];
        }

        $allowed = array_fill_keys(array_keys(self::tokens()), true);
        $result = [];
        foreach ($colors as $token => $value) {
            $token = (string) $token;
            if (! isset($allowed[$token])) {
                continue;
            }
            $color = self::sanitizeCssColor($value);
            if ($color !== '') {
                $result[$token] = $color;
            }
        }
        return $result;
    }

    private function sanitizeName(mixed $name) : string
    {
        $name = sanitize_text_field((string) $name);
        $name = function_exists('mb_substr') ? mb_substr($name, 0, 80) : substr($name, 0, 80);
        return $name !== '' ? $name : __('Store theme', 'asuka-product-designer');
    }

    private static function sanitizeCssColor(mixed $value) : string
    {
        $value = trim((string) $value);
        if ($value === '' || strlen($value) > 80) {
            return '';
        }
        if ($value === 'transparent') {
            return $value;
        }
        if (preg_match('/^#(?:[0-9a-f]{3}|[0-9a-f]{4}|[0-9a-f]{6}|[0-9a-f]{8})$/i', $value)) {
            return strtolower($value);
        }
        if (preg_match('/^rgba?\(\s*[0-9.]+%?\s*[, ]\s*[0-9.]+%?\s*[, ]\s*[0-9.]+%?(?:\s*[,\/]\s*[0-9.]+%?)?\s*\)$/i', $value)) {
            return $value;
        }
        if (preg_match('/^hsla?\(\s*[-0-9.]+(?:deg|rad|turn)?\s*[, ]\s*[0-9.]+%\s*[, ]\s*[0-9.]+%(?:\s*[,\/]\s*[0-9.]+%?)?\s*\)$/i', $value)) {
            return $value;
        }
        return '';
    }
}
