<?php

use Webuccino\Install\Core\App;
use Webuccino\Install\Core\Session;
use Webuccino\Install\Core\Database;
use Webuccino\Install\Core\Response;

function urlIs($value)
{

    $uri = parse_url($_SERVER['REQUEST_URI'])['path'];

    $install_dir = config_native("srm_config.installer.install_dir");

    $uri = isset(explode("/$install_dir/index.php", $uri)[1]) ? explode("/$install_dir/index.php", $uri)[1] : explode("/$install_dir/index.php", $uri)[0];

    return rtrim($uri, "/") === rtrim($value, "/");
}

function config_native($path, $default = null)
{
    $file_name = explode('.', $path)[0];

    if (file_exists('../dashboard/config/' . $file_name . ".php")) {
        $data = require base_path_native('../dashboard/config/' . $file_name . ".php");
    } else {
        return $default;
    }

    $paths = array_slice(explode('.', $path), 1);

    $result = $data;

    foreach ($paths as $path) {
        $result = $result[$path];
    }

    return $result;
}

function write_config_native($path, $content)
{
    return file_put_contents($path, $content) !== false;
}

function write_srm_install_config_native($status)
{
    $path         = BASE_PATH . '../dashboard/config/srm_install_config.php';
    $security_key = empty(config_native('srm_install_config.security_key'))
    ? "base64:" . base64_encode(random_bytes(32))
    : config_native('srm_install_config.security_key');

    $data = <<<EOT
    <?php

    //defined('ACCESS') or die("No direct access allowed!");

    return [
        "status" => "$status",
        "security_key" => "$security_key"
    ];

    EOT;

    return write_config_native($path, $data);
}

function write_srm_db_config_native($driver, $host, $db_name, $db_user, $db_password, $db_port = '')
{
    $path = BASE_PATH . '../dashboard/config/srm_db_config.php';

    $data = <<<EOT
    <?php

    //defined('ACCESS') or die("No direct access allowed!");

    return [
        "driver" => "$driver",
        "host" => "$host",
        "database" => "$db_name",
        "username" => "$db_user",
        "password" => "$db_password",
        "port" => "$db_port",
    ];
    EOT;

    return write_config_native($path, $data);
}

function check_directories_permission()
{

    if (!write_srm_install_config_native("inprogress")) {
        $permission_error = "Please ensure that you have properly granted read/write permissions to the necessary directories";
        Session::flash('permission_error', $permission_error);

        redirect_native(route_native("/permissions"));
    }

}

function check_write_permissions()
{

    $directories = config_native('srm_config.installer.read_write_directories', []);

    $non_writable_dirs = [];

    foreach ($directories as $dir) {

        if (!is_writable(BASE_PATH . "../../" . $dir)) {
            $non_writable_dirs[] = $dir;
        }

    }

    return $non_writable_dirs;
}

function check_is_writeable_config_native($config)
{
    $path = BASE_PATH . "../dashboard/config/$config.php";

    if (!is_writeable($path)) {
        $permission_error = "Please ensure that you have properly granted read/write permissions to the necessary directories";
        Session::flash('permission_error', $permission_error);

        redirect_native(route_native("/permissions"));
    }

}

// function check_database_step()

// {

//     if (!Session::get('connection-success'))

//         redirect_native(route_native('/database'));
// }

function check_migration_step()
{

    if (config_native('srm_db_config')) {
        $db = App::resolve(Database::class);

        // $last_step = $db->first("installed_versions, [["is_current", true]])->install_last_success_step;
        if (!Session::has('database-imported') && !$db->hasTable("installed_versions")) {
            redirect_native(route_native('/database'));
        }

    } else {
        if (!Session::has('database-imported')) {
            redirect_native(route_native('/database'));
        }

    }

}

function check_profile_step()
{
    if (is_null(Session::get('profile-created'))) {
        redirect_native(route_native('/profile'));
    }

}

function abort_native($code = 404)
{
    http_response_code($code);

    require base_path_native("views/{$code}.php");

    die();
}

function authorize($condition, $status = Response::FORBIDDEN)
{
    if (!$condition) {
        abort_native($status);
    }

    return true;
}

function base_path_native($path)
{
    return BASE_PATH . $path;
}

function get_protocol()
{
    if (
        isset($_SERVER['HTTPS']) &&
        ($_SERVER['HTTPS'] == 'on' || $_SERVER['HTTPS'] == 1) ||
        isset($_SERVER['HTTP_X_FORWARDED_PROTO']) &&
        $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https'
    ) {
        $protocol = 'https://';
    } else {
        $protocol = 'http://';
    }

    return $protocol;
}

function route_native($path)
{

    $uri = substr(base_url(), -1) === "/" ? base_url() : base_url() . "/";

    return get_protocol() . $_SERVER['HTTP_HOST'] . $uri . ltrim($path, "/");
}

function asset_native($path)
{
    $uri = substr(base_url(), -1) === "/" ? base_url() : base_url() . "/";

    $uri = str_replace("/index.php", "", $uri);

    return get_protocol() . $_SERVER['HTTP_HOST'] . $uri . ltrim($path, "/");
}

function base_url()
{
    $install_dir = config_native("srm_config.installer.install_dir");

    return explode(
        "/" . $install_dir,
        $_SERVER["PHP_SELF"]
    )[0] . "/$install_dir/index.php";
}

function view_native($path, $attributes = [])
{
    extract($attributes);

    require base_path_native('views/' . $path);
}

function redirect_native($path)
{
    header("location: {$path}");
    exit();
}

function old_native($key, $default = '')
{
    return Session::get('old')[$key] ?? $default;
}

function check_minimum_php_version()
{

    $minimum_php_version = config_native('srm_config.installer.min_supported_version');

    $php_version_warning = config_native('srm_config.installer.php_version_warning');

    if (isset($minimum_php_version) && isset($php_version_warning)) {
        $result = [];

        $minimum_php_major_version = str_split($minimum_php_version)[0];
        $minimum_php_minor_version = str_split($minimum_php_version)[1];

        $minimum_php_version = "$minimum_php_major_version.$minimum_php_minor_version";

        $result['can_run'] = version_compare(
            phpversion(),
            $minimum_php_version,
            '>='
        ) == -1;

        $result['php_version_warning'] = str_replace(
            ['{user_PHP_Version}', '{Min_supported_version}'],
            [phpversion(), $minimum_php_version],
            $php_version_warning
        );

        return $result;
    }

    return;
}

function get_root_directory()
{
    $install_dir = config_native("srm_config.installer.install_dir");

    return explode("/$install_dir", $_SERVER['SCRIPT_FILENAME'])[0];
}

function get_cron_job_script($withPhpPath = false, $phpPath = null)
{
    $cronjobs = config_native(
        'srm_config.installer.cronjob',
        ['dashboard/scheduler.php', 'dashboard/worker.php']
    );

    $basepath = get_root_directory() . "/";

    $cronjobs = array_map(function ($cronjob) use ($basepath) {return $basepath . $cronjob;}, $cronjobs);

    if ($withPhpPath) {
        $cronjobs = array_map(function ($cronjob) use ($phpPath) {return $phpPath . " " . $cronjob;}, $cronjobs);
    }

    return implode(" && ", $cronjobs);
}

function root_url()
{
    $install_dir = config_native("srm_config.installer.install_dir");

    return get_protocol() . $_SERVER["HTTP_HOST"] . explode(
        "/" . $install_dir,
        $_SERVER["PHP_SELF"]
    )[0];
}

function login_url()
{
    $redirect = config_native("srm_config.installer.redirect");

    // Get the current request URI
    $request_uri = $_SERVER["REQUEST_URI"];

    // Determine if the request URI contains the "public" directory
    if (strpos($request_uri, "/public/") !== false) {
        // Remove "/public/" from the request URI
        $base_path = explode("/public/", $request_uri)[0];
        return get_protocol() . $_SERVER["HTTP_HOST"] . $base_path . $redirect;
    } elseif (strpos($request_uri, "/srm/") !== false) {
        $base_path = explode("/srm/", $request_uri)[0];
        return get_protocol() . $_SERVER["HTTP_HOST"] . $base_path . "/srm";
    } else {
        // Return the URL with the redirect path
        return get_protocol() . $_SERVER["HTTP_HOST"] . $redirect;
    }

}

function finish_installer()
{

    $db      = App::resolve(Database::class);
    $version = config_native('srm_config.installer.version_to_install', "v9.1.8");

    $db->updateOrInsert(
        'installed_versions',
        ['version' => $version],
        ['install_last_success_step' => "finish", 'is_install_complete' => true]
    );

    write_srm_install_config_native("complete");
}

function check_installed()
{

    $status = config_native('srm_install_config.status');

    $config = config_native('srm_db_config');

    if ($config) {

        $db = App::resolve(Database::class);
        $db->initiateConnection(
            $config["driver"],
            $config["host"],
            $config["database"],
            $config["username"],
            $config["password"],
            $config["port"]
        );

        $installed_version_exist = $db->hasTable("installed_versions") ?
        $db->checkExist(
            'installed_versions',
            [['is_current', true], ['is_install_complete', true]]
        ) : false;

        if ($status === "complete" || ($config && $installed_version_exist)) {
            return true;
        }

        return false;
    }

}

function redirect_based_on_progress()
{
    $db_config = config_native('srm_db_config');

    if (!$db_config) {
        view_native("installer/begin.view.php");
    } elseif ($db_config) {
        $db = App::resolve(Database::class);
        $db->initiateConnection(
            $db_config["driver"],
            $db_config["host"],
            $db_config["database"],
            $db_config["username"],
            $db_config["password"],
            $db_config["port"]
        );

        if (!$db->hasTable('installed_versions')) {

            return redirect_native(route_native("/database"));
        } else {

            $progress = $db->first("installed_versions", [["is_current", true]]);

            switch ($progress->install_last_success_step) {
                case "migrate":
                    Session::put('database-imported', true);
                    return redirect_native(route_native("/profile"));
                    break;
                case "profile":
                    Session::put('database-imported', true);
                    Session::put('profile-created', true);
                    return redirect_native(route_native("/settings"));
                default:
                    view_native("installer/begin.view.php");
            }

        }

    }

}

function encrypt_native($value)
{
    $key    = config_native("srm_install_config.security_key");
    $key    = base64_decode(explode("base64:", $key)[1]);
    $cipher = 'aes-256-cbc';

    $iv = random_bytes(openssl_cipher_iv_length(strtolower($cipher)));

    $value = \openssl_encrypt(
        serialize($value),
        strtolower($cipher),
        $key,
        0,
        $iv,
        $tag
    );

    if ($value === false) {
        throw new \Exception('Could not encrypt the data.');
    }

    $iv  = base64_encode($iv);
    $tag = base64_encode($tag ?? '');

    $mac = hash_hmac('sha256', $iv . $value, $key);

    $json = json_encode(compact('iv', 'value', 'mac', 'tag'), JSON_UNESCAPED_SLASHES);

    if (json_last_error() !== JSON_ERROR_NONE) {
        throw new \Exception('Could not encrypt the data.');
    }

    return base64_encode($json);
}

function decrypt_native($payload)
{
    $key    = config_native("srm_install_config.security_key");
    $key    = base64_decode(explode("base64:", $key)[1]);
    $cipher = 'aes-256-cbc';

    $payload = get_json_payload_native($payload);

    $iv = base64_decode($payload['iv']);

    $decrypted = \openssl_decrypt(
        $payload['value'],
        strtolower($cipher),
        $key,
        0,
        $iv,
        $tag ?? ''
    );

    if ($decrypted === false) {
        throw new \Exception('Could not decrypt the data.');
    }

    return unserialize($decrypted);
}

function get_json_payload_native($payload)
{
    $payload = json_decode(base64_decode($payload), true);
    $cipher  = 'aes-256-cbc';

    if (!valid_payload_native($payload)) {
        throw new \Exception('The payload is invalid.');
    }

    if (!valid_mac_native($payload)) {
        throw new \Exception('The MAC is invalid.');
    }

    return $payload;
}

function valid_payload_native($payload)
{
    $cipher = 'aes-256-cbc';

    if (!is_array($payload)) {
        return false;
    }

    foreach (['iv', 'value', 'mac'] as $item) {

        if (!isset($payload[$item]) || !is_string($payload[$item])) {
            return false;
        }

    }

    if (isset($payload['tag']) && !is_string($payload['tag'])) {
        return false;
    }

    return strlen(base64_decode($payload['iv'], true)) === openssl_cipher_iv_length(strtolower($cipher));
}

function valid_mac_native(array $payload)
{
    return hash_equals(
        hash_native($payload['iv'], $payload['value']),
        $payload['mac']
    );
}

function hash_native($iv, $value)
{
    $key = config_native("srm_install_config.security_key");
    $key = base64_decode(explode("base64:", $key)[1]);

    return hash_hmac('sha256', $iv . $value, $key);
}

function installation_method()
{
    return config_native("srm_config.installer.installation_method");
}

function is_docker()
{
    return strtolower(installation_method()) == "docker";
}

function is_hosted_version()
{
    return strtolower(installation_method()) == "hosted_version";
}

function get_final_message($docker = false)
{

    if ($docker) {
        return get_docker_final_message();
    }

    return config_native('srm_config.installer.final_message');

}

function get_docker_final_message()
{
    $message = config_native('srm_config.installer.final_message_docker');

    // $docker_id = getenv('HOSTNAME');

    // $command = "<code class='srm-code'>docker exec -it $docker_id /bin/bash -c 'rm -rf /var/www/html/srm_install'</code>";

    return $message;
}

function get_time_zones()
{

    $timezone_identifiers = DateTimeZone::listIdentifiers(DateTimeZone::ALL);
    $tz_stamp             = time();

    foreach ($timezone_identifiers as $identifier) {

        date_default_timezone_set(
            $identifier
        );

        $timezones[$identifier] = "(GMT " . date('P', $tz_stamp) . ") " . $identifier;

    }

    return $timezones;

}

function get_environment_variable($variable)
{

    if (is_docker() && !is_null(getenv('DEFAULT_CONNECTION')) && getenv('DEFAULT_CONNECTION') == "new") {

        return getenv($variable);

    }

}
