<?php
/**
 * RouteGroup Implementation
 *
 * @package Licenzo\Framework\Http\Router
 */

namespace Licenzo\Framework\Http\Router;

use Licenzo\Framework\Contracts\Router\RouteGroup as RouteGroupContract;
use Licenzo\Framework\Contracts\Router\Router;

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

/**
 * RouteGroup implementation for fluent route grouping
 */
class RouteGroup implements RouteGroupContract
{
    /**
     * Router instance
     *
     * @var Router
     */
    protected Router $router;

    /**
     * Group attributes
     *
     * @var array
     */
    protected array $attributes;

    /**
     * Create a new route group instance
     *
     * @param Router $router
     * @param array $attributes
     */
    public function __construct(Router $router, array $attributes = [])
    {
        $this->router = $router;
        $this->attributes = $attributes;
    }

    /**
     * Execute the group callback with current attributes
     *
     * @param \Closure $callback
     * @return void
     */
    public function group(\Closure $callback): void
    {
        $this->router->group($this->attributes, $callback);
    }

    /**
     * Add middleware to the group
     *
     * @param string|array $middleware
     * @return self
     */
    public function middleware(string|array $middleware): self
    {
        $existingMiddleware = $this->attributes['middleware'] ?? [];
        $this->attributes['middleware'] = array_merge(
            $existingMiddleware,
            (array) $middleware
        );
        
        return $this;
    }

    /**
     * Add a policy to the group
     *
     * @param string $policy
     * @return self
     */
    public function policy(string $policy): self
    {
        $this->attributes['policy'] = $policy;
        return $this;
    }

    /**
     * Add a prefix to the group
     *
     * @param string $prefix
     * @return self
     */
    public function prefix(string $prefix): self
    {
        $existingPrefix = $this->attributes['prefix'] ?? '';
        $this->attributes['prefix'] = $this->combinePrefix($existingPrefix, $prefix);
        return $this;
    }

    /**
     * Add a namespace to the group
     *
     * @param string $namespace
     * @return self
     */
    public function namespace(string $namespace): self
    {
        $existingNamespace = $this->attributes['namespace'] ?? '';
        $this->attributes['namespace'] = $this->combineNamespace($existingNamespace, $namespace);
        return $this;
    }

    /**
     * Get the current attributes
     *
     * @return array
     */
    public function getAttributes(): array
    {
        return $this->attributes;
    }

    /**
     * Set an attribute
     *
     * @param string $key
     * @param mixed $value
     * @return self
     */
    public function setAttribute(string $key, $value): self
    {
        $this->attributes[$key] = $value;
        return $this;
    }

    /**
     * Get an attribute
     *
     * @param string $key
     * @param mixed $default
     * @return mixed
     */
    public function getAttribute(string $key, $default = null)
    {
        return $this->attributes[$key] ?? $default;
    }

    /**
     * Check if attribute exists
     *
     * @param string $key
     * @return bool
     */
    public function hasAttribute(string $key): bool
    {
        return isset($this->attributes[$key]);
    }

    /**
     * Combine prefixes properly
     *
     * @param string $existing
     * @param string $new
     * @return string
     */
    protected function combinePrefix(string $existing, string $new): string
    {
        $existing = trim($existing, '/');
        $new = trim($new, '/');
        
        if (empty($existing)) {
            return $new;
        }
        
        if (empty($new)) {
            return $existing;
        }
        
        return $existing . '/' . $new;
    }

    /**
     * Combine namespaces properly
     *
     * @param string $existing
     * @param string $new
     * @return string
     */
    protected function combineNamespace(string $existing, string $new): string
    {
        $existing = trim($existing, '\\');
        $new = trim($new, '\\');
        
        if (empty($existing)) {
            return $new;
        }
        
        if (empty($new)) {
            return $existing;
        }
        
        return $existing . '\\' . $new;
    }

    /**
     * Create a new group with merged attributes
     *
     * @param array $attributes
     * @return self
     */
    public function merge(array $attributes): self
    {
        $mergedAttributes = array_merge($this->attributes, $attributes);
        
        // Special handling for middleware - merge arrays
        if (isset($this->attributes['middleware']) && isset($attributes['middleware'])) {
            $mergedAttributes['middleware'] = array_merge(
                (array) $this->attributes['middleware'],
                (array) $attributes['middleware']
            );
        }
        
        // Special handling for prefix - combine properly
        if (isset($this->attributes['prefix']) && isset($attributes['prefix'])) {
            $mergedAttributes['prefix'] = $this->combinePrefix(
                $this->attributes['prefix'],
                $attributes['prefix']
            );
        }
        
        // Special handling for namespace - combine properly
        if (isset($this->attributes['namespace']) && isset($attributes['namespace'])) {
            $mergedAttributes['namespace'] = $this->combineNamespace(
                $this->attributes['namespace'],
                $attributes['namespace']
            );
        }
        
        return new static($this->router, $mergedAttributes);
    }
}
