<?php
/**
 * Integration Manager Class
 *
 * @package FleekDash
 * @subpackage Integrations\Core
 */

namespace FleekDash\Integrations\Core;

use FleekDash\Traits\Base;

defined('ABSPATH') || exit;

/**
 * Integration Manager class
 *
 * Manages the integration lifecycle and API endpoints
 */
class IntegrationManager
{

    use Base;

    /**
     * Integration registry instance
     *
     * @var IntegrationRegistry
     */
    private $registry;

    /**
     * Constructor
     */
    protected function __construct()
    {
        $this->registry = IntegrationRegistry::get_instance();

        // Discover and register integrations
        $this->discoverAndRegisterIntegrations();

        // Register hooks
        add_action('init', [$this, 'initializeIntegrations']);
        add_action('rest_api_init', [$this, 'registerApiRoutes']);

        // Add admin-ajax endpoint as a fallback
        add_action('wp_ajax_fleekdash_get_integrations', [$this, 'ajaxGetIntegrations']);
    }

    /**
     * Discover and register integrations
     */
    private function discoverAndRegisterIntegrations()
    {
        $integrations_dir = FLEEKDASH_PLUGIN_DIR . 'integrations/';

        // Scan integrations directory
        if (!is_dir($integrations_dir)) {
            return;
        }

        $dirs = scandir($integrations_dir);

        foreach ($dirs as $dir) {
            // Skip special directories
            if ($dir === '.' || $dir === '..' || $dir === 'core') {
                continue;
            }

            $integration_path = $integrations_dir . $dir;

            // Check if it's a directory with an Integration.php file
            if (is_dir($integration_path) && file_exists($integration_path . '/Integration.php')) {
                try {
                    require_once $integration_path . '/Integration.php';

                    // Try to instantiate the integration
                    $class_name = 'FleekDash\\Integrations\\' . ucfirst($dir) . '\\Integration';

                    if (class_exists($class_name)) {
                        $integration = new $class_name($integration_path);
                        $this->registry->register($integration);
                    }
                } catch (\Exception $e) {
                    error_log('IntegrationManager: Failed to register integration');
                }
            }
        }
    }

    /**
     * Initialize active integrations
     *
     * @return void
     */
    public function initializeIntegrations()
    {
        $active_integrations = $this->getActiveIntegrations();

        foreach ($active_integrations as $integrations) {
            foreach ($integrations as $integration) {
                if ($integration->isAvailable()) {
                    $integration->init();
                    $integration->registerHooks();
                }
            }
        }
    }

    /**
     * Get active integrations
     *
     * @return array
     */
    public function getActiveIntegrations()
    {
        return $this->registry->getActive();
    }

    /**
     * Register API routes
     *
     * @return void
     */
    public function registerApiRoutes()
    {
        // Define a reusable permission callback
        $permission_callback = function () {
            // Check if user is logged in first
            if (!is_user_logged_in()) {
                return new \WP_Error(
                    'rest_forbidden',
                    __('You must be logged in to access this endpoint.', 'fleekdash'),
                    ['status' => 401],
                );
            }

            // Then check if user has manage_options capability
            if (!current_user_can('manage_options')) {
                return new \WP_Error(
                    'rest_forbidden',
                    __('You do not have permission to access this endpoint.', 'fleekdash'),
                    ['status' => 403],
                );
            }

            return true;
        };

        register_rest_route(
            FLEEKDASH_ROUTE_PREFIX,
            '/integrations',
            [
                'methods' => 'GET',
                'callback' => [$this, 'getIntegrations'],
                'permission_callback' => $permission_callback,
            ],
        );

        register_rest_route(
            FLEEKDASH_ROUTE_PREFIX,
            '/integrations/(?P<category>[a-zA-Z0-9-]+)',
            [
                'methods' => 'GET',
                'callback' => [$this, 'getIntegrationsByCategory'],
                'permission_callback' => $permission_callback,
            ],
        );

        register_rest_route(
            FLEEKDASH_ROUTE_PREFIX,
            '/integrations/(?P<category>[a-zA-Z0-9-]+)/(?P<id>[a-zA-Z0-9-]+)',
            [
                'methods' => 'GET',
                'callback' => [$this, 'getIntegration'],
                'permission_callback' => $permission_callback,
            ],
        );

        register_rest_route(
            FLEEKDASH_ROUTE_PREFIX,
            '/integrations/(?P<category>[a-zA-Z0-9-]+)/(?P<id>[a-zA-Z0-9-]+)/activate',
            [
                'methods' => 'POST',
                'callback' => [$this, 'activateIntegration'],
                'permission_callback' => $permission_callback,
            ],
        );

        register_rest_route(
            FLEEKDASH_ROUTE_PREFIX,
            '/integrations/(?P<category>[a-zA-Z0-9-]+)/(?P<id>[a-zA-Z0-9-]+)/deactivate',
            [
                'methods' => 'POST',
                'callback' => [$this, 'deactivateIntegration'],
                'permission_callback' => $permission_callback,
            ],
        );
    }

    /**
     * AJAX endpoint to get integrations
     * This is a fallback for when the REST API fails
     */
    public function ajaxGetIntegrations()
    {
        // Check if user has permission
        if (!current_user_can('manage_options')) {
            wp_send_json_error([
                'message' => __('You do not have permission to access this endpoint.', 'fleekdash')
            ], 403);
            return;
        }

        // Get integrations data
        $integrations = $this->getIntegrationsData();

        // Send response
        wp_send_json_success($integrations);
    }

    /**
     * Get integrations data
     *
     * @return array
     */
    private function getIntegrationsData()
    {
        // Initialize with empty arrays for each category
        $integrations = [
            'plugin' => [],
            'theme' => [],
            'api' => [],
        ];

        // Get all registered integrations
        $all_integrations = $this->registry->getAll();

        // If no integrations are registered, return the empty structure
        if (empty($all_integrations)) {
            return $integrations;
        }

        // Process each integration by category
        foreach ($all_integrations as $category => $category_integrations) {
            // Skip if category doesn't exist in our structure
            if (!isset($integrations[$category])) {
                $integrations[$category] = [];
            }

            foreach ($category_integrations as $integration) {
                $data = $integration->getData();
                $integrations[$category][] = $data;
            }
        }

        return $integrations;
    }

    /**
     * Get all integrations
     *
     * @return \WP_REST_Response
     */
    public function getIntegrations()
    {
        return rest_ensure_response($this->getIntegrationsData());
    }

    /**
     * Get integrations by category
     *
     * @param \WP_REST_Request $request REST request
     * @return \WP_REST_Response
     */
    public function getIntegrationsByCategory($request)
    {
        $category = $request->get_param('category');
        $integrations = [];

        foreach ($this->registry->getByCategory($category) as $integration) {
            $data = $integration->getData();
            $integrations[] = $data;
        }

        return rest_ensure_response($integrations);
    }

    /**
     * Get a specific integration
     *
     * @param \WP_REST_Request $request REST request
     * @return \WP_REST_Response|\WP_Error
     */
    public function getIntegration($request)
    {
        $category = $request->get_param('category');
        $id = $request->get_param('id');

        $integration = $this->registry->get($id, $category);

        if (!$integration) {
            return new \WP_Error(
                'integration_not_found',
                __('Integration not found', 'fleekdash'),
                ['status' => 404],
            );
        }

        return rest_ensure_response($integration->getData());
    }

    /**
     * Activate an integration
     *
     * @param \WP_REST_Request $request REST request
     * @return \WP_REST_Response|\WP_Error
     */
    public function activateIntegration($request)
    {
        $id = $request->get_param('id');
        $category_param = $request->get_param('category'); // May be null from URL

        // Try to find the integration in all categories if category is not provided
        $integration = null;
        $actual_category = null;

        if ($category_param) {
            $integration = $this->registry->get($id, $category_param);
            $actual_category = $category_param;
        } else {
            // Search in all categories
            foreach (['api', 'app', 'plugin', 'theme'] as $cat) {
                $integration = $this->registry->get($id, $cat);
                if ($integration) {
                    $actual_category = $cat;
                    break;
                }
            }
        }

        if (!$integration) {
            error_log('IntegrationManager::activate - Integration not found');
            return new \WP_Error(
                'integration_not_found',
                __('Integration not found', 'fleekdash'),
                ['status' => 404],
            );
        }

        if (!$integration->isAvailable()) {
            return new \WP_Error(
                'integration_not_available',
                __('Integration is not available', 'fleekdash'),
                ['status' => 400],
            );
        }

        // Get the category from the integration itself if still not set
        if (!$actual_category) {
            $integration_data = $integration->getData();
            $actual_category = $integration_data['category'] ?? 'api';
        }

        // Get current active integrations
        $active_integrations = get_option('fleekdash_active_integrations', []);

        // Initialize category if not exists
        if (!isset($active_integrations[$actual_category])) {
            $active_integrations[$actual_category] = [];
        }

        // Add integration to active list if not already active
        if (!in_array($id, $active_integrations[$actual_category], true)) {
            $active_integrations[$actual_category][] = $id;

            error_log('IntegrationManager::activate - Saving to DB');
            update_option('fleekdash_active_integrations', $active_integrations);
        }

        // Initialize the integration
        $integration->init();
        $integration->registerHooks();

        return rest_ensure_response([
            'success' => true,
            'message' => __('Integration activated successfully', 'fleekdash'),
            'data' => $integration->getData(),
        ]);
    }

    /**
     * Deactivate an integration
     *
     * @param \WP_REST_Request $request REST request
     * @return \WP_REST_Response|\WP_Error
     */
    public function deactivateIntegration($request)
    {
        $id = $request->get_param('id');
        $category_param = $request->get_param('category'); // May be null from URL

        [$integration, $actual_category] = $this->resolveIntegrationAndCategory($id, $category_param);

        $active_integrations = get_option('fleekdash_active_integrations', []);
        $active_integrations = is_array($active_integrations) ? $active_integrations : [];
        $active_integrations = $this->removeIntegrationFromActiveList($active_integrations, $id, $actual_category);

        update_option('fleekdash_active_integrations', $active_integrations);

        $data = $integration ? $integration->getData() : ['id' => $id, 'status' => 'deactivated'];

        return rest_ensure_response([
            'success' => true,
            'message' => __('Integration deactivated successfully', 'fleekdash'),
            'data' => $data,
        ]);
    }

    /**
     * Resolve integration instance and category from request params
     *
     * @param string $id Integration ID
     * @param string|null $category_param Category from URL (may be null)
     * @return array{0: object|null, 1: string}
     */
    private function resolveIntegrationAndCategory(string $id, ?string $category_param): array
    {
        $integration = null;
        $actual_category = null;

        if ($category_param) {
            $integration = $this->registry->get($id, $category_param);
            $actual_category = $category_param;
        } else {
            foreach (['api', 'app', 'plugin', 'theme'] as $cat) {
                $integration = $this->registry->get($id, $cat);
                if ($integration) {
                    $actual_category = $cat;
                    break;
                }
            }
        }

        if (!$integration) {
            $actual_category = $category_param ?: 'api';
        }

        return [$integration, $actual_category];
    }

    /**
     * Remove integration ID from active list across all categories
     *
     * @param array<string, string[]> $active_integrations
     * @param string $id Integration ID
     * @param string $actual_category Primary category
     * @return array<string, string[]>
     */
    private function removeIntegrationFromActiveList(array $active_integrations, string $id, string $actual_category): array
    {
        if (isset($active_integrations[$actual_category]) && in_array($id, $active_integrations[$actual_category], true)) {
            $active_integrations[$actual_category] = array_values(array_diff($active_integrations[$actual_category], [$id]));
        }

        foreach ($active_integrations as $key => $value) {
            if (is_array($value)) {
                $active_integrations[$key] = array_values(array_diff($value, [$id]));
                if (empty($active_integrations[$key])) {
                    unset($active_integrations[$key]);
                }
            } elseif ($key === '' || $key === null) {
                unset($active_integrations[$key]);
            }
        }

        return $active_integrations;
    }
}
