<?php
/**
 * ActionHandler — bridges LolaCore action dispatch to Bricks handlers.
 *
 * @package LolaCoreForBricks
 */

declare(strict_types=1);

namespace LolaCoreForBricks;

use LolaCoreForBricks\Handlers\ClassHandler;
use LolaCoreForBricks\Handlers\CompositionHandler;
use LolaCoreForBricks\Handlers\ContentShortcutHandler;
use LolaCoreForBricks\Handlers\ElementStyleHandler;
use LolaCoreForBricks\Handlers\ComponentWriteHandler;
use LolaCoreForBricks\Handlers\PageBehaviorHandler;
use LolaCoreForBricks\Handlers\TemplateWriteHandler;
use LolaCoreForBricks\Handlers\WooSurfaceHandler;
use LolaCoreForBricks\Handlers\BatchCompositionHandler;
use LolaCoreForBricks\Handlers\ConventionHandler;
use LolaCoreForBricks\Handlers\DesignSystemHandler;
use LolaCoreForBricks\Handlers\GovernanceHandler;
use LolaCoreForBricks\Handlers\IndexHandler;
use LolaCoreForBricks\Handlers\KnowledgeHandler;
use LolaCoreForBricks\Handlers\OrientationHandler;
use LolaCoreForBricks\Support\BricksCodeGuard;
use LolaCoreForBricks\Support\OperatingGuide;

/**
 * Door 2 — snake_case registry and external action dispatch.
 */
class ActionHandler
{
    /**
     * @var array<string, array{requires_confirmation: bool, type: string}>
     */
    private const ACTIONS = [
        'get_bricks_overview'          => ['requires_confirmation' => false, 'type' => 'read'],
        'rebuild_design_index'         => ['requires_confirmation' => false, 'type' => 'write'],
        'get_global_classes'           => ['requires_confirmation' => false, 'type' => 'read'],
        'get_class_usage'              => ['requires_confirmation' => false, 'type' => 'read'],
        'get_global_variables'         => ['requires_confirmation' => false, 'type' => 'read'],
        'get_variable_usage'           => ['requires_confirmation' => false, 'type' => 'read'],
        'get_theme_styles'             => ['requires_confirmation' => false, 'type' => 'read'],
        'get_components'               => ['requires_confirmation' => false, 'type' => 'read'],
        'get_component_usage'          => ['requires_confirmation' => false, 'type' => 'read'],
        'get_templates'                => ['requires_confirmation' => false, 'type' => 'read'],
        'resolve_template_for_page'    => ['requires_confirmation' => false, 'type' => 'read'],
        'describe_element_controls'    => ['requires_confirmation' => false, 'type' => 'read'],
        'get_bricks_operating_guide'   => ['requires_confirmation' => false, 'type' => 'read'],
        'find_unused_classes'          => ['requires_confirmation' => false, 'type' => 'read'],
        'find_duplicate_classes'       => ['requires_confirmation' => false, 'type' => 'read'],
        'find_unused_variables'        => ['requires_confirmation' => false, 'type' => 'read'],
        'find_orphan_components'       => ['requires_confirmation' => false, 'type' => 'read'],
        'find_theme_style_conflicts'   => ['requires_confirmation' => false, 'type' => 'read'],
        'create_global_class'          => ['requires_confirmation' => true, 'type' => 'write'],
        'update_global_class_settings' => ['requires_confirmation' => true, 'type' => 'write'],
        'rename_global_class'          => ['requires_confirmation' => true, 'type' => 'write'],
        'merge_global_classes'         => ['requires_confirmation' => true, 'type' => 'write'],
        'trash_global_classes'           => ['requires_confirmation' => true, 'type' => 'write'],
        'restore_global_class'           => ['requires_confirmation' => true, 'type' => 'write'],
        'set_global_variable'            => ['requires_confirmation' => true, 'type' => 'write'],
        'delete_global_variable'         => ['requires_confirmation' => true, 'type' => 'write'],
        'update_color_palette'           => ['requires_confirmation' => true, 'type' => 'write'],
        'update_theme_style'             => ['requires_confirmation' => true, 'type' => 'write'],
        'set_design_convention'          => ['requires_confirmation' => true, 'type' => 'write'],
        'get_page_structure'             => ['requires_confirmation' => false, 'type' => 'read'],
        'insert_element'                 => ['requires_confirmation' => true, 'type' => 'write'],
        'move_element'                   => ['requires_confirmation' => true, 'type' => 'write'],
        'duplicate_element'              => ['requires_confirmation' => true, 'type' => 'write'],
        'delete_element'                 => ['requires_confirmation' => true, 'type' => 'write'],
        'style_element'                  => ['requires_confirmation' => true, 'type' => 'write'],
        'apply_classes'                  => ['requires_confirmation' => true, 'type' => 'write'],
        'remove_classes'                 => ['requires_confirmation' => true, 'type' => 'write'],
        'update_element_settings'        => ['requires_confirmation' => true, 'type' => 'write'],
        'set_element_content'            => ['requires_confirmation' => true, 'type' => 'write'],
        'add_section'                    => ['requires_confirmation' => true, 'type' => 'write'],
        'add_container'                  => ['requires_confirmation' => true, 'type' => 'write'],
        'add_div'                        => ['requires_confirmation' => true, 'type' => 'write'],
        'add_heading'                    => ['requires_confirmation' => true, 'type' => 'write'],
        'add_text'                       => ['requires_confirmation' => true, 'type' => 'write'],
        'add_image'                      => ['requires_confirmation' => true, 'type' => 'write'],
        'add_button'                     => ['requires_confirmation' => true, 'type' => 'write'],
        'create_template'                => ['requires_confirmation' => true, 'type' => 'write'],
        'set_template_content'           => ['requires_confirmation' => true, 'type' => 'write'],
        'update_template_conditions'     => ['requires_confirmation' => true, 'type' => 'write'],
        'duplicate_template'             => ['requires_confirmation' => true, 'type' => 'write'],
        'delete_template'                => ['requires_confirmation' => true, 'type' => 'write'],
        'create_component_from_element'  => ['requires_confirmation' => true, 'type' => 'write'],
        'update_component_properties'    => ['requires_confirmation' => true, 'type' => 'write'],
        'update_component'               => ['requires_confirmation' => true, 'type' => 'write'],
        'insert_component_instance'      => ['requires_confirmation' => true, 'type' => 'write'],
        'update_component_instance'      => ['requires_confirmation' => true, 'type' => 'write'],
        'detach_component_instance'      => ['requires_confirmation' => true, 'type' => 'write'],
        'update_page_settings'           => ['requires_confirmation' => true, 'type' => 'write'],
        'set_element_conditions'         => ['requires_confirmation' => true, 'type' => 'write'],
        'set_element_interactions'       => ['requires_confirmation' => true, 'type' => 'write'],
        'list_dynamic_data_tags'         => ['requires_confirmation' => false, 'type' => 'read'],
        'set_dynamic_content'            => ['requires_confirmation' => true, 'type' => 'write'],
        'clone_structure'                => ['requires_confirmation' => true, 'type' => 'write'],
        'bulk_update_content'            => ['requires_confirmation' => true, 'type' => 'write'],
        'bulk_apply_classes'             => ['requires_confirmation' => true, 'type' => 'write'],
    ];

    /**
     * @var array<string, string>
     */
    private const KNOWLEDGE_HANDLERS = [
        'get_global_classes'         => 'getGlobalClasses',
        'get_class_usage'            => 'getClassUsage',
        'get_global_variables'       => 'getGlobalVariables',
        'get_variable_usage'         => 'getVariableUsage',
        'get_theme_styles'           => 'getThemeStyles',
        'get_components'             => 'getComponents',
        'get_component_usage'        => 'getComponentUsage',
        'get_templates'              => 'getTemplates',
        'resolve_template_for_page'  => 'resolveTemplateForPage',
        'describe_element_controls'  => 'describeElementControls',
        'get_bricks_operating_guide' => 'getBricksOperatingGuide',
    ];

    /**
     * @var array<string, string>
     */
    private const GOVERNANCE_HANDLERS = [
        'find_unused_classes'        => 'findUnusedClasses',
        'find_duplicate_classes'     => 'findDuplicateClasses',
        'find_unused_variables'      => 'findUnusedVariables',
        'find_orphan_components'     => 'findOrphanComponents',
        'find_theme_style_conflicts' => 'findThemeStyleConflicts',
    ];

    /**
     * @var array<string, string>
     */
    private const CLASS_WRITE_HANDLERS = [
        'create_global_class'          => 'createGlobalClass',
        'update_global_class_settings' => 'updateGlobalClassSettings',
        'rename_global_class'          => 'renameGlobalClass',
        'merge_global_classes'         => 'mergeGlobalClasses',
        'trash_global_classes'         => 'trashGlobalClasses',
        'restore_global_class'         => 'restoreGlobalClass',
    ];

    /**
     * @var array<string, string>
     */
    private const DESIGN_SYSTEM_WRITE_HANDLERS = [
        'set_global_variable'    => 'setGlobalVariable',
        'delete_global_variable' => 'deleteGlobalVariable',
        'update_color_palette'   => 'updateColorPalette',
        'update_theme_style'     => 'updateThemeStyle',
    ];

    /**
     * @var array<string, string>
     */
    private const CONVENTION_WRITE_HANDLERS = [
        'set_design_convention' => 'setDesignConvention',
    ];

    /**
     * @var array<string, string>
     */
    private const COMPOSITION_READ_HANDLERS = [
        'get_page_structure' => 'getPageStructure',
    ];

    /**
     * @var array<string, string>
     */
    private const COMPOSITION_WRITE_HANDLERS = [
        'insert_element'    => 'insertElement',
        'move_element'      => 'moveElement',
        'duplicate_element' => 'duplicateElement',
        'delete_element'    => 'deleteElement',
    ];

    /**
     * @var array<string, string>
     */
    private const ELEMENT_STYLE_HANDLERS = [
        'style_element'           => 'styleElement',
        'apply_classes'           => 'applyClasses',
        'remove_classes'          => 'removeClasses',
        'update_element_settings' => 'updateElementSettings',
    ];

    /**
     * @var array<string, string>
     */
    private const CONTENT_SHORTCUT_HANDLERS = [
        'set_element_content' => 'setElementContent',
        'add_section'         => 'addSection',
        'add_container'       => 'addContainer',
        'add_div'             => 'addDiv',
        'add_heading'         => 'addHeading',
        'add_text'            => 'addText',
        'add_image'           => 'addImage',
        'add_button'          => 'addButton',
    ];

    /**
     * @var array<string, string>
     */
    private const TEMPLATE_WRITE_HANDLERS = [
        'create_template'            => 'createTemplate',
        'set_template_content'       => 'setTemplateContent',
        'update_template_conditions' => 'updateTemplateConditions',
        'duplicate_template'         => 'duplicateTemplate',
        'delete_template'            => 'deleteTemplate',
    ];

    /**
     * @var array<string, string>
     */
    private const COMPONENT_WRITE_HANDLERS = [
        'create_component_from_element' => 'createComponentFromElement',
        'update_component_properties'   => 'updateComponentProperties',
        'update_component'              => 'updateComponent',
        'insert_component_instance'     => 'insertComponentInstance',
        'update_component_instance'     => 'updateComponentInstance',
        'detach_component_instance'     => 'detachComponentInstance',
    ];

    /**
     * @var array<string, string>
     */
    private const PAGE_BEHAVIOR_WRITE_HANDLERS = [
        'update_page_settings'     => 'updatePageSettings',
        'set_element_conditions'   => 'setElementConditions',
        'set_element_interactions' => 'setElementInteractions',
        'set_dynamic_content'      => 'setDynamicContent',
    ];

    public function register(): void
    {
        add_filter('lolacore_execute_external_action', [$this, 'handleAction'], 10, 5);
        add_filter('lolacore_sop_map', [$this, 'injectSop'], 10, 1);
        add_filter('lolacore_available_actions', [$this, 'registerActions'], 10, 1);
    }

    /**
     * @param array<string, mixed>|null $result
     * @param array<string, mixed>      $params
     * @return array<string, mixed>|null
     */
    public function handleAction(?array $result, string $actionId, array $params, bool $dryRun, string $source): ?array
    {
        unset($source);

        $actions = self::getActions();
        if (!isset($actions[$actionId])) {
            return $result;
        }

        if ($result !== null) {
            return $result;
        }

        if (!BricksEnv::isAvailable() || !BricksEnv::meetsFloor()) {
            return $this->deniedResponse(
                $actionId,
                'Bricks is not available on this site yet. Activate Bricks '
                . BricksEnv::FLOOR_VERSION . ' or newer, then try again.'
            );
        }

        if (!BricksEnv::userCanReadDesignSystem()) {
            return $this->deniedResponse(
                $actionId,
                'I need administrator access to use Bricks design-system tools.'
            );
        }

        if ($actions[$actionId]['type'] === 'write') {
            if ($rejection = BricksCodeGuard::rejectionResponse($params)) {
                return $this->deniedResponse(
                    $actionId,
                    (string) $rejection['message'],
                    (string) ($rejection['error'] ?? 'forbidden_code')
                );
            }
        }

        $orientation = new OrientationHandler();
        $index       = new IndexHandler();
        $knowledge   = new KnowledgeHandler();
        $governance  = new GovernanceHandler();
        $classWrites = new ClassHandler();
        $designWrites = new DesignSystemHandler();
        $conventionWrites = new ConventionHandler();
        $composition      = new CompositionHandler();
        $elementStyles    = new ElementStyleHandler();
        $contentShortcuts = new ContentShortcutHandler();
        $templateWrites   = new TemplateWriteHandler();
        $componentWrites  = new ComponentWriteHandler();
        $pageBehavior     = new PageBehaviorHandler();
        $wooSurface       = new WooSurfaceHandler();
        $batchWrites      = new BatchCompositionHandler();

        if (isset(BatchCompositionAbilityMap::entries()[$actionId])) {
            $method = BatchCompositionAbilityMap::entries()[$actionId]['handler'];

            return $this->handleClassWrite($actionId, $dryRun, $batchWrites->{$method}($params, $dryRun));
        }

        if (isset(WooSurfaceAbilityMap::entries()[$actionId])) {
            $entry  = WooSurfaceAbilityMap::entries()[$actionId];
            $method = $entry['handler'];

            return $entry['type'] === 'read'
                ? $this->handleRead($actionId, $wooSurface->{$method}($params))
                : $this->handleClassWrite($actionId, $dryRun, $wooSurface->{$method}($params, $dryRun));
        }

        if ($actionId === 'list_dynamic_data_tags') {
            return $this->handleRead($actionId, $pageBehavior->listDynamicDataTags($params));
        }

        if (isset(self::PAGE_BEHAVIOR_WRITE_HANDLERS[$actionId])) {
            $method = self::PAGE_BEHAVIOR_WRITE_HANDLERS[$actionId];

            return $this->handleClassWrite($actionId, $dryRun, $pageBehavior->{$method}($params, $dryRun));
        }

        if (isset(self::COMPONENT_WRITE_HANDLERS[$actionId])) {
            $method = self::COMPONENT_WRITE_HANDLERS[$actionId];

            return $this->handleClassWrite($actionId, $dryRun, $componentWrites->{$method}($params, $dryRun));
        }

        if (isset(self::TEMPLATE_WRITE_HANDLERS[$actionId])) {
            $method = self::TEMPLATE_WRITE_HANDLERS[$actionId];

            return $this->handleClassWrite($actionId, $dryRun, $templateWrites->{$method}($params, $dryRun));
        }

        if (isset(self::CONTENT_SHORTCUT_HANDLERS[$actionId])) {
            $method = self::CONTENT_SHORTCUT_HANDLERS[$actionId];

            return $this->handleClassWrite($actionId, $dryRun, $contentShortcuts->{$method}($params, $dryRun));
        }

        if (isset(self::ELEMENT_STYLE_HANDLERS[$actionId])) {
            $method = self::ELEMENT_STYLE_HANDLERS[$actionId];

            return $this->handleClassWrite($actionId, $dryRun, $elementStyles->{$method}($params, $dryRun));
        }

        if (isset(self::COMPOSITION_WRITE_HANDLERS[$actionId])) {
            $method = self::COMPOSITION_WRITE_HANDLERS[$actionId];

            return $this->handleClassWrite($actionId, $dryRun, $composition->{$method}($params, $dryRun));
        }

        if (isset(self::COMPOSITION_READ_HANDLERS[$actionId])) {
            $method = self::COMPOSITION_READ_HANDLERS[$actionId];

            return $this->handleRead($actionId, $composition->{$method}($params));
        }

        if (isset(self::CONVENTION_WRITE_HANDLERS[$actionId])) {
            $method = self::CONVENTION_WRITE_HANDLERS[$actionId];

            return $this->handleClassWrite($actionId, $dryRun, $conventionWrites->{$method}($params, $dryRun));
        }

        if (isset(self::DESIGN_SYSTEM_WRITE_HANDLERS[$actionId])) {
            $method = self::DESIGN_SYSTEM_WRITE_HANDLERS[$actionId];

            return $this->handleClassWrite($actionId, $dryRun, $designWrites->{$method}($params, $dryRun));
        }

        if (isset(self::CLASS_WRITE_HANDLERS[$actionId])) {
            $method = self::CLASS_WRITE_HANDLERS[$actionId];

            return $this->handleClassWrite($actionId, $dryRun, $classWrites->{$method}($params, $dryRun));
        }

        if (isset(self::GOVERNANCE_HANDLERS[$actionId])) {
            $method = self::GOVERNANCE_HANDLERS[$actionId];

            return $this->handleRead($actionId, $governance->{$method}($params));
        }

        if (isset(self::KNOWLEDGE_HANDLERS[$actionId])) {
            $method = self::KNOWLEDGE_HANDLERS[$actionId];

            return $this->handleRead($actionId, $knowledge->{$method}($params));
        }

        return match ($actionId) {
            'get_bricks_overview'  => $this->handleRead($actionId, $orientation->getBricksOverview($params)),
            'rebuild_design_index' => $dryRun
                ? $this->handleRead($actionId, $index->rebuildDesignIndex($params, true))
                : $this->handleWrite(
                    $actionId,
                    false,
                    'Will advance one design-index batch.',
                    fn (): array => $index->rebuildDesignIndex($params, false)
                ),
            default                => $result,
        };
    }

    /**
     * @param array<string, string> $sopMap
     * @return array<string, string>
     */
    public function injectSop(array $sopMap): array
    {
        $sopMap['bricks'] = OperatingGuide::sop();

        return $sopMap;
    }

    /**
     * @param array<string, array<string, mixed>> $registry
     * @return array<string, array<string, mixed>>
     */
    public function registerActions(array $registry): array
    {
        foreach (self::getActions() as $actionId => $meta) {
            if (!isset($registry[$actionId])) {
                $registry[$actionId] = $meta;
            }
        }

        return $registry;
    }

    /**
     * @return array<string, array{requires_confirmation: bool, type: string}>
     */
    public static function getActions(): array
    {
        $actions = self::ACTIONS;
        if (BricksEnv::isWooCommerceActive()) {
            $actions = array_merge($actions, WooSurfaceAbilityMap::doorTwoActions());
        }

        return $actions;
    }

    /**
     * @param array<string, mixed> $data
     * @return array<string, mixed>
     */
    private function handleClassWrite(string $actionId, bool $dryRun, array $data): array
    {
        $success = (bool) ($data['success'] ?? false);

        if (!$success) {
            return [
                'action_id'             => $actionId,
                'mode'                  => 'denied',
                'result'                => (object) $data,
                'message'               => (string) ($data['message'] ?? 'Write action failed.'),
                'requires_confirmation' => true,
                'warnings'              => [],
            ];
        }

        if ($dryRun || ($data['dry_run'] ?? false)) {
            return [
                'action_id'             => $actionId,
                'mode'                  => 'preview',
                'result'                => (object) $data,
                'message'               => (string) ($data['message'] ?? 'Write preview is ready.'),
                'requires_confirmation' => true,
                'warnings'              => [],
            ];
        }

        return [
            'action_id'             => $actionId,
            'mode'                  => 'executed',
            'result'                => (object) $data,
            'message'               => (string) ($data['message'] ?? 'Write action executed successfully.'),
            'requires_confirmation' => true,
            'warnings'              => [],
        ];
    }

    /**
     * @param array<string, mixed> $data
     * @return array<string, mixed>
     */
    private function handleRead(string $actionId, array $data): array
    {
        return [
            'action_id'             => $actionId,
            'mode'                  => 'executed',
            'result'                => (object) $data,
            'message'               => ($data['success'] ?? true)
                ? 'Read action executed successfully.'
                : (string) ($data['message'] ?? 'Read action could not complete.'),
            'requires_confirmation' => false,
            'warnings'              => [],
        ];
    }

    /**
     * @param callable(): array<string, mixed> $executor
     * @return array<string, mixed>
     */
    private function handleWrite(string $actionId, bool $dryRun, string $previewMessage, callable $executor): array
    {
        if ($dryRun) {
            return [
                'action_id'             => $actionId,
                'mode'                  => 'preview',
                'result'                => (object) [],
                'message'               => $previewMessage,
                'requires_confirmation' => true,
                'warnings'              => [],
            ];
        }

        $data    = $executor();
        $success = (bool) ($data['success'] ?? false);

        return [
            'action_id'             => $actionId,
            'mode'                  => $success ? 'executed' : 'denied',
            'result'                => (object) $data,
            'message'               => $success
                ? (string) ($data['message'] ?? 'Write action executed successfully.')
                : (string) ($data['message'] ?? 'Write action failed.'),
            'requires_confirmation' => true,
            'warnings'              => [],
        ];
    }

    /**
     * @return array<string, mixed>
     */
    private function deniedResponse(string $actionId, string $message, ?string $error = null): array
    {
        return [
            'action_id'             => $actionId,
            'mode'                  => 'denied',
            'result'                => (object) ($error !== null ? ['error' => $error] : []),
            'message'               => $message,
            'requires_confirmation' => false,
            'warnings'              => [],
        ];
    }
}
