<?php

namespace App\Console\Commands;

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

class MakeModule extends Command
{
    /**
     * The name and signature of the console command.
     */
    protected $signature = 'make:module 
                           {name : The name of the module}
                           {--commands=* : List of commands this module should handle}
                           {--callbacks=* : List of callback prefixes this module should handle}
                           {--dependencies=* : List of module dependencies}
                           {--no-service : Do not create a service class}
                           {--no-config : Do not create a config file}';

    /**
     * The console command description.
     */
    protected $description = 'Create a new Telegram bot module with all necessary files';

    /**
     * Execute the console command.
     */
    public function handle()
    {
        $name = $this->argument('name');
        $className = Str::studly($name) . 'Module';
        $serviceName = Str::studly($name) . 'Service';
        $namespace = 'App\\Modules\\' . Str::studly($name);
        
        $this->info("Creating module: {$className}");

        // Create module directory structure
        $this->createDirectoryStructure($name);

        // Create module class
        $this->createModuleClass($name, $className, $namespace);

        // Create service class (if requested)
        if (!$this->option('no-service')) {
            $this->createServiceClass($name, $serviceName, $namespace);
        }

        // Create configuration file (if requested)
        if (!$this->option('no-config')) {
            $this->createConfigFile($name);
        }

        // Create migration
        $this->createMigration($name);

        // Create Filament resource
        $this->createFilamentResource($name);

        // Update module registration
        $this->updateModuleRegistration($className, $namespace);

        $this->info("Module {$className} created successfully!");
        $this->displayNextSteps($name);
    }

    /**
     * Create directory structure for the module
     */
    private function createDirectoryStructure(string $name): void
    {
        $studlyName = Str::studly($name);
        
        $directories = [
            "app/Modules/{$studlyName}",
            "app/Services/{$studlyName}",
            "config/modules",
            "database/migrations",
        ];

        foreach ($directories as $directory) {
            if (!File::isDirectory(base_path($directory))) {
                File::makeDirectory(base_path($directory), 0755, true);
                $this->line("Created directory: {$directory}");
            }
        }
    }

    /**
     * Create the main module class
     */
    private function createModuleClass(string $name, string $className, string $namespace): void
    {
        $commands = $this->option('commands') ?: ['/example'];
        $callbacks = $this->option('callbacks') ?: ['example_'];
        $dependencies = $this->option('dependencies') ?: [];

        $stub = $this->getModuleStub();
        $content = str_replace(
            [
                '{{namespace}}',
                '{{className}}',
                '{{moduleName}}',
                '{{commands}}',
                '{{callbacks}}',
                '{{dependencies}}',
                '{{serviceName}}',
                '{{hasService}}'
            ],
            [
                $namespace,
                $className,
                Str::snake($name),
                $this->formatArrayForStub($commands),
                $this->formatArrayForStub($callbacks),
                $this->formatArrayForStub($dependencies),
                Str::studly($name) . 'Service',
                !$this->option('no-service') ? 'true' : 'false'
            ],
            $stub
        );

        $filePath = app_path("Modules/" . Str::studly($name) . "/{$className}.php");
        File::put($filePath, $content);
        $this->line("Created module class: {$filePath}");
    }

    /**
     * Create the service class
     */
    private function createServiceClass(string $name, string $serviceName, string $moduleNamespace): void
    {
        $serviceNamespace = 'App\\Services\\' . Str::studly($name);
        $stub = $this->getServiceStub();
        
        $content = str_replace(
            [
                '{{namespace}}',
                '{{className}}',
                '{{moduleName}}'
            ],
            [
                $serviceNamespace,
                $serviceName,
                Str::snake($name)
            ],
            $stub
        );

        $filePath = app_path("Services/" . Str::studly($name) . "/{$serviceName}.php");
        File::put($filePath, $content);
        $this->line("Created service class: {$filePath}");
    }

    /**
     * Create configuration file
     */
    private function createConfigFile(string $name): void
    {
        $stub = $this->getConfigStub();
        $content = str_replace('{{moduleName}}', Str::snake($name), $stub);

        $filePath = config_path("modules/{$name}.php");
        File::put($filePath, $content);
        $this->line("Created config file: {$filePath}");
    }

    /**
     * Create database migration
     */
    private function createMigration(string $name): void
    {
        $timestamp = now()->format('Y_m_d_His');
        $migrationName = "create_{$name}_tables";
        $className = Str::studly($migrationName);

        $stub = $this->getMigrationStub();
        $content = str_replace(
            [
                '{{className}}',
                '{{tableName}}',
                '{{moduleName}}'
            ],
            [
                $className,
                Str::snake(Str::plural($name)),
                Str::snake($name)
            ],
            $stub
        );

        $filePath = database_path("migrations/{$timestamp}_{$migrationName}.php");
        File::put($filePath, $content);
        $this->line("Created migration: {$filePath}");
    }

    /**
     * Create Filament resource
     */
    private function createFilamentResource(string $name): void
    {
        $this->call('make:filament-resource', [
            'name' => Str::studly($name),
            '--generate' => true,
        ]);
    }

    /**
     * Update module registration
     */
    private function updateModuleRegistration(string $className, string $namespace): void
    {
        $providerPath = app_path('Providers/ModuleServiceProvider.php');
        
        if (!File::exists($providerPath)) {
            $this->createModuleServiceProvider();
        }

        // Add import and registration
        $content = File::get($providerPath);
        
        // Add use statement
        if (!str_contains($content, "use {$namespace}\\{$className};")) {
            $content = str_replace(
                "<?php\n\nnamespace App\\Providers;",
                "<?php\n\nnamespace App\\Providers;\n\nuse {$namespace}\\{$className};",
                $content
            );
        }

        // Add registration
        $registration = "\$moduleManager->registerModule(app({$className}::class));";
        if (!str_contains($content, $registration)) {
            $content = str_replace(
                '// Register modules here',
                "// Register modules here\n        {$registration}",
                $content
            );
        }

        File::put($providerPath, $content);
        $this->line("Updated module registration in: {$providerPath}");
    }

    /**
     * Create ModuleServiceProvider if it doesn't exist
     */
    private function createModuleServiceProvider(): void
    {
        $stub = $this->getModuleServiceProviderStub();
        $filePath = app_path('Providers/ModuleServiceProvider.php');
        File::put($filePath, $stub);
        $this->line("Created ModuleServiceProvider: {$filePath}");
    }

    /**
     * Display next steps to the user
     */
    private function displayNextSteps(string $name): void
    {
        $this->newLine();
        $this->info('Next steps:');
        $this->line('1. Run migration: php artisan migrate');
        $this->line('2. Update your .env with module configuration');
        $this->line("3. Implement your module logic in app/Modules/" . Str::studly($name));
        $this->line('4. Register the module service provider in config/app.php');
        $this->line('5. Test your module with the Telegram bot');
        $this->newLine();
    }

    /**
     * Format array for stub replacement
     */
    private function formatArrayForStub(array $items): string
    {
        if (empty($items)) {
            return '[]';
        }

        $formatted = array_map(fn($item) => "'{$item}'", $items);
        return '[' . implode(', ', $formatted) . ']';
    }

    /**
     * Get module class stub
     */
    private function getModuleStub(): string
    {
        return '<?php

namespace {{namespace}};

use App\Contracts\TelegramModuleInterface;
use App\DTOs\TelegramMessage;
use App\DTOs\TelegramCallback;
use App\DTOs\TelegramResponse;
use App\Models\User;
use Illuminate\Support\Facades\Log;' . (
            !$this->option('no-service') ? "\nuse App\\Services\\{{serviceName}};" : ''
        ) . '

class {{className}} implements TelegramModuleInterface
{' . (
            !$this->option('no-service') ? "
    private {{serviceName}} \$service;

    public function __construct({{serviceName}} \$service)
    {
        \$this->service = \$service;
    }" : ''
        ) . '

    public function getModuleName(): string
    {
        return \'{{moduleName}}\';
    }

    public function getModuleVersion(): string
    {
        return \'1.0.0\';
    }

    public function getDependencies(): array
    {
        return {{dependencies}};
    }

    public function handleMessage(TelegramMessage $message): ?TelegramResponse
    {
        // Handle commands
        return match($message->text) {
            // Add your command handlers here
            default => null,
        };
    }

    public function handleCallback(TelegramCallback $callback): ?TelegramResponse
    {
        // Handle callbacks
        $callbacks = {{callbacks}};
        
        foreach ($callbacks as $prefix) {
            if (str_starts_with($callback->data, $prefix)) {
                return $this->handleSpecificCallback($callback);
            }
        }
        
        return null;
    }

    public function getConfigurationSchema(): array
    {
        return [
            \'enabled\' => [\'type\' => \'boolean\', \'default\' => true],
            // Add your configuration schema here
        ];
    }

    public function install(): void
    {
        Log::info(\'{{className}} installed\');
    }

    public function uninstall(): void
    {
        Log::info(\'{{className}} uninstalled\');
    }

    public function isEnabled(): bool
    {
        return config(\'modules.{{moduleName}}.enabled\', true);
    }

    public function getPriority(): int
    {
        return 50; // Medium priority
    }

    /**
     * Handle specific callback logic
     */
    private function handleSpecificCallback(TelegramCallback $callback): ?TelegramResponse
    {
        // Implement your callback handling logic here
        return new TelegramResponse(\'Callback handled!\');
    }
}';
    }

    /**
     * Get service class stub
     */
    private function getServiceStub(): string
    {
        return '<?php

namespace {{namespace}};

use App\Models\User;
use Illuminate\Support\Facades\Log;

class {{className}}
{
    /**
     * Initialize the service
     */
    public function __construct()
    {
        // Service initialization
    }

    /**
     * Example service method
     */
    public function performAction(User $user, array $data = []): array
    {
        try {
            // Implement your service logic here
            
            Log::info(\'{{moduleName}} action performed\', [
                \'user_id\' => $user->id,
                \'data\' => $data
            ]);

            return [
                \'success\' => true,
                \'message\' => \'Action completed successfully\'
            ];
        } catch (\Exception $e) {
            Log::error(\'{{moduleName}} action failed\', [
                \'user_id\' => $user->id,
                \'error\' => $e->getMessage()
            ]);

            return [
                \'success\' => false,
                \'message\' => \'Action failed: \' . $e->getMessage()
            ];
        }
    }
}';
    }

    /**
     * Get config file stub
     */
    private function getConfigStub(): string
    {
        return '<?php

return [
    /*
    |--------------------------------------------------------------------------
    | {{moduleName}} Module Configuration
    |--------------------------------------------------------------------------
    */

    \'enabled\' => env(\'{{moduleName|upper}}_MODULE_ENABLED\', true),

    \'settings\' => [
        // Add your module settings here
    ],

    \'features\' => [
        // Add feature flags here
    ],

    \'limits\' => [
        // Add rate limits and other constraints here
    ],
];';
    }

    /**
     * Get migration stub
     */
    private function getMigrationStub(): string
    {
        return '<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::create(\'{{tableName}}\', function (Blueprint $table) {
            $table->id();
            $table->foreignId(\'user_id\')->constrained()->onDelete(\'cascade\');
            // Add your table columns here
            $table->timestamps();

            // Add indexes
            $table->index([\'user_id\']);
        });
    }

    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        Schema::dropIfExists(\'{{tableName}}\');
    }
};';
    }

    /**
     * Get ModuleServiceProvider stub
     */
    private function getModuleServiceProviderStub(): string
    {
        return '<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use App\Services\Core\ModuleManager;

class ModuleServiceProvider extends ServiceProvider
{
    /**
     * Register services.
     */
    public function register(): void
    {
        //
    }

    /**
     * Bootstrap services.
     */
    public function boot(): void
    {
        $moduleManager = app(ModuleManager::class);
        
        // Register modules here
    }
}';
    }
}