<?php
/**
 * Created by PhpStorm.
 * User: enured
 * Date: 19.09.24
 * Time: 11:00
 */

namespace IMATHUZH\Qfq\Api;

require_once(__DIR__ . '/../../vendor/autoload.php');

use IMATHUZH\Qfq\Core\Database\Database;
use IMATHUZH\Qfq\Core\Helper\HelperFile;
use IMATHUZH\Qfq\Core\Helper\Path;
use IMATHUZH\Qfq\Core\Store\Client;
use IMATHUZH\Qfq\Core\Store\Config;
use IMATHUZH\Qfq\Core\Store\Store;
use IMATHUZH\Qfq\Core\Store\T3Info;

// Detect API calls if this is defined.
define('QFQ_API', 'Api call');

try {
    $json = file_get_contents('php://input');
    $config = array();
    if (!empty($json)) {
        $config = json_decode($json, true);
        if ($config === null && json_last_error() !== JSON_ERROR_NONE) {
            $config = array();
        }
    }

    // Get variables from qfq STORE_SYSTEM and T3Info
    $store = Store::getInstance();
    $vars = T3Info::getVars();

    // Verify API token
    $headers = Client::getParam();
    $providedToken = $headers[HTTP_HEADER_AUTHORIZATION] ?? '';
    $validToken = $store::getVar(SYSTEM_QFQ_VERSION_API_TOKEN, STORE_SYSTEM);

    if (empty($validToken)) {
        throw new \Exception("Server configuration error: API token not set", 500);
    }

    if (empty($providedToken)) {
        throw new \Exception("No API token provided: " . $providedToken, 401);
    }

    if ($providedToken !== $validToken) {
        throw new \Exception("Invalid API token", 401);
    }

    // Prepare file paths
    // Content will be fetched for response
    // Also used to get typo3 database credentials
    $filePaths = [
        Path::absoluteConf(CONFIG_QFQ_JSON),
        Path::absoluteTypo3Conf(CONFIG_T3),
    ];

    // Prepare database indexes
    $dbArray = array();
    $dbIndexData = $store->getVar(SYSTEM_DB_INDEX_DATA, STORE_SYSTEM);
    $dbIndexQfq = $store->getVar(SYSTEM_DB_INDEX_QFQ, STORE_SYSTEM);
    $dbIndexT3 = $dbIndexQfq;

    // Define free index number for Typo3 database
    for ($i = 1; $i <= 3; $i++) {
        if ($dbIndexData !== $i && $dbIndexQfq !== $i) {
            $dbIndexT3 = $i;
            continue;
        }
    }

    // Words which will be masked in content
    $blacklistWords = [
        'DB_1_PASSWORD',
        'DB_2_PASSWORD',
        'DB_3_PASSWORD',
        'DB_4_PASSWORD',
        'LDAP_1_PASSWORD',
        'ENCRYPTION_KEY',
        'installToolPassword',
        'password',
        'secretKey',
        'forwardServiceSecret',
        'encryptionKey',
    ];

    // Prepare typo3 config array
    $t3DbConfig = [];
    // Get all file contents and typo3 credentials (incl. system maintainer list)
    $contents = HelperFile::getFileContents($filePaths, $blacklistWords, $t3DbConfig);
    // Create typo3 database object if config exists
    if (!empty($t3DbConfig)) {
        $dbConfig = [
            'DB_' . $dbIndexT3 . '_USER' => $t3DbConfig['user'],
            'DB_' . $dbIndexT3 . '_PASSWORD' => $t3DbConfig['password'],
            'DB_' . $dbIndexT3 . '_SERVER' => $t3DbConfig['host'],
            'DB_' . $dbIndexT3 . '_NAME' => $t3DbConfig['dbname'],
        ];
        $dbArray[$dbIndexT3] = new Database($dbIndexT3, $dbConfig);
    }

    // Get all extensions and their versions
    $extensions = T3Info::getAllExtensionsInfo();
    $extensions = Config::getExtVersion($extensions);

    // Get TYPO3 site name (project name)
    $siteName = $store::getVar(SYSTEM_T3_SITE_NAME, STORE_SYSTEM);

    // Get TYPO3 version
    $typo3Version = $vars[TYPO3_VERSION] ?? 'unknown';

    $url = $store::getVar(SYSTEM_BASE_URL, STORE_SYSTEM);

    // Get hostname
    $hostname = gethostname();

    // Prepare response data
    $data = [
        API_VERSION_KEY_URL => $url,
        API_VERSION_KEY_HOSTNAME => $hostname,
        API_VERSION_KEY_PROJECT => $siteName,
        API_VERSION_KEY_TYPO3 => $typo3Version,
    ];

    // Get deb packages
    $data[API_VERSION_KEY_DEB_PACKAGES] = Config::getServerInfo();

    // System Maintainers aus t3DbConfig
    $systemMaintainers = $t3DbConfig['systemMaintainers'] ?? [];

    // Check request flags (array_key_exists because value can be empty)
    $hasExtModuleRequest = array_key_exists(API_VERSION_CHECK_EXT_MODULE, $config);
    $hasBeUserRequest = array_key_exists(API_VERSION_CHECK_BE_USER, $config);

    // Determine response mode:
    // - extModule only: return ONLY check-extModule (complex operation, isolated)
    // - extModule + beUser: return everything including check-extModule
    // - no extModule: return everything EXCEPT check-extModule
    $extModuleOnlyMode = $hasExtModuleRequest && !$hasBeUserRequest;

    if ($extModuleOnlyMode) {
        // Only execute and return check-extModule
        if (isset($dbArray[$dbIndexT3])) {
            // Set extension module data if provided
            if (!empty($config[API_VERSION_CHECK_EXT_MODULE])) {
                T3Info::setExtModuleData($config[API_VERSION_CHECK_EXT_MODULE], $dbArray[$dbIndexT3]);
            }
            // Get extension module data
            $extModuleData = T3Info::getExtModuleData($dbArray[$dbIndexT3]);
            $data = [API_VERSION_CHECK_EXT_MODULE => $extModuleData];
        } else {
            $data = [API_VERSION_CHECK_EXT_MODULE => ['error' => 'Database not available']];
        }
    } else {
        // Standard mode: return everything (optionally including check-extModule)

        // Set beUsers based on passed config
        if ($hasBeUserRequest && isset($dbArray[$dbIndexT3])) {
            T3Info::ensureAdminMaintainers($config[API_VERSION_CHECK_BE_USER], $dbArray[$dbIndexT3], $systemMaintainers);
        }

        // Set extension settings based on passed config
        if (isset($config[API_VERSION_CHECK_EXT_SETTING])) {
            try {
                T3Info::setExtensionSettings($config[API_VERSION_CHECK_EXT_SETTING]);
            } catch (\Exception $e) {
                // Silently ignore write errors
            }
        }

        // Set extension module data based on passed config (only if beUser also requested)
        if ($hasExtModuleRequest && $hasBeUserRequest && isset($dbArray[$dbIndexT3])) {
            if (!empty($config[API_VERSION_CHECK_EXT_MODULE])) {
                T3Info::setExtModuleData($config[API_VERSION_CHECK_EXT_MODULE], $dbArray[$dbIndexT3]);
            }
        }

        // Get all typo3 backend users
        // Get active feUser info
        if (isset($dbArray[$dbIndexT3])) {
            $allBeUsers = T3Info::getAllBackendUsers($dbArray[$dbIndexT3], $systemMaintainers);
            $feUserInfo = T3Info::getActiveFrontendUsersInfo($dbArray[$dbIndexT3]);
            // All not deleted users should be returned, even those which are disabled. Disabled and deleted are two different states in typo3.
            //$activeBeUsers = array_filter($allBeUsers, fn($u) => !$u['isDisabled']);
            $data[API_VERSION_CHECK_BE_USER] = array_values($allBeUsers);
            $data[API_VERSION_CHECK_FE_USER] = $feUserInfo;
        }

        // Get extension settings (template + current values) for extensions with ext_conf_template.txt
        $t3ConfigPath = Path::absoluteTypo3Conf(CONFIG_T3);
        if (file_exists($t3ConfigPath)) {
            $t3Config = include $t3ConfigPath;
            // Return as array - json_encode($data) will handle escaping correctly
            $data[API_VERSION_CHECK_EXT_SETTING] = T3Info::getExtensionSettings($t3Config);
        }

        // Get extension module data only if both extModule and beUser are requested
        if ($hasExtModuleRequest && $hasBeUserRequest && isset($dbArray[$dbIndexT3])) {
            $extModuleData = T3Info::getExtModuleData($dbArray[$dbIndexT3]);
            if (!empty($extModuleData)) {
                $data[API_VERSION_CHECK_EXT_MODULE] = $extModuleData;
            }
        }

        // Add extensions to response
        $data = array_merge($data, $extensions);
        $data = array_merge($data, $contents);
    }

    $status = 200;
} catch (\Exception $e) {
    $exceptionCode = $e->getCode();
    // Ensure valid HTTP status code (100-599), default to 500
    $status = (is_int($exceptionCode) && $exceptionCode >= 100 && $exceptionCode <= 599) ? $exceptionCode : 500;
    $data = [
        'error' => $e->getMessage()
    ];
}

// Send response
header('HTTP/1.1 ' . $status);
header('Content-Type: application/json');

// Encode to JSON - handles all escaping correctly
$jsonOutput = json_encode($data);

echo $jsonOutput;
