<?php

namespace IMATHUZH\Qfq\Core\Helper\Version;

use IMATHUZH\Qfq\Core\Helper\HelperFile;
use IMATHUZH\Qfq\Core\Helper\Path;

/**
 * Helper class for extension deployment operations.
 * Handles downloading, installing, and activating TYPO3 extensions.
 */
class ExtensionDeploy
{
    /**
     * Deploy extensions from URLs.
     *
     * @param array $extensions Array of extension configs: ['ext_key' => ['url' => '...']]
     * @return array Results: ['ext_key' => [API_ANSWER_STATUS_SUCCESS => bool, 'message' => string]]
     */
    public static function deployExtensions(array $extensions): array {
        $results = [];

        foreach ($extensions as $extensionKey => $extensionConfig) {
            $results[$extensionKey] = self::deployExtension($extensionKey, $extensionConfig);
        }

        return $results;
    }

    /**
     * Deploy a single extension from URL.
     *
     * @param string $extensionKey The extension key
     * @param array $extensionConfig Config with 'url' key
     * @return array [API_ANSWER_STATUS_SUCCESS => bool, 'message' => string]
     */
    public static function deployExtension(string $extensionKey, array $extensionConfig): array {
        $result = [
            API_ANSWER_STATUS_SUCCESS => false,
            'message' => ''
        ];

        try {
            // Validate extension key (alphanumeric and underscore only, must start with letter)
            if (!preg_match('/^[a-z][a-z0-9_]*$/i', $extensionKey)) {
                throw new \Exception("Invalid extension key format");
            }

            // Get download URL
            $downloadUrl = $extensionConfig['url'] ?? null;
            if (empty($downloadUrl)) {
                throw new \Exception("No download URL provided");
            }

            // Validate URL
            if (!filter_var($downloadUrl, FILTER_VALIDATE_URL)) {
                throw new \Exception("Invalid download URL format");
            }

            // Download ZIP file
            $zipContent = @file_get_contents($downloadUrl);
            if ($zipContent === false) {
                throw new \Exception("Failed to download from URL: $downloadUrl");
            }

            // Create temp file
            $tempFile = sys_get_temp_dir() . '/ext_' . $extensionKey . '_' . time() . '.zip';
            if (file_put_contents($tempFile, $zipContent) === false) {
                throw new \Exception("Failed to write temporary file");
            }

            // Determine extension target path
            $extBasePath = Path::absoluteApp('typo3conf/ext');
            $extTargetPath = $extBasePath . '/' . $extensionKey;

            // Remove existing extension directory if exists
            if (is_dir($extTargetPath)) {
                HelperFile::rmdirRecursive($extTargetPath);
            }

            // Extract ZIP
            $zip = new \ZipArchive();
            $zipOpenResult = $zip->open($tempFile);
            if ($zipOpenResult !== true) {
                @unlink($tempFile);
                throw new \Exception("Failed to open ZIP file (error code: $zipOpenResult)");
            }

            // Check ZIP structure - might have a root folder
            $firstEntry = $zip->getNameIndex(0);
            $hasRootFolder = (strpos($firstEntry, '/') !== false && strpos($firstEntry, '/') === strlen(rtrim($firstEntry, '/')));

            if ($hasRootFolder) {
                // Extract to temp location first, then move contents
                $tempExtractPath = sys_get_temp_dir() . '/ext_extract_' . $extensionKey . '_' . time();
                $zip->extractTo($tempExtractPath);
                $zip->close();

                // Find the root folder name
                $extractedDirs = glob($tempExtractPath . '/*', GLOB_ONLYDIR);
                if (count($extractedDirs) === 1) {
                    // Move the contents of the root folder to target
                    rename($extractedDirs[0], $extTargetPath);
                    @rmdir($tempExtractPath);
                } else {
                    // Multiple folders or no folder - move entire content
                    rename($tempExtractPath, $extTargetPath);
                }
            } else {
                // No root folder - extract directly to target
                if (!is_dir($extTargetPath)) {
                    mkdir($extTargetPath, 0755, true);
                }
                $zip->extractTo($extTargetPath);
                $zip->close();
            }

            // Clean up temp file
            @unlink($tempFile);

            // Verify extraction
            if (!is_dir($extTargetPath) || !file_exists($extTargetPath . '/ext_emconf.php')) {
                throw new \Exception("Extension extraction failed or invalid extension structure");
            }

            // Run TYPO3 CLI commands
            $typo3CliPath = Path::absoluteApp('typo3/sysext/core/bin/typo3');
            if (!file_exists($typo3CliPath)) {
                // Try alternative path for some TYPO3 installations
                $typo3CliPath = Path::absoluteApp('vendor/bin/typo3');
            }

            if (!file_exists($typo3CliPath)) {
                throw new \Exception("TYPO3 CLI not found");
            }

            $appRoot = Path::absoluteApp('');

            // Check if extension is already active (in PackageStates.php)
            $packageStatesPath = Path::absoluteApp('typo3conf/PackageStates.php');
            $isAlreadyActive = false;
            if (file_exists($packageStatesPath)) {
                $packageStatesContent = file_get_contents($packageStatesPath);
                $isAlreadyActive = strpos($packageStatesContent, "'$extensionKey'") !== false;
            }

            if ($isAlreadyActive) {
                // Extension already active - just flush cache
                $command = sprintf(
                    'cd %s && php %s cache:flush 2>&1',
                    escapeshellarg($appRoot),
                    escapeshellarg($typo3CliPath)
                );
            } else {
                // New extension - activate it
                $command = sprintf(
                    'cd %s && php %s extension:activate %s 2>&1',
                    escapeshellarg($appRoot),
                    escapeshellarg($typo3CliPath),
                    escapeshellarg($extensionKey)
                );
            }

            $output = [];
            $returnCode = 0;
            exec($command, $output, $returnCode);

            if ($returnCode !== 0) {
                $outputStr = implode("\n", $output);
                $action = $isAlreadyActive ? 'Cache flush' : 'Extension activation';
                throw new \Exception("$action failed: $outputStr");
            }

            // Run extension:setup to sync ext_conf_template settings and DB schema
            $setupCommand = sprintf(
                'cd %s && php %s extension:setup --extension %s 2>&1',
                escapeshellarg($appRoot),
                escapeshellarg($typo3CliPath),
                escapeshellarg($extensionKey)
            );

            $setupOutput = [];
            $setupReturnCode = 0;
            exec($setupCommand, $setupOutput, $setupReturnCode);

            // extension:setup failure is non-critical, just log it
            if ($setupReturnCode !== 0) {
                $result['setupWarning'] = implode("\n", $setupOutput);
            }

            $result[API_ANSWER_STATUS_SUCCESS] = true;
            $result[API_MESSAGE] = "Extension $extensionKey installed and activated successfully";

        } catch (\Exception $e) {
            $result[API_ANSWER_STATUS_SUCCESS] = false;
            $result[API_MESSAGE] = $e->getMessage();
        }

        return $result;
    }

    /**
     * Get TYPO3 extension information from PackageStates.php
     *
     * @return array
     */
    public static function getAllExtensionsInfo(): array {
        $packageStatesPath = Path::absoluteTypo3Conf('PackageStates.php');

        if (!file_exists($packageStatesPath)) {
            throw new \Exception('PackageStates.php does not exist at the specified path.');
        }

        $packageStates = include $packageStatesPath;

        $extensions = [];
        if (isset($packageStates[TYPO3_PACKAGES])) {
            foreach ($packageStates[TYPO3_PACKAGES] as $key => $package) {
                $extensions[$key] = $package[TYPO3_PACKAGE_PATH];
            }
        }

        return $extensions;
    }
}
