<?php

declare(strict_types=1);

namespace App\Framework\Discovery\Processing;

use App\Framework\Core\ValueObjects\ClassName;
use App\Framework\Filesystem\File;
use App\Framework\Filesystem\FileSystemService;
use App\Framework\Tokenizer\Discovery\DiscoveryTokenizer;
use Throwable;

/**
 * Modern class extractor using the tokenizer module
 * More accurate than regex-based extraction
 */
final readonly class ClassExtractor
{
    public function __construct(
        private FileSystemService $fileSystemService,
        private DiscoveryTokenizer $tokenizer = new DiscoveryTokenizer()
    ) {
    }

    /**
     * Extract class names from a file using tokenizer
     * @return array<ClassName>
     */
    public function extractFromFile(File $file): array
    {
        try {
            $content = $this->fileSystemService->readFile($file);

            // Skip files without PHP tags (e.g., pure HTML templates)
            // This prevents HTML tags from being misinterpreted as PHP classes
            if (! $this->containsPhpCode($content)) {
                return [];
            }

            $classes = $this->tokenizer->extractClasses($content);

            return array_map(
                fn ($class) => ClassName::create($class['fqn']),
                $classes
            );

        } catch (Throwable) {
            // Silently fail for files that can't be processed
            return [];
        }
    }

    /**
     * Check if content contains actual PHP code
     */
    private function containsPhpCode(string $content): bool
    {
        $trimmed = trim($content);

        return str_starts_with($trimmed, '<?php') || str_starts_with($trimmed, '<?=');
    }

    /**
     * Extract detailed class information with metadata
     * @return array<array{type: string, name: string, namespace: ?string, fqn: string, line: int}>
     */
    public function extractDetailedFromFile(File $file): array
    {
        try {
            $content = $this->fileSystemService->readFile($file);

            // Skip files without PHP tags
            if (! $this->containsPhpCode($content)) {
                return [];
            }

            return $this->tokenizer->extractClasses($content);

        } catch (Throwable) {
            return [];
        }
    }

    /**
     * Extract functions and methods from file
     * @return array<array{name: string, type: string, class: ?string, namespace: ?string, line: int, visibility: string}>
     */
    public function extractFunctionsFromFile(File $file): array
    {
        try {
            $content = $this->fileSystemService->readFile($file);

            // Skip files without PHP tags
            if (! $this->containsPhpCode($content)) {
                return [];
            }

            return $this->tokenizer->extractFunctions($content);

        } catch (Throwable) {
            return [];
        }
    }

    /**
     * Extract attributes from file
     * @return array<array{name: string, context: string, line: int, target: string}>
     */
    public function extractAttributesFromFile(File $file): array
    {
        try {
            $content = $this->fileSystemService->readFile($file);

            // Skip files without PHP tags
            if (! $this->containsPhpCode($content)) {
                return [];
            }

            return $this->tokenizer->extractAttributes($content);

        } catch (Throwable) {
            return [];
        }
    }

    /**
     * Extract use statements from file
     * @return array<array{class: string, alias: ?string, line: int}>
     */
    public function extractUseStatementsFromFile(File $file): array
    {
        try {
            $content = $this->fileSystemService->readFile($file);

            // Skip files without PHP tags
            if (! $this->containsPhpCode($content)) {
                return [];
            }

            return $this->tokenizer->extractUseStatements($content);

        } catch (Throwable) {
            return [];
        }
    }

    /**
     * Check if file likely contains PHP classes (quick check)
     */
    public function likelyContainsClasses(string $content): bool
    {
        // Quick checks to avoid tokenization on files that definitely don't have classes
        if (strlen($content) < 10) {
            return false;
        }

        // Must have PHP opening tag
        if (! str_contains($content, '<?php')) {
            return false;
        }

        // Check for class-like keywords
        $keywords = ['class ', 'interface ', 'trait ', 'enum '];
        foreach ($keywords as $keyword) {
            if (str_contains($content, $keyword)) {
                return true;
            }
        }

        return false;
    }

    /**
     * Extract complete file analysis
     */
    public function analyzeFile(File $file): array
    {
        try {
            $content = $this->fileSystemService->readFile($file);

            // Skip files without PHP tags
            if (! $this->containsPhpCode($content)) {
                return [
                    'classes' => [],
                    'functions' => [],
                    'attributes' => [],
                    'uses' => [],
                ];
            }

            return [
                'classes' => $this->tokenizer->extractClasses($content),
                'functions' => $this->tokenizer->extractFunctions($content),
                'attributes' => $this->tokenizer->extractAttributes($content),
                'uses' => $this->tokenizer->extractUseStatements($content),
            ];

        } catch (Throwable) {
            return [
                'classes' => [],
                'functions' => [],
                'attributes' => [],
                'uses' => [],
            ];
        }
    }
}
