<?php

namespace IMATHUZH\Qfq\Core\Helper\Version;

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

/**
 * Helper class for backend user management operations.
 * Handles CRUD operations for backend users, maintainer status, and frontend user info.
 */
class BackendUserManager
{
    /**
     * Get all backend users with admin and maintainer status
     *
     * @param Database $db
     * @param array $systemMaintainers
     * @return array
     */
    public static function getAllBackendUsers(Database $db, array $systemMaintainers = []): array {
        $users = $db->sql(
            "SELECT uid, username, admin, email, realName, disable FROM be_users WHERE deleted = 0",
            ROW_REGULAR
        );

        return array_map(function ($user) use ($systemMaintainers) {
            $uid = (int)$user[T3_BE_USERS_UID];
            return [
                API_RESULT_KEY_UID => $uid,
                BE_USER_KEY_USERNAME => $user[T3_BE_USERS_USERNAME],
                BE_USER_KEY_REAL_NAME => $user[T3_BE_USERS_REAL_NAME],
                BE_USER_KEY_EMAIL => $user[T3_BE_USERS_EMAIL],
                BE_USER_KEY_IS_ADMIN => (bool)$user[T3_BE_USERS_ADMIN],
                BE_USER_KEY_IS_MAINTAINER => in_array($uid, $systemMaintainers, true),
                BE_USER_KEY_IS_DISABLED => (bool)$user[T3_BE_USERS_DISABLE],
            ];
        }, $users);
    }

    /**
     * Ensure backend users have correct admin/maintainer/disabled status
     *
     * @param array|string $config JSON string or array with username => settings mapping
     * @param Database $db
     * @param array $systemMaintainers Current system maintainers (will be updated by reference)
     * @return array
     */
    public static function ensureAdminMaintainers(array|string $config, Database $db, array &$systemMaintainers): array {
        // Accept JSON string or array
        if (is_string($config)) {
            $config = json_decode($config, true);
            if (json_last_error() !== JSON_ERROR_NONE) {
                throw new \InvalidArgumentException('Invalid JSON: ' . json_last_error_msg());
            }
        }

        $originalMaintainers = $systemMaintainers;
        $results = [];

        foreach ($config as $username => $settings) {
            $isAdmin = (bool)($settings[BE_USER_KEY_IS_ADMIN] ?? false);
            $isMaintainer = (bool)($settings[BE_USER_KEY_IS_MAINTAINER] ?? false);
            $isDisabled = (bool)($settings[BE_USER_KEY_IS_DISABLED] ?? false);
            $delete = (bool)($settings[BE_USER_KEY_DELETE] ?? false);

            $result = [
                BE_USER_KEY_USERNAME => $username,
                API_RESULT_KEY_UID => null,
                BE_USER_KEY_CREATED => false,
                API_RESULT_KEY_CHANGES => [],
            ];

            // Check if user exists
            $existing = $db->sql(
                "SELECT uid, admin, disable, deleted FROM be_users WHERE username = ?  AND deleted = ?",
                ROW_EXPECT_0_1,
                [$username, 0]
            );

            if (!empty($existing)) {
                $uid = (int)$existing[API_RESULT_KEY_UID];
                $result[API_RESULT_KEY_UID] = $uid;
                $updates = [];

                // Check admin flag
                if ((bool)$existing[T3_BE_USERS_ADMIN] !== $isAdmin) {
                    $updates[] = T3_BE_USERS_ADMIN . ' = ' . ($isAdmin ? 1 : 0);
                    $result[API_RESULT_KEY_CHANGES][] = $isAdmin ? 'admin granted' : 'admin revoked';
                }

                // Check disable flag
                if ((bool)$existing[T3_BE_USERS_DISABLE] !== $isDisabled) {
                    $updates[] = T3_BE_USERS_DISABLE . ' = ' . ($isDisabled ? 1 : 0);
                    $result[API_RESULT_KEY_CHANGES][] = $isDisabled ? 'disabled' : 'enabled';
                }

                if ((bool)$existing[T3_BE_USERS_DELETED] !== $delete) {
                    $updates[] = T3_BE_USERS_DELETED . ' = ' . ($delete ? 1 : 0);
                    $result[API_RESULT_KEY_CHANGES][] = $delete ? 'deleted' : 'revoke delete';
                }

                if (!empty($updates)) {
                    $updates[] = 'tstamp = ' . time();
                    $db->sql("UPDATE be_users SET " . implode(', ', $updates) . " WHERE uid = ?", ROW_REGULAR, [$uid]);
                }
            } else if (!$delete) {
                // Create new user
                $db->sql(
                    "INSERT INTO be_users (username, admin, disable, password, tstamp, crdate) VALUES (?, ?, ?, '', ?, ?)",
                    ROW_REGULAR,
                    [$username, $isAdmin ? 1 : 0, $isDisabled ? 1 : 0, time(), time()]
                );
                $uid = $db->getLastInsertId();
                $result[API_RESULT_KEY_UID] = $uid;
                $result[BE_USER_KEY_CREATED] = true;
                $result[API_RESULT_KEY_CHANGES][] = 'user created';
            }

            // Handle maintainer status
            $isCurrentlyMaintainer = in_array($uid, $systemMaintainers, true);

            if ($isMaintainer && !$isCurrentlyMaintainer) {
                $systemMaintainers[] = $uid;
                $result[API_RESULT_KEY_CHANGES][] = 'maintainer added';
            } elseif (!$isMaintainer && $isCurrentlyMaintainer) {
                $systemMaintainers = array_values(array_filter($systemMaintainers, fn($id) => $id !== $uid));
                $result[API_RESULT_KEY_CHANGES][] = 'maintainer removed';
            }

            $results[] = $result;
        }

        // Check if maintainers changed
        $maintainersChanged = $systemMaintainers !== $originalMaintainers;

        // Write to config if changed
        if ($maintainersChanged) {
            self::setSystemMaintainersToConfig(array_values($systemMaintainers));
        }

        return [
            OIDC_KEY_PROCESSED => count($results),
            'maintainersUpdated' => $maintainersChanged,
            OIDC_KEY_RESULTS => $results,
        ];
    }

    /**
     * Write systemMaintainers to LocalConfiguration.php
     *
     * @param array $maintainers
     */
    private static function setSystemMaintainersToConfig(array $maintainers): void {
        $localConfPath = Path::absoluteTypo3Conf('LocalConfiguration.php');
        if (!file_exists($localConfPath)) {
            return;
        }

        $config = include $localConfPath;
        $config[TYPO3_CONF_SYS][TYPO3_CONF_SYSTEM_MAINTAINERS] = $maintainers;

        $content = "<?php\nreturn " . var_export($config, true) . ";\n";
        file_put_contents($localConfPath, $content);

        // Clear TYPO3 system cache if available
        self::clearSystemCache();
    }

    /**
     * Clear TYPO3 system cache
     */
    public static function clearSystemCache(): void {
        $possiblePaths = [
            Path::absoluteTypo3Conf('../typo3temp/var/cache'), // Upgrade or legacy installations
            Path::absoluteTypo3Conf('../var/cache'),           // Fresh TYPO3 >= 11
        ];

        foreach ($possiblePaths as $cacheDir) {
            if (is_dir($cacheDir)) {
                $codeCacheDir = $cacheDir . '/code/cache_core';
                if (is_dir($codeCacheDir)) {
                    array_map('unlink', glob($codeCacheDir . '/*') ?: []);
                }
            }
        }
    }

    /**
     * Get active frontend users information (count and activity timestamps)
     *
     * @param Database $db
     * @return array
     */
    public static function getActiveFrontendUsersInfo(Database $db): array {
        $result = $db->sql(
            "SELECT COUNT(DISTINCT ses_userid) as count, MIN(ses_tstamp) as firstTimestamp, MAX(ses_tstamp) as lastTimestamp FROM fe_sessions WHERE ses_userid > 0",
            ROW_EXPECT_0_1
        );

        return [
            'activeCount' => (int)($result['count'] ?? 0),
            'firstActiveDatetime' => $result['firstTimestamp'] ? date('Y-m-d H:i:s', $result['firstTimestamp']) : null,
            'lastActiveDatetime' => $result['lastTimestamp'] ? date('Y-m-d H:i:s', $result['lastTimestamp']) : null
        ];
    }
}
