<?php

namespace PortalPeople\NgaugeBackupSql\controllers;

use Yii;
use yii\web\Controller;
use yii\web\Response;
use yii\filters\AccessControl;

/**
 * Setup Controller for Backup Module Configuration
 * 
 * Provides initial configuration interface for the backup module,
 * including encryption key generation and system setup.
 */
class SetupController extends Controller
{
    /**
     * @inheritdoc
     */
    public function behaviors()
    {
        return [
            'access' => [
                'class' => AccessControl::class,
                'rules' => [
                    [
                        'allow' => true,
                        'roles' => ['@'], // Only authenticated users
                    ],
                ],
            ],
        ];
    }

    /**
     * Setup wizard - initial configuration
     * 
     * @return string|Response
     */
    public function actionIndex()
    {
        $module = Yii::$app->getModule('db-backup');
        
        // Redirect to dashboard if already configured
        if ($this->isConfigured($module)) {
            return $this->redirect(['default/index']);
        }

        return $this->render('index', [
            'module' => $module,
        ]);
    }

    /**
     * Configuration page
     * 
     * @return string|Response
     */
    public function actionConfigure()
    {
        $module = Yii::$app->getModule('db-backup');
        
        $model = new \stdClass();
        $model->encryptionEnabled = $module->encryptionEnabled;
        $model->systemId = $module->systemId;
        $model->authorizedSystems = implode("\n", $module->authorizedSystems ?? []);
        
        if (Yii::$app->request->isPost) {
            $model->encryptionEnabled = (bool) Yii::$app->request->post('encryptionEnabled', false);
            $model->systemId = Yii::$app->request->post('systemId', '');
            $model->authorizedSystems = Yii::$app->request->post('authorizedSystems', '');
            
            return $this->render('configure', [
                'model' => $model,
                'module' => $module,
            ]);
        }

        return $this->render('configure', [
            'model' => $model,
            'module' => $module,
        ]);
    }

    /**
     * Generate encryption key
     * 
     * @return array JSON response
     */
    public function actionGenerateKey()
    {
        Yii::$app->response->format = Response::FORMAT_JSON;
        
        try {
            // Generate random 256-bit key
            $key = random_bytes(32);
            $base64Key = base64_encode($key);
            $formattedKey = 'base64:' . $base64Key;
            
            return [
                'success' => true,
                'key' => $formattedKey,
                'base64' => $base64Key,
                'message' => 'Encryption key generated successfully.',
            ];
        } catch (\Exception $e) {
            return [
                'success' => false,
                'message' => 'Failed to generate encryption key: ' . $e->getMessage(),
            ];
        }
    }

    /**
     * Get system ID
     * 
     * @return array JSON response
     */
    public function actionGetSystemId()
    {
        Yii::$app->response->format = Response::FORMAT_JSON;
        
        $encryptionManager = Yii::createObject([
            'class' => 'PortalPeople\NgaugeBackupSql\components\EncryptionManager',
            'module' => Yii::$app->getModule('db-backup'),
        ]);
        
        $systemId = $encryptionManager->getSystemId();
        
        return [
            'success' => true,
            'systemId' => $systemId,
        ];
    }

    /**
     * Save configuration
     * 
     * @return array JSON response
     */
    public function actionSaveConfig()
    {
        Yii::$app->response->format = Response::FORMAT_JSON;
        
        $encryptionEnabled = (bool) Yii::$app->request->post('encryptionEnabled', false);
        $encryptionKey = Yii::$app->request->post('encryptionKey', '');
        $systemId = Yii::$app->request->post('systemId', '');
        $authorizedSystems = Yii::$app->request->post('authorizedSystems', '');
        
        try {
            // Validate inputs
            if ($encryptionEnabled && empty($encryptionKey)) {
                return [
                    'success' => false,
                    'error' => 'Encryption key is required when encryption is enabled.',
                ];
            }
            
            // Parse authorized systems
            $authorizedSystemsArray = array_filter(array_map('trim', explode("\n", $authorizedSystems)));
            
            // Generate configuration array
            $configArray = $this->generateConfigArray($encryptionEnabled, $encryptionKey, $systemId, $authorizedSystemsArray);
            
            // Build the file content
            $fileContent = "<?php\n\n";
            $fileContent .= "/**\n";
            $fileContent .= " * Database Backup Module Configuration\n";
            $fileContent .= " * Auto-generated by setup wizard\n";
            $fileContent .= " * Generated: " . date('Y-m-d H:i:s') . "\n";
            $fileContent .= " * NOTE: The encryption key is stored in environment variables for security\n";
            $fileContent .= " */\n\n";
            $fileContent .= "return " . var_export($configArray, true) . ";\n";
            
            // Get the config directory - try common first, then app config
            $configDir = null;
            
            // Try @common/config first (Yii2 advanced template)
            try {
                $commonConfigDir = Yii::getAlias('@common/config');
                if (is_dir($commonConfigDir)) {
                    $configDir = $commonConfigDir;
                }
            } catch (\Exception $e) {
                // @common alias doesn't exist
            }
            
            // Try @app/config (console, backend, frontend specific config)
            if (!$configDir) {
                try {
                    $appConfigDir = Yii::getAlias('@app/config');
                    if (is_dir($appConfigDir)) {
                        $configDir = $appConfigDir;
                    }
                } catch (\Exception $e) {
                    // @app alias doesn't exist
                }
            }
            
            if (!$configDir) {
                return [
                    'success' => false,
                    'error' => 'Could not determine config directory. No @common or @app alias found.',
                ];
            }
            
            $configFile = $configDir . DIRECTORY_SEPARATOR . 'backup.php';
            
            // Write the configuration file
            if (file_put_contents($configFile, $fileContent) === false) {
                return [
                    'success' => false,
                    'error' => 'Failed to write configuration file. Check directory permissions.',
                ];
            }
            
            // Also generate the PHP code for display
            $config = $this->generateConfig($encryptionEnabled, $encryptionKey, $systemId, $authorizedSystemsArray);
            
            // Try to write encryption key to .env file (more secure)
            $envFile = null;
            $envWritten = false;
            
            try {
                // Try @root/.env.local first (local environment override)
                $rootDir = Yii::getAlias('@root');
                if (is_dir($rootDir) && is_writable($rootDir)) {
                    $envFile = $rootDir . DIRECTORY_SEPARATOR . '.env.local';
                    $this->writeEncryptionKeyToEnv($envFile, $encryptionKey);
                    $envWritten = true;
                }
            } catch (\Exception $e) {
                // Silently fail - env file is optional
            }
            
            return [
                'success' => true,
                'config' => $config,
                'filePath' => $configFile,
                'envFile' => $envFile,
                'envWritten' => $envWritten,
                'encryptionKey' => $encryptionKey,
                'message' => 'Configuration saved successfully to ' . $configFile,
            ];
            
        } catch (\Exception $e) {
            return [
                'success' => false,
                'error' => 'Error: ' . $e->getMessage(),
            ];
        }
    }

    /**
     * Test encryption
     * 
     * @return array JSON response
     */
    public function actionTestEncryption()
    {
        Yii::$app->response->format = Response::FORMAT_JSON;
        
        $testData = Yii::$app->request->post('testData', 'Test backup data');
        
        try {
            $module = Yii::$app->getModule('db-backup');
            
            $encryptionManager = Yii::createObject([
                'class' => 'PortalPeople\NgaugeBackupSql\components\EncryptionManager',
                'module' => $module,
            ]);
            
            // Encrypt test data
            $encrypted = $encryptionManager->encrypt($testData);
            $encryptedSize = strlen($encrypted);
            
            // Decrypt test data
            $decrypted = $encryptionManager->decrypt($encrypted);
            
            // Verify
            if ($decrypted !== $testData) {
                return [
                    'success' => false,
                    'message' => 'Encryption test failed: decrypted data does not match original.',
                ];
            }
            
            return [
                'success' => true,
                'message' => 'Encryption test successful!',
                'originalSize' => strlen($testData),
                'encryptedSize' => $encryptedSize,
                'overheadBytes' => $encryptedSize - strlen($testData),
            ];
            
        } catch (\Exception $e) {
            return [
                'success' => false,
                'message' => 'Encryption test failed: ' . $e->getMessage(),
            ];
        }
    }

    /**
     * Check if module is configured
     * 
     * @param mixed $module Module instance
     * @return bool
     */
    protected function isConfigured($module)
    {
        // Check if basic backup path is configured
        return !empty($module->backupPath);
    }

    /**
     * Generate configuration array (for file writing)
     * 
     * @param bool $encryptionEnabled
     * @param string $encryptionKey
     * @param string $systemId
     * @param array $authorizedSystems
     * @return array Configuration array
     */
    protected function generateConfigArray($encryptionEnabled, $encryptionKey, $systemId, $authorizedSystems)
    {
        $config = [
            'class' => 'PortalPeople\NgaugeBackupSql\Module',
            'backupPath' => '@backups/sql',
            'retentionDays' => 30,
            'compressBackups' => true,
        ];
        
        if ($encryptionEnabled) {
            $config['encryptionEnabled'] = true;
            $config['encryptionKey'] = $encryptionKey;
            
            // NOTE: We don't save systemId to config - it will auto-generate from system info
            // This prevents duplicate concatenation issues
            
            if (!empty($authorizedSystems)) {
                $config['authorizedSystems'] = $authorizedSystems;
            }
        } else {
            $config['encryptionEnabled'] = false;
        }
        
        return $config;
    }

    /**
     * Generate configuration code
     * 
     * @param bool $encryptionEnabled
     * @param string $encryptionKey
     * @param string $systemId
     * @param array $authorizedSystems
     * @return string PHP configuration code
     */
    protected function generateConfig($encryptionEnabled, $encryptionKey, $systemId, $authorizedSystems)
    {
        $config = "'db-backup' => [\n";
        $config .= "    'class' => 'PortalPeople\\NgaugeBackupSql\\Module',\n";
        $config .= "    'backupPath' => '@backups/sql', // Change to your backup directory\n";
        $config .= "    'retentionDays' => 30,\n";
        $config .= "    'compressBackups' => true,\n";
        
        if ($encryptionEnabled) {
            $config .= "    'encryptionEnabled' => true,\n";
            $config .= "    'encryptionKey' => getenv('DB_BACKUP_ENCRYPTION_KEY') ?? '{$encryptionKey}',\n";
            
            if (!empty($systemId)) {
                $config .= "    'systemId' => '{$systemId}',\n";
            }
            
            if (!empty($authorizedSystems)) {
                $config .= "    'authorizedSystems' => [\n";
                foreach ($authorizedSystems as $system) {
                    $config .= "        '{$system}',\n";
                }
                $config .= "    ],\n";
            }
        } else {
            $config .= "    'encryptionEnabled' => false,\n";
        }
        
        $config .= "],\n";
        
        return $config;
    }

    /**
     * Write encryption key to .env file
     * 
     * @param string $filePath Path to .env file
     * @param string $encryptionKey Encryption key to write
     */
    protected function writeEncryptionKeyToEnv($filePath, $encryptionKey)
    {
        // Read existing .env content if it exists
        $envContent = '';
        if (file_exists($filePath)) {
            $envContent = file_get_contents($filePath);
        }
        
        // Check if key already exists
        if (strpos($envContent, 'DB_BACKUP_ENCRYPTION_KEY=') !== false) {
            // Update existing key
            $envContent = preg_replace(
                '/^DB_BACKUP_ENCRYPTION_KEY=.*/m',
                'DB_BACKUP_ENCRYPTION_KEY=' . $this->escapeEnvValue($encryptionKey),
                $envContent
            );
        } else {
            // Append new key
            if (!empty($envContent) && substr($envContent, -1) !== "\n") {
                $envContent .= "\n";
            }
            $envContent .= "DB_BACKUP_ENCRYPTION_KEY=" . $this->escapeEnvValue($encryptionKey) . "\n";
        }
        
        // Write to file
        file_put_contents($filePath, $envContent);
        
        // Restrict file permissions (readable by owner only)
        chmod($filePath, 0600);
    }

    /**
     * Escape value for .env file
     * 
     * @param string $value Value to escape
     * @return string Escaped value
     */
    protected function escapeEnvValue($value)
    {
        // If value contains special characters, wrap in quotes
        if (preg_match('/["\'\s$`\\\\]/', $value)) {
            // Escape quotes and backslashes
            $value = str_replace(['\\', '"'], ['\\\\', '\\"'], $value);
            return '"' . $value . '"';
        }
        
        return $value;
    }
}
