<?php

namespace App\Http\Controllers\Install;

use App\Http\Controllers\Controller;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Str;

class InstallController extends Controller
{
    /**
     * Check if application is already installed
     */
    public function __construct()
    {
        // Skip installation check for install routes themselves
    }

    /**
     * Step 0: Welcome / Check Requirements
     */
    public function welcome()
    {
        if ($this->isInstalled()) {
            return redirect('/');
        }

        $requirements = $this->checkRequirements();
        
        return view('install.welcome', compact('requirements'));
    }

    /**
     * Step 1: Database Configuration
     */
    public function database()
    {
        if ($this->isInstalled()) {
            return redirect('/');
        }

        return view('install.database');
    }

    /**
     * Process Database Configuration
     */
    public function processDatabase(Request $request)
    {
        if ($this->isInstalled()) {
            return redirect('/');
        }

        $validated = $request->validate([
            'db_host' => 'required|string|max:255',
            'db_port' => 'required|integer|min:1|max:65535',
            'db_database' => 'required|string|max:255',
            'db_username' => 'required|string|max:255',
            'db_password' => 'nullable|string|max:255',
        ]);

        // Test database connection
        try {
            $config = [
                'driver' => 'mysql',
                'host' => $validated['db_host'],
                'port' => $validated['db_port'],
                'database' => $validated['db_database'],
                'username' => $validated['db_username'],
                'password' => $validated['db_password'] ?? '',
                'charset' => 'utf8mb4',
                'collation' => 'utf8mb4_unicode_ci',
            ];

            config(['database.connections.test' => $config]);
            DB::connection('test')->getPdo();

            // Save to session for next steps
            session(['install_db' => $validated]);

            return redirect()->route('install.migrations');

        } catch (\Exception $e) {
            return back()->with('error', 'Database connection failed: ' . $e->getMessage());
        }
    }

    /**
     * Step 2: Run Migrations
     */
    public function migrations()
    {
        if ($this->isInstalled()) {
            return redirect('/');
        }

        if (!session('install_db')) {
            return redirect()->route('install.database');
        }

        return view('install.migrations');
    }

    /**
     * Run a single migration via AJAX
     */
    public function runSingleMigration(Request $request)
    {
        if ($this->isInstalled()) {
            return response()->json(['success' => false, 'message' => 'Already installed']);
        }

        $dbConfig = session('install_db');
        if (!$dbConfig) {
            return response()->json(['success' => false, 'message' => 'Database not configured']);
        }

        $migration = $request->input('migration');
        
        try {
            // Set config on first migration
            config(['database.connections.mysql.host' => $dbConfig['db_host']]);
            config(['database.connections.mysql.port' => $dbConfig['db_port']]);
            config(['database.connections.mysql.database' => $dbConfig['db_database']]);
            config(['database.connections.mysql.username' => $dbConfig['db_username']]);
            config(['database.connections.mysql.password' => $dbConfig['db_password']]);

            DB::purge('mysql');
            DB::reconnect('mysql');

            // Write .env on first migration
            if (!file_exists(storage_path('app/.env_written'))) {
                $this->updateEnvFile($dbConfig);
                File::put(storage_path('app/.env_written'), '1');
            }

            // Run single migration
            Artisan::call('migrate', [
                '--force' => true,
                '--path' => 'database/migrations/' . $migration . '.php',
            ]);

            return response()->json([
                'success' => true,
                'message' => str_replace('_', ' ', substr($migration, 18)),
            ]);

        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'message' => $e->getMessage(),
            ]);
        }
    }

    /**
     * Step 3: Create Admin Account
     */
    public function admin()
    {
        if ($this->isInstalled()) {
            return redirect('/');
        }

        if (!session('install_db')) {
            return redirect()->route('install.database');
        }

        return view('install.admin');
    }

    /**
     * Process Admin Creation
     */
    public function processAdmin(Request $request)
    {
        if ($this->isInstalled()) {
            return redirect('/');
        }

        $validated = $request->validate([
            'name' => 'required|string|max:255',
            'email' => 'required|email|max:255',
            'username' => 'required|string|min:3|max:30|regex:/^[a-zA-Z0-9_]+$/',
            'password' => 'required|string|min:8|confirmed',
        ]);

        $dbConfig = session('install_db');
        if (!$dbConfig) {
            return back()->with('error', 'Database configuration not found. Please start installation again.');
        }

        try {
            // Configure database connection
            config(['database.connections.mysql.host' => $dbConfig['db_host']]);
            config(['database.connections.mysql.port' => $dbConfig['db_port']]);
            config(['database.connections.mysql.database' => $dbConfig['db_database']]);
            config(['database.connections.mysql.username' => $dbConfig['db_username']]);
            config(['database.connections.mysql.password' => $dbConfig['db_password']]);

            DB::purge('mysql');
            DB::reconnect('mysql');

            // Create roles if they don't exist
            $roles = ['admin', 'vendor', 'customer'];
            foreach ($roles as $roleName) {
                \Spatie\Permission\Models\Role::firstOrCreate(['name' => $roleName, 'guard_name' => 'web']);
            }

            // Create permissions if they don't exist
            $permissions = [
                'view_admin_dashboard',
                'manage_users',
                'manage_vendors',
                'manage_products',
                'manage_orders',
                'manage_categories',
                'manage_brands',
                'manage_coupons',
                'manage_settings',
            ];
            foreach ($permissions as $permissionName) {
                \Spatie\Permission\Models\Permission::firstOrCreate(['name' => $permissionName, 'guard_name' => 'web']);
            }

            // Assign all permissions to admin role
            $adminRole = \Spatie\Permission\Models\Role::findByName('admin');
            $adminRole->syncPermissions(\Spatie\Permission\Models\Permission::all());

            // Create admin user
            $user = User::create([
                'name' => $validated['name'],
                'email' => $validated['email'],
                'username' => strtolower($validated['username']),
                'password' => Hash::make($validated['password']),
                'email_verified_at' => now(),
                'status' => 'active',
            ]);

            // Assign admin role
            $user->assignRole('admin');

            // Run seeders now that admin exists
            try {
                // Set the app key for encryption during seeding
                if (empty(config('app.key'))) {
                    $key = 'base64:' . base64_encode(random_bytes(32));
                    config(['app.key' => $key]);
                }
                
                // Run any remaining migrations first
                try {
                    Artisan::call('migrate', ['--force' => true]);
                } catch (\Exception $me) {
                    \Log::warning('Migration warning during install: ' . $me->getMessage());
                }
                
                Artisan::call('db:seed', ['--force' => true]);
                
                // Create storage link
                try {
                    // Remove existing link if it exists
                    $publicStorage = public_path('storage');
                    if (is_link($publicStorage)) {
                        unlink($publicStorage);
                    }
                    // Create the symlink
                    Artisan::call('storage:link');
                } catch (\Exception $e) {
                    // Storage link might fail on some systems, continue anyway
                    \Log::warning('Storage link creation failed: ' . $e->getMessage());
                }
                
            } catch (\Exception $se) {
                // Log seeder error but don't fail installation
                \Log::warning('Seeder warning during install: ' . $se->getMessage());
            }

            // Mark as installed
            $this->markAsInstalled();

            // Clear caches
            try {
                Artisan::call('config:clear');
                Artisan::call('cache:clear');
                Artisan::call('view:clear');
            } catch (\Exception $e) {
                // Ignore cache clearing errors
            }

            // Clear session
            session()->forget('install_db');

            return redirect()->route('install.complete');

        } catch (\Exception $e) {
            return back()->with('error', 'Admin creation failed: ' . $e->getMessage());
        }
    }

    /**
     * Step 4: Installation Complete
     */
    public function complete()
    {
        if (!$this->isInstalled()) {
            return redirect()->route('install.welcome');
        }

        return view('install.complete');
    }

    /**
     * Check system requirements
     */
    protected function checkRequirements(): array
    {
        return [
            'php_version' => [
                'name' => 'PHP Version (>= 8.1)',
                'met' => version_compare(PHP_VERSION, '8.1.0', '>='),
                'current' => PHP_VERSION,
            ],
            'pdo_mysql' => [
                'name' => 'PDO MySQL Extension',
                'met' => extension_loaded('pdo_mysql'),
                'current' => extension_loaded('pdo_mysql') ? 'Installed' : 'Not Installed',
            ],
            'mbstring' => [
                'name' => 'Mbstring Extension',
                'met' => extension_loaded('mbstring'),
                'current' => extension_loaded('mbstring') ? 'Installed' : 'Not Installed',
            ],
            'openssl' => [
                'name' => 'OpenSSL Extension',
                'met' => extension_loaded('openssl'),
                'current' => extension_loaded('openssl') ? 'Installed' : 'Not Installed',
            ],
            'tokenizer' => [
                'name' => 'Tokenizer Extension',
                'met' => extension_loaded('tokenizer'),
                'current' => extension_loaded('tokenizer') ? 'Installed' : 'Not Installed',
            ],
            'xml' => [
                'name' => 'XML Extension',
                'met' => extension_loaded('xml'),
                'current' => extension_loaded('xml') ? 'Installed' : 'Not Installed',
            ],
            'ctype' => [
                'name' => 'Ctype Extension',
                'met' => extension_loaded('ctype'),
                'current' => extension_loaded('ctype') ? 'Installed' : 'Not Installed',
            ],
            'json' => [
                'name' => 'JSON Extension',
                'met' => extension_loaded('json'),
                'current' => extension_loaded('json') ? 'Installed' : 'Not Installed',
            ],
            'fileinfo' => [
                'name' => 'Fileinfo Extension',
                'met' => extension_loaded('fileinfo'),
                'current' => extension_loaded('fileinfo') ? 'Installed' : 'Not Installed',
            ],
            'storage_writable' => [
                'name' => 'Storage Directory Writable',
                'met' => is_writable(storage_path()),
                'current' => is_writable(storage_path()) ? 'Writable' : 'Not Writable',
            ],
            'env_writable' => [
                'name' => '.env File Writable',
                'met' => is_writable(base_path('.env')),
                'current' => is_writable(base_path('.env')) ? 'Writable' : 'Not Writable',
            ],
        ];
    }

    /**
     * Check if all requirements are met
     */
    protected function requirementsMet(array $requirements): bool
    {
        foreach ($requirements as $req) {
            if (!$req['met']) {
                return false;
            }
        }
        return true;
    }

    /**
     * Update .env file with database config
     */
    protected function updateEnvFile(array $config): void
    {
        $envPath = base_path('.env');
        $envContent = File::get($envPath);

        $replacements = [
            'DB_HOST=' => 'DB_HOST=' . $config['db_host'],
            'DB_PORT=' => 'DB_PORT=' . $config['db_port'],
            'DB_DATABASE=' => 'DB_DATABASE=' . $config['db_database'],
            'DB_USERNAME=' => 'DB_USERNAME=' . $config['db_username'],
            'DB_PASSWORD=' => 'DB_PASSWORD=' . ($config['db_password'] ?? ''),
        ];

        foreach ($replacements as $key => $value) {
            if (strpos($envContent, $key) !== false) {
                $envContent = preg_replace('/^' . preg_quote($key, '/') . '.*$/m', $value, $envContent);
            } else {
                $envContent .= "\n" . $value;
            }
        }

        // Set app key if not set
        if (strpos($envContent, 'APP_KEY=') === false || preg_match('/APP_KEY=$/m', $envContent)) {
            $key = 'base64:' . base64_encode(random_bytes(32));
            if (strpos($envContent, 'APP_KEY=') !== false) {
                $envContent = preg_replace('/^APP_KEY=.*$/m', 'APP_KEY=' . $key, $envContent);
            } else {
                $envContent .= "\nAPP_KEY=" . $key;
            }
        }

        // Set app env to production
        $envContent = preg_replace('/^APP_ENV=.*$/m', 'APP_ENV=production', $envContent);

        File::put($envPath, $envContent);
    }

    /**
     * Check if application is installed
     */
    protected function isInstalled(): bool
    {
        // Only check lock file
        return file_exists(storage_path('app/install.lock'));
    }

    /**
     * Mark application as installed
     */
    protected function markAsInstalled(): void
    {
        $lockFile = storage_path('app/install.lock');
        File::put($lockFile, 'Installed at: ' . now()->toDateTimeString());
    }
}
