<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\DB;
use App\Models\Configuration;

class InstallerController extends Controller
{
    public function index()
    {
        if (File::exists(storage_path('app/installed.txt'))) {
            return redirect('/')->with('error', 'Application is already installed!');
        }
        
        return view('installer.welcome');
    }
    
    public function requirements()
    {
        $requirements = [
            'PHP Version (>= 8.2)' => version_compare(PHP_VERSION, '8.2.0', '>='),
            'BCMath Extension' => extension_loaded('bcmath'),
            'Ctype Extension' => extension_loaded('ctype'),
            'Fileinfo Extension' => extension_loaded('fileinfo'),
            'JSON Extension' => extension_loaded('json'),
            'Mbstring Extension' => extension_loaded('mbstring'),
            'OpenSSL Extension' => extension_loaded('openssl'),
            'PDO Extension' => extension_loaded('pdo'),
            'Tokenizer Extension' => extension_loaded('tokenizer'),
            'XML Extension' => extension_loaded('xml'),
            'Storage Directory Writable' => is_writable(storage_path()),
            'Bootstrap/Cache/ Directory Writable' => is_writable(base_path('bootstrap/cache')),
            'Plugins Directory Writable' => is_writable(base_path('plugins')),
        ];
        
        $allPassed = !in_array(false, $requirements);
        
        return view('installer.requirements', compact('requirements', 'allPassed'));
    }
    
    public function license()
    {
        return view('installer.license');
    }
    
    public function verifyLicense(Request $request)
    {
        $request->validate([
            'license_key' => 'required|string|min:16'
        ]);
        
        $licenseKey = $request->input('license_key');
        
        $valid = $this->checkLicenseValidity($licenseKey);
        
        if (!$valid) {
            return back()->with('error', 'Invalid license key. Please check and try again.');
        }
        
        session(['license_key' => $licenseKey]);
        
        return redirect()->route('installer.database')->with('success', 'License key verified successfully!');
    }
    
    private function checkLicenseValidity($key)
    {
        try {
            $response = Http::post('https://dash.siedestudios.co.uk/api/licenses/validate', [
                'license_key' => $key
            ]);
            
            if ($response->successful() && $response->json('valid') === true) {
                return true;
            }
            
            return false;
        } catch (\Exception $e) {
            \Log::error('License validation error', [
                'license_key' => $key,
                'error' => $e->getMessage()
            ]);
            
            return false;
        }
    }
    
    public function database()
    {
        return view('installer.database');
    }
    
    public function setDatabase(Request $request)
    {
        $request->validate([
            'db_host' => 'required|string',
            'db_port' => 'required|numeric',
            'db_database' => 'required|string',
            'db_username' => 'required|string',
            'db_password' => 'nullable|string',
        ]);
        
        try {
            $conn = new \PDO(
                "mysql:host={$request->db_host};port={$request->db_port}",
                $request->db_username,
                $request->db_password
            );
            
            $dbName = $request->db_database;
            $conn->exec("CREATE DATABASE IF NOT EXISTS `$dbName`;");
            
        } catch (\Exception $e) {
            return back()->with('error', 'Database connection failed: ' . $e->getMessage());
        }
        
        session([
            'db_host' => $request->db_host,
            'db_port' => $request->db_port,
            'db_database' => $request->db_database,
            'db_username' => $request->db_username,
            'db_password' => $request->db_password,
        ]);
        
        return redirect()->route('installer.app')->with('success', 'Database connection verified successfully!');
    }
    
    public function app()
    {
        return view('installer.app');
    }
    
    public function setApp(Request $request)
    {
        $request->validate([
            'app_name' => 'required|string',
            'app_url' => 'required|url',
            'steam_client_secret' => 'required|string',
        ]);
        
        session([
            'app_name' => $request->app_name,
            'app_url' => $request->app_url,
            'steam_client_secret' => $request->steam_client_secret,
        ]);
        
        return redirect()->route('installer.install')->with('success', 'Application settings saved successfully!');
    }
    
    public function install()
    {
        return view('installer.install');
    }
    
    public function doInstall(Request $request)
    {
        try {
            // CRITICAL: Retrieve all session data BEFORE any modifications
            // This prevents data loss when the .env file is updated
            $sessionData = [
                'app_name' => session('app_name'),
                'app_url' => session('app_url'),
                'db_host' => session('db_host'),
                'db_port' => session('db_port'),
                'db_database' => session('db_database'),
                'db_username' => session('db_username'),
                'db_password' => session('db_password'),
                'license_key' => session('license_key'),
                'steam_client_secret' => session('steam_client_secret'),
            ];
            
            // Validate that we have all required data
            foreach ($sessionData as $key => $value) {
                if (empty($value) && $key !== 'db_password') {
                    throw new \Exception("Missing required installation data: {$key}. Please restart the installation process.");
                }
            }
            
            $envPath = base_path('.env');
            $envExample = base_path('.env.example');
            
            if (File::exists($envExample)) {
                File::copy($envExample, $envPath);
            }
            
            $appKey = env('APP_KEY');
            if (empty($appKey)) {
                $output = Artisan::output();
                if (preg_match('/\[(.+?)\]/', $output, $matches)) {
                    $appKey = $matches[1];
                }
                
                if (empty($appKey)) {
                    $appKey = 'base64:' . base64_encode(random_bytes(32));
                }
            }
            
            $steamRedirectUri = rtrim($sessionData['app_url'], '/') . '/login/steam/callback';
            
            // Use the retrieved session data instead of session() helper
            $this->updateEnv([
                'APP_NAME' => $sessionData['app_name'],
                'APP_URL' => $sessionData['app_url'],
                'DB_HOST' => $sessionData['db_host'],
                'DB_PORT' => $sessionData['db_port'],
                'DB_DATABASE' => $sessionData['db_database'],
                'DB_USERNAME' => $sessionData['db_username'],
                'DB_PASSWORD' => $sessionData['db_password'],
                'LICENSE_KEY' => $sessionData['license_key'],
                'APP_INSTALLED' => 'true',
                'STEAM_CLIENT_SECRET' => $sessionData['steam_client_secret'],
                'STEAM_REDIRECT_URI' => $steamRedirectUri,
                'APP_KEY' => $appKey,
                'SESSION_DRIVER' => 'file', // Ensure file-based sessions
            ]);
            
            // Clear configuration to reload new database settings
            Artisan::call('config:clear');
            
            // Run migrations and seeders
            Artisan::call('migrate:fresh', ['--force' => true]);
            Artisan::call('db:seed', ['--force' => true]);
            
            // Update database configurations using the stored session data
            $this->updateDatabaseConfigurations($sessionData);
            
            File::put(storage_path('app/installed.txt'), 'Installation completed on ' . date('Y-m-d H:i:s'));
            
            Artisan::call('key:generate', ['--force' => true]);
            
            $this->ensureAppKey();
            
            Artisan::call('cache:clear');
            Artisan::call('view:clear');
            Artisan::call('storage:link');
            
            // Store success message in a way that will persist
            $successMessage = 'Installation completed successfully!';
            
            return redirect()->route('installer.complete')->with('success', $successMessage);
            
        } catch (\Exception $e) {
            \Log::error('Installation failed', [
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString()
            ]);
            
            return back()->with('error', 'Installation failed: ' . $e->getMessage());
        }
    }
    
    private function updateDatabaseConfigurations($sessionData = null)
    {
        try {
            // Use passed data or fall back to session (for backward compatibility)
            $appName = $sessionData['app_name'] ?? session('app_name');
            $appUrl = $sessionData['app_url'] ?? session('app_url');
            $steamSecret = $sessionData['steam_client_secret'] ?? session('steam_client_secret');
            
            Configuration::updateOrCreate(
                ['key' => 'site_name'],
                [
                    'value' => $appName,
                    'description' => 'The name of the website',
                    'type' => 'text',
                    'group' => 'general'
                ]
            );
            
            Configuration::updateOrCreate(
                ['key' => 'site_url'],
                [
                    'value' => $appUrl,
                    'description' => 'The URL of the website',
                    'type' => 'text',
                    'group' => 'general'
                ]
            );
            
            Configuration::updateOrCreate(
                ['key' => 'steam_apikey'],
                [
                    'value' => $steamSecret,
                    'description' => 'Steam API key for authentication',
                    'type' => 'text',
                    'group' => 'auth'
                ]
            );
            
            return true;
        } catch (\Exception $e) {
            \Log::error('Failed to update database configurations: ' . $e->getMessage());
            return false;
        }
    }
    
    private function updateEnv($data)
    {
        $envPath = base_path('.env');
        $envExamplePath = base_path('.env.example');
        
        try {
            if (!File::exists($envPath) && File::exists($envExamplePath)) {
                try {
                    File::copy($envExamplePath, $envPath);
                } catch (\Exception $e) {
                    throw new \Exception("Cannot create .env file. Please check file permissions or create the file manually. Error: " . $e->getMessage());
                }
            }
            
            if (!File::exists($envPath)) {
                try {
                    File::put($envPath, '');
                } catch (\Exception $e) {
                    throw new \Exception("Cannot create .env file. Please check directory permissions. Error: " . $e->getMessage());
                }
            }
            
            if (!is_writable($envPath)) {
                throw new \Exception("The .env file exists but is not writable. Please check file permissions.");
            }
            
            $envContents = File::get($envPath);
            
            foreach ($data as $key => $value) {
                $formattedValue = $this->formatEnvValue($key, $value);
                $pattern = "/^{$key}=.*$/m";
                
                if (preg_match($pattern, $envContents)) {
                    $envContents = preg_replace($pattern, "{$key}={$formattedValue}", $envContents);
                } else {
                    $envContents .= PHP_EOL . "{$key}={$formattedValue}";
                }
            }
            
            File::put($envPath, $envContents);
            
            return true;
        } catch (\Exception $e) {
            throw new \Exception("Environment configuration failed: " . $e->getMessage());
        }
    }
    
    private function formatEnvValue($key, $value)
    {
        $needsQuotes = [
            'APP_NAME',
            'DB_PASSWORD',
            'APP_URL',
            'STEAM_REDIRECT_URI'
        ];
        
        $cleanValue = trim($value, '"\'');
        
        if ($key === 'DB_PASSWORD') {
            return '"' . str_replace('"', '\\"', $cleanValue) . '"';
        }
        
        if (in_array($key, $needsQuotes)) {
            if (empty($cleanValue) || preg_match('/[\s#"\'\\\\]/', $cleanValue)) {
                return '"' . str_replace('"', '\\"', $cleanValue) . '"';
            }
        }
        
        return $cleanValue;
    }
    
    private function ensureAppKey()
    {
        $envPath = base_path('.env');
        
        try {
            $envContents = File::get($envPath);
            
            if (!preg_match('/^APP_KEY=.+$/m', $envContents)) {
                $appKey = 'base64:' . base64_encode(random_bytes(32));
                $envContents .= PHP_EOL . "APP_KEY={$appKey}";
                File::put($envPath, $envContents);
                Artisan::call('config:clear');
            }
            
            return true;
        } catch (\Exception $e) {
            throw new \Exception("Failed to ensure app key is set: " . $e->getMessage());
        }
    }
    
    public function complete()
    {
        if (!File::exists(storage_path('app/installed.txt'))) {
            return redirect()->route('installer.index');
        }
        
        return view('installer.complete');
    }
}