<?php

declare(strict_types=1);

namespace App\Framework\Mcp\ValueObjects;

/**
 * Value Object representing a codebase analysis query
 */
final readonly class CodebaseQuery
{
    /**
     * @param array<string> $patterns Text patterns to search for
     * @param array<class-string> $attributeTypes Attribute classes to discover
     * @param array<class-string> $interfaceTypes Interface implementations to find
     * @param array<string> $classNamePatterns Class name patterns (e.g., "*Controller", "*Service")
     * @param array<string> $directories Specific directories to search in
     * @param array<string> $excludeDirectories Directories to exclude from search
     * @param bool $includeTests Whether to include test files
     * @param bool $includeVendor Whether to include vendor files
     * @param int $maxResults Maximum number of results to return
     */
    public function __construct(
        public array $patterns = [],
        public array $attributeTypes = [],
        public array $interfaceTypes = [],
        public array $classNamePatterns = [],
        public array $directories = [],
        public array $excludeDirectories = ['vendor', 'var', 'storage', 'public'],
        public bool $includeTests = false,
        public bool $includeVendor = false,
        public int $maxResults = 1000
    ) {
    }

    public static function forControllers(): self
    {
        return new self(
            attributeTypes: [\App\Framework\Attributes\Route::class],
            classNamePatterns: ['*Controller']
        );
    }

    public static function forRoutes(): self
    {
        return new self(
            attributeTypes: [\App\Framework\Attributes\Route::class]
        );
    }

    public static function forServices(): self
    {
        return new self(
            classNamePatterns: ['*Service', '*Manager', '*Repository']
        );
    }

    public static function forValueObjects(): self
    {
        return new self(
            classNamePatterns: ['*VO', '*ValueObject'],
            directories: ['src/Framework/Core/ValueObjects', 'src/Domain']
        );
    }

    public static function forInitializers(): self
    {
        return new self(
            attributeTypes: [\App\Framework\Attributes\Initializer::class],
            interfaceTypes: [\App\Framework\DI\Initializer::class]
        );
    }

    public static function forMcpTools(): self
    {
        return new self(
            attributeTypes: [\App\Framework\Mcp\McpTool::class]
        );
    }

    public static function forCommands(): self
    {
        return new self(
            attributeTypes: [\App\Framework\Console\Attributes\ConsoleCommand::class]
        );
    }

    public static function forEventHandlers(): self
    {
        return new self(
            attributeTypes: [\App\Framework\EventBus\Attributes\EventHandler::class]
        );
    }

    /**
     * Create a custom query from array parameters
     */
    public static function fromArray(array $params): self
    {
        return new self(
            patterns: $params['patterns'] ?? [],
            attributeTypes: $params['attribute_types'] ?? [],
            interfaceTypes: $params['interface_types'] ?? [],
            classNamePatterns: $params['class_name_patterns'] ?? [],
            directories: $params['directories'] ?? [],
            excludeDirectories: $params['exclude_directories'] ?? ['vendor', 'var', 'storage', 'public'],
            includeTests: $params['include_tests'] ?? false,
            includeVendor: $params['include_vendor'] ?? false,
            maxResults: $params['max_results'] ?? 1000
        );
    }

    public function isEmpty(): bool
    {
        return empty($this->patterns)
            && empty($this->attributeTypes)
            && empty($this->interfaceTypes)
            && empty($this->classNamePatterns);
    }

    public function hasAttributeSearch(): bool
    {
        return ! empty($this->attributeTypes);
    }

    public function hasInterfaceSearch(): bool
    {
        return ! empty($this->interfaceTypes);
    }

    public function hasPatternSearch(): bool
    {
        return ! empty($this->patterns) || ! empty($this->classNamePatterns);
    }

    public function toArray(): array
    {
        return [
            'patterns' => $this->patterns,
            'attribute_types' => $this->attributeTypes,
            'interface_types' => $this->interfaceTypes,
            'class_name_patterns' => $this->classNamePatterns,
            'directories' => $this->directories,
            'exclude_directories' => $this->excludeDirectories,
            'include_tests' => $this->includeTests,
            'include_vendor' => $this->includeVendor,
            'max_results' => $this->maxResults,
        ];
    }
}
