<?php
/**
 * Application Builder
 *
 * @package ZenoChatbot\Framework\Foundation
 */

namespace ZenoChatbot\Framework\Foundation;

use Closure;

// Prevent direct access
if (!defined('ABSPATH')) {
    exit;
}

/**
 * Fluent application configuration builder
 */
class ApplicationBuilder
{
    /**
     * Application base path
     *
     * @var string
     */
    protected $basePath;



    /**
     * Service providers
     *
     * @var array
     */
    protected $providers = [];

    /**
     * Exception configuration closure
     *
     * @var Closure|null
     */
    protected $exceptionsClosure = null;

    /**
     * Additional configuration
     *
     * @var array
     */
    protected $config = [];

    /**
     * Constructor
     *
     * @param string $basePath
     */
    public function __construct(string $basePath)
    {
        $this->basePath = $basePath;
    }



    /**
     * Configure service providers
     *
     * @param array $providers
     * @return $this
     */
    public function providers(array $providers): self
    {
        $this->providers = array_merge($this->providers, $providers);
        return $this;
    }

    /**
     * Configure exceptions
     *
     * @param Closure|string $handler
     * @return $this
     */
    public function exceptions($handler): self
    {
        if (is_string($handler)) {
            // Simple handler class registration
            $this->config['exceptions.handler'] = $handler;
        } else {
            // Closure configuration
            $this->exceptionsClosure = $handler;
        }
        return $this;
    }

    /**
     * Set configuration values
     *
     * @param array $config
     * @return $this
     */
    public function config(array $config): self
    {
        $this->config = array_merge($this->config, $config);
        return $this;
    }

    /**
     * Enable debug mode
     *
     * @param bool $debug
     * @return $this
     */
    public function debug(bool $debug = true): self
    {
        $this->config['app.debug'] = $debug;
        return $this;
    }



    /**
     * Configure database
     *
     * @param array $database
     * @return $this
     */
    public function database(array $database): self
    {
        $this->config['database'] = $database;
        return $this;
    }

    /**
     * Configure cache
     *
     * @param array $cache
     * @return $this
     */
    public function cache(array $cache): self
    {
        $this->config['cache'] = $cache;
        return $this;
    }

    /**
     * Configure logging
     *
     * @param array $logging
     * @return $this
     */
    public function logging(array $logging): self
    {
        $this->config['logging'] = $logging;
        return $this;
    }

    /**
     * Add middleware
     *
     * @param array $middleware
     * @return $this
     */
    public function middleware(array $middleware): self
    {
        $this->config['middleware'] = array_merge(
            $this->config['middleware'] ?? [],
            $middleware
        );
        return $this;
    }

    /**
     * Configure assets
     *
     * @param array $assets
     * @return $this
     */
    public function assets(array $assets): self
    {
        $this->config['assets'] = $assets;
        return $this;
    }

    /**
     * Configure hooks
     *
     * @param array $hooks
     * @return $this
     */
    public function hooks(array $hooks): self
    {
        $this->config['hooks'] = $hooks;
        return $this;
    }

    /**
     * Set the request instance
     *
     * @param \ZenoChatbot\Framework\Http\Request $request
     * @return $this
     */
    public function withRequest(\ZenoChatbot\Framework\Http\Request $request)
    {
        $this->config['app.request'] = $request;
        return $this;
    }

    /**
     * Create and configure the application with full preparation
     *
     * @return Application
     */
    public function create(): Application
    {
        // 1. Create minimal application instance
        $app = new Application($this->basePath);

        // 2. Register base container bindings
        $app->registerBaseBindings();

        // 3. Load and bind configuration
        $this->loadConfiguration($app);

        // 4. Register service providers
        $this->registerProviders($app);

        // 5. Configure request handling
        $this->configureRequest($app);

        // 6. Setup exception handling
        $this->configureExceptions($app);

        // 7. Apply builder configuration
        $this->applyConfiguration($app);

        // 8. Register core aliases
        $app->registerCoreContainerAliases();

        return $app;
    }



    /**
     * Load configuration and bind to container
     *
     * @param Application $app
     * @return void
     */
    protected function loadConfiguration(Application $app): void
    {
        // Load config files and store in container
        $configData = $app->loadConfigFiles();
        $app->instance('config', new \ZenoChatbot\Framework\Config\Repository($configData));
    }

    /**
     * Configure request binding
     *
     * @param Application $app
     * @return void
     */
    protected function configureRequest(Application $app): void
    {
        // Register HTTP Request singleton
        $app->singleton(\ZenoChatbot\Framework\Http\Request::class, function() {
            return \ZenoChatbot\Framework\Http\Request::capture();
        });

        // Override with specific request if provided via builder
        if (isset($this->config['app.request'])) {
            $request = $this->config['app.request'];
            $app->instance(\ZenoChatbot\Framework\Http\Request::class, $request);
        }

        // Check if this is a REST request and bind WP_REST_Request if needed
        if (defined('REST_REQUEST') && REST_REQUEST) {
            global $wp_rest_server;
            if ($wp_rest_server && $wp_rest_server->get_request()) {
                $app->instance('wp.rest.request', $wp_rest_server->get_request());
            }
        }
    }

    /**
     * Configure exceptions
     *
     * @param Application $app
     * @return void
     */
    protected function configureExceptions(Application $app): void
    {
        // Register default exception handler
        $app->singleton(\ZenoChatbot\Framework\Exceptions\Handler::class, function($app) {
            return new \ZenoChatbot\Framework\Exceptions\Handler($app);
        });

        // Handle simple handler class registration
        if (isset($this->config['exceptions.handler'])) {
            $handlerClass = $this->config['exceptions.handler'];
            $app->singleton($handlerClass);
            $app->alias($handlerClass, 'exception.handler');
        }

        // Handle closure configuration
        if ($this->exceptionsClosure) {
            $exceptions = new \ZenoChatbot\Framework\Foundation\Configuration\Exceptions($app);
            call_user_func($this->exceptionsClosure, $exceptions);
            $exceptions->apply();
        }
    }

    /**
     * Register service providers
     *
     * @param Application $app
     * @return void
     */
    protected function registerProviders(Application $app): void
    {
        foreach ($this->providers as $provider) {
            $app->register($provider);
        }
    }

    /**
     * Apply builder configuration
     *
     * @param Application $app
     * @return void
     */
    protected function applyConfiguration(Application $app): void
    {
        // Configuration is now loaded from files and stored as read-only
        // Builder-specific config (like debug mode) is applied via other means

        // Apply debug mode if set
        if (isset($this->config['app.debug'])) {
            // Store debug setting in a way the app can access it
            $app->instance('app.debug', $this->config['app.debug']);
        }

        // Other builder config can be applied here as needed
        // Note: File-based config is read-only, builder config is for runtime overrides
    }

    /**
     * Get base path
     *
     * @return string
     */
    public function getBasePath(): string
    {
        return $this->basePath;
    }



    /**
     * Get providers configuration
     *
     * @return array
     */
    public function getProviders(): array
    {
        return $this->providers;
    }

    /**
     * Get configuration
     *
     * @return array
     */
    public function getConfig(): array
    {
        return $this->config;
    }
}
