<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use Illuminate\Support\Facades\File;

class ValidateControllerImports extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'validate:imports 
                            {--fix : Attempt to automatically fix missing imports}
                            {--module= : Only check specific module}
                            {--detailed : Show detailed output}';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Validate that all controllers have proper imports for classes they use';

    /**
     * Execute the console command.
     *
     * @return int
     */
    public function handle()
    {
        $this->info('🔍 Scanning controllers for missing imports...');
        $this->newLine();

        $controllerPaths = $this->getControllerPaths();
        $errors = [];
        $scannedCount = 0;

        foreach ($controllerPaths as $path) {
            $relativePath = str_replace(base_path() . DIRECTORY_SEPARATOR, '', $path);
            
            if ($this->option('detailed')) {
                $this->line("📂 Scanning: {$relativePath}");
            }
            
            $controllerErrors = $this->validateControllerImports($path, $relativePath);
            $errors = array_merge($errors, $controllerErrors);
            $scannedCount++;
        }

        $this->newLine();
        $this->info("📊 Scanned {$scannedCount} controller files");

        if (empty($errors)) {
            $this->info('✅ All controllers have proper imports!');
            return Command::SUCCESS;
        }

        $this->error("❌ Found " . count($errors) . " missing imports:");
        $this->newLine();

        $groupedErrors = $this->groupErrorsByFile($errors);

        foreach ($groupedErrors as $file => $fileErrors) {
            $this->warn("📄 {$file}");
            foreach ($fileErrors as $error) {
                $this->line("   ❌ Missing: {$error['class']} (line {$error['line']})");
                if ($this->option('detailed')) {
                    $this->line("      Context: " . trim($error['context']));
                }
            }
            $this->newLine();

            if ($this->option('fix')) {
                $this->attemptFix($file, $fileErrors);
            }
        }

        if ($this->option('fix')) {
            $this->info('🔧 Automatic fix attempts completed. Please review the changes.');
        } else {
            $this->info('💡 Run with --fix to attempt automatic fixes');
        }

        return Command::FAILURE;
    }

    /**
     * Get all controller file paths.
     *
     * @return array
     */
    private function getControllerPaths(): array
    {
        $paths = [];
        $module = $this->option('module');
        
        if ($module) {
            // Only scan specific module
            $moduleDir = app_path("Modules/{$module}/controllers");
            if (File::isDirectory($moduleDir)) {
                $paths = File::allFiles($moduleDir);
            } else {
                $this->error("Module '{$module}' not found or has no controllers directory");
                return [];
            }
        } else {
            // Main controllers
            if (File::isDirectory(app_path('Http/Controllers'))) {
                $paths = array_merge($paths, File::allFiles(app_path('Http/Controllers')));
            }
            
            // All module controllers
            if (File::isDirectory(app_path('Modules'))) {
                $moduleDirs = File::directories(app_path('Modules'));
                foreach ($moduleDirs as $moduleDir) {
                    $controllerDir = $moduleDir . '/controllers';
                    if (File::isDirectory($controllerDir)) {
                        $paths = array_merge($paths, File::allFiles($controllerDir));
                    }
                }
            }
        }

        // Filter only PHP files
        return array_filter($paths, function ($file) {
            return $file->getExtension() === 'php';
        });
    }

    /**
     * Validate imports for a single controller file.
     *
     * @param string $filePath
     * @param string $relativePath
     * @return array
     */
    private function validateControllerImports(string $filePath, string $relativePath): array
    {
        $errors = [];
        $content = File::get($filePath);
        
        if (!$this->isController($content)) {
            return $errors;
        }

        $imports = $this->extractImports($content);
        $namespace = $this->extractNamespace($content);
        $usedClasses = $this->extractUsedClasses($content);

        foreach ($usedClasses as $classInfo) {
            $className = $classInfo['class'];
            $line = $classInfo['line'];
            $context = $classInfo['context'];

            // Skip built-in classes
            if ($this->isBuiltInClass($className)) {
                continue;
            }

            // Skip if already imported
            if ($this->isImported($className, $imports, $namespace)) {
                continue;
            }

            // Find possible import path
            $possibleImport = $this->findClassImportPath($className);
            if ($possibleImport) {
                $errors[] = [
                    'file' => $relativePath,
                    'class' => $className,
                    'line' => $line,
                    'context' => $context,
                    'suggested_import' => $possibleImport
                ];
            }
        }

        return $errors;
    }

    /**
     * Attempt to automatically fix missing imports.
     *
     * @param string $file
     * @param array $errors
     * @return void
     */
    private function attemptFix(string $file, array $errors): void
    {
        $fullPath = base_path($file);
        $content = File::get($fullPath);
        $lines = explode("\n", $content);
        
        // Find the last use statement or namespace line
        $insertLine = 0;
        for ($i = 0; $i < count($lines); $i++) {
            if (preg_match('/^use\s/', trim($lines[$i]))) {
                $insertLine = $i + 1;
            } elseif (preg_match('/^namespace\s/', trim($lines[$i]))) {
                $insertLine = $i + 1;
            }
        }

        // Add missing imports
        $newImports = [];
        foreach ($errors as $error) {
            if (isset($error['suggested_import'])) {
                $newImports[] = "use {$error['suggested_import']};";
            }
        }

        if (!empty($newImports)) {
            // Insert imports
            array_splice($lines, $insertLine, 0, $newImports);
            
            // Write back to file
            File::put($fullPath, implode("\n", $lines));
            
            $this->info("   🔧 Added " . count($newImports) . " imports to {$file}");
        }
    }

    /**
     * Find the correct import path for a class.
     *
     * @param string $className
     * @return string|null
     */
    private function findClassImportPath(string $className): ?string
    {
        // Common locations to search
        $searchPaths = [
            app_path("Models/{$className}.php") => "App\\Models\\{$className}",
            app_path("Modules/*/models/{$className}.php") => null, // Will be resolved dynamically
            app_path("Modules/*/{$className}.php") => null,
        ];

        foreach ($searchPaths as $pattern => $namespace) {
            $files = glob($pattern);
            foreach ($files as $file) {
                if ($namespace === null) {
                    // Extract namespace from file
                    $content = File::get($file);
                    if (preg_match('/namespace\s+([^;]+);/', $content, $matches)) {
                        return trim($matches[1]) . "\\{$className}";
                    }
                } else {
                    return $namespace;
                }
            }
        }

        return null;
    }

    /**
     * Group errors by file.
     *
     * @param array $errors
     * @return array
     */
    private function groupErrorsByFile(array $errors): array
    {
        $grouped = [];
        foreach ($errors as $error) {
            $grouped[$error['file']][] = $error;
        }
        return $grouped;
    }

    // Include all the helper methods from the test class
    private function isController(string $content): bool
    {
        return preg_match('/class\s+\w+.*Controller/i', $content) || 
               preg_match('/extends\s+.*Controller/i', $content);
    }

    private function extractImports(string $content): array
    {
        $imports = [];
        $lines = explode("\n", $content);
        
        foreach ($lines as $line) {
            if (preg_match('/^use\s+([^;]+);/', trim($line), $matches)) {
                $fullImport = trim($matches[1]);
                
                if (preg_match('/(.+)\s+as\s+(.+)/', $fullImport, $aliasMatches)) {
                    $imports[trim($aliasMatches[2])] = trim($aliasMatches[1]);
                } else {
                    $className = substr(strrchr($fullImport, '\\'), 1) ?: $fullImport;
                    $imports[$className] = $fullImport;
                }
            }
        }
        
        return $imports;
    }

    private function extractNamespace(string $content): ?string
    {
        if (preg_match('/namespace\s+([^;]+);/', $content, $matches)) {
            return trim($matches[1]);
        }
        return null;
    }

    private function extractUsedClasses(string $content): array
    {
        $classes = [];
        $lines = explode("\n", $content);
        
        foreach ($lines as $lineNumber => $line) {
            if (preg_match('/^\s*(\/\/|\/\*|\*|use\s)/', $line)) {
                continue;
            }

            $patterns = [
                '/([A-Z][a-zA-Z0-9_]*)::[a-zA-Z_]/m',
                '/new\s+([A-Z][a-zA-Z0-9_]*)/m',
                '/function\s+\w+\([^)]*([A-Z][a-zA-Z0-9_]*)\s+\$/m',
                '/instanceof\s+([A-Z][a-zA-Z0-9_]*)/m',
                '/([A-Z][a-zA-Z0-9_]*)::[A-Z_]+/m',
                '/([A-Z][a-zA-Z0-9_]*)::(find|create|where|first|get|all|paginate|query|with|select|join|orderBy|groupBy|update|delete|destroy)\s*\(/m'
            ];

            foreach ($patterns as $pattern) {
                if (preg_match_all($pattern, $line, $matches, PREG_OFFSET_CAPTURE)) {
                    foreach ($matches[1] as $match) {
                        $className = $match[0];
                        
                        if ($this->isValidClassName($className)) {
                            $classes[] = [
                                'class' => $className,
                                'line' => $lineNumber + 1,
                                'context' => $line
                            ];
                        }
                    }
                }
            }
        }

        return array_unique($classes, SORT_REGULAR);
    }

    private function isValidClassName(string $className): bool
    {
        if (!preg_match('/^[A-Z]/', $className)) {
            return false;
        }

        $skipList = [
            'Auth', 'Log', 'DB', 'App', 'URL', 'View', 'Input', 'Session', 'Cache', 'Config',
            'Request', 'Response', 'Redirect', 'File', 'Storage', 'Mail', 'Queue', 'Event',
            'Carbon', 'Collection', 'Exception', 'Closure', 'Route', 'Schema', 'Artisan',
            'PDF', 'Excel', 'Zipper', 'Messenger', 'Hash', 'Str', 'Validator'
        ];

        return !in_array($className, $skipList);
    }

    private function isBuiltInClass(string $className): bool
    {
        $builtInClasses = [
            'DateTime', 'DateTimeImmutable', 'Exception', 'PDO', 'PDOException',
            'Closure', 'Generator', 'ArrayObject', 'SplFileInfo', 'ReflectionClass',
            'stdClass', 'Throwable', 'Error', 'ParseError', 'TypeError'
        ];

        return in_array($className, $builtInClasses) || 
               class_exists($className) ||
               interface_exists($className);
    }

    private function isImported(string $className, array $imports, ?string $namespace): bool
    {
        if (isset($imports[$className])) {
            return true;
        }

        if ($namespace) {
            $fullClassName = $namespace . '\\' . $className;
            if (class_exists($fullClassName)) {
                return true;
            }
        }

        return false;
    }
} 