<?php

use Carbon\Carbon;
use App\Models\User;
use App\Models\Setting;
use App\Models\Resource;
use App\Models\InstalledVersion;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\File;
use App\Generators\TourGuideScriptGenerator;

if (!function_exists("get_asset")) {
    function get_asset($path)
    {
        $public_url = explode("/index.php", request()->server->get("PHP_SELF"))[0];

        return $public_url . "/$path";
    }

}

if (!function_exists("createSymblicLink")) {

    function createSymblicLink($source, $target, $name)
    {

        if (is_link($target) && !file_exists($target) && !realpath($target)) {
            try {
                unlink($target);

            } catch (Exception $e) {
                rmdir($target);
            }

        }

        if (!is_link($target) && !file_exists($target)) {

            if (@symlink($source, $target)) {
                return true;
            } else {
                return false;
            }

        } else {
            return true;
        }

    }

}

if (!function_exists("getSecurityQuestions")) {

    function getSecurityQuestions()
    {
        try {
            $questions = config('srm_config.dashboard.security_questions', false);
            return $questions;
        } catch (\Exception $e) {

            return false;
        }

    }

}

if (!function_exists("generatePassword")) {
    function generatePassword($length = 32, $letters = true, $numbers = true, $symbols = true, $spaces = false)
    {
        $password = new Collection();

        $options = (new Collection([
            'letters' => $letters === true ? [
                'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k',
                'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
                'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
                'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R',
                'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'
            ] : null,
            'numbers' => $numbers === true ? [
                '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'
            ] : null,
            'symbols' => $symbols === true ? [
                '~', '!', '#', '$', '%', '^', '&', '*', '(', ')', '-',
                '_', '.', ',', '<', '>', '?', '/', '\\', '{', '}', '[',
                ']', '|', ':', ';'
            ] : null,
            'spaces'  => $spaces === true ? [' '] : null
        ]))->filter()
            ->each(fn($c) => $password->push($c[random_int(0, count($c) - 1)]))
            ->flatten();

        $length = $length - $password->count();

        return $password->merge(
            $options->pipe(
                fn($c) => Collection::times($length, fn() => $c[random_int(0, $c->count() - 1)])
            )
        )->shuffle()
            ->implode('');
    }

}

if (!function_exists("getSettingsValue")) {

    function getSettingsValue($setting_key)
    {
        return isset(Setting::where('settings_key', $setting_key)->first()['settings_value'])
        ? Setting::where('settings_key', $setting_key)->first()['settings_value']
        : null;
    }

}

if (!function_exists("getSystemLogo")) {

    function getSystemLogo($absoulte = false)
    {

        if (!$absoulte) {

            if (File::exists('srm_storage/' . getSettingsValue('system_logo'))) {
                return get_asset('srm_storage/' . getSettingsValue('system_logo'));
            } else {
                return get_asset(getSettingsValue('system_logo'));
            }

        }

        if (File::exists('srm_storage/' . getSettingsValue('system_logo'))) {
            return public_path('srm_storage/' . getSettingsValue('system_logo'));
        } else {
            return public_path(getSettingsValue('system_logo'));
        }

    }

}

if (!function_exists("getDefaultLogo")) {

    function getDefaultLogo($absoulte = false)
    {

        if (!$absoulte) {

            return get_asset('dist/images/srm-logo.jpg');

        }

        return public_path('dist/images/srm-logo.jpg');

    }

}

if (!function_exists('saveSetting')) {
    function saveSetting($setting_key, $settings_value)
    {
        Setting::updateOrInsert([
            'settings_key' => $setting_key
        ], [
            'settings_value' => $settings_value
        ]);
    }

}

if (!function_exists('checkDemo')) {
    function checkDemo()
    {
        $demo     = config('srm_config.dashboard.demo.srm_demo_mode');
        $buy_link = config('srm_config.dashboard.demo.Buy_link');

        if (
            is_null($demo) ||
            $demo === false ||
            is_null($buy_link) ||
            filter_var($buy_link, FILTER_VALIDATE_URL) === false
        ) {
            return false;
        }

        return true;
    }

}

if (!function_exists('isCheckedGuidedTour')) {
    function isCheckedGuidedTour()
    {
        return auth()->user()->is_checked_guided_tour;
    }

}

if (!function_exists('tourScript')) {
    function tourScript()
    {
        return (new TourGuideScriptGenerator)->getTourGuide();
    }

}

if (!function_exists('getTablesPrefix')) {
    function getTablesPrefix()
    {
        return config("srm_config.installer.table_prefix", "srm_");
    }

}

if (!function_exists('getReportUrl')) {
    function getReportUrl($path)
    {
        return getBaseUrl() . getReportPath($path);
    }

}

if (!function_exists('getBaseUrl')) {

    function getBaseUrl()
    {
        return Setting::where('settings_key', 'base_url')->first()->settings_value;
    }

}

if (!function_exists('getReportPath')) {
    function getReportPath($path)
    {
        $parsedUrl = parse_url(getBaseUrl());

        if (!isset($parsedUrl['path']) || $parsedUrl['path'] === '' || $parsedUrl['path'] === '/') {
            return "/srm_modules/{$path}";
        }

        return "public/srm_modules/{$path}";

    }

}

if (!function_exists('getTablesRelation')) {

    function getTablesRelation($connection, $xTable, $yTable)
    {

        $foreignKeys = $connection->select("
        SELECT
            constraint_name as constraint_name,
            column_name as column_name,
            referenced_table_name as referenced_table_name,
            referenced_column_name as referenced_column_name
        FROM
            information_schema.key_column_usage
        WHERE
            referenced_table_name IS NOT NULL
            AND table_name = '{$xTable}'
    ");

        foreach ($foreignKeys as $foreignKey) {

            if ($foreignKey->referenced_table_name == $yTable) {
                return "{$xTable}.{$foreignKey->column_name}={$yTable}.{$foreignKey->referenced_column_name}";
            }

        }

        $foreignKeys = $connection->select("
        SELECT
            constraint_name as constraint_name,
            column_name as column_name,
            referenced_table_name as referenced_table_name,
            referenced_column_name as referenced_column_name
        FROM
            information_schema.key_column_usage
        WHERE
            referenced_table_name IS NOT NULL
            AND table_name = '{$yTable}'
    ");

        foreach ($foreignKeys as $foreignKey) {

            if ($foreignKey->referenced_table_name == $xTable) {
                return "{$yTable}.{$foreignKey->column_name}={$xTable}.{$foreignKey->referenced_column_name}";
            }

        }

    }

}

if (!function_exists('convertArrayToString')) {

    function convertArrayToString($array, $quote = "'")
    {
        return "$quote" . implode("$quote, $quote", $array) . "$quote";
    }

}

// Monday: 0

// Tuesday: 1

// Wednesday: 2

// Thursday: 3

// Friday: 4

// Saturday: 5

// Sunday: 6

if (!function_exists('getDaysOff')) {

    function getDaysOff($isString = true)
    {
        $daysOff = [4, 5];

        if ($isString) {
            return convertArrayToString($daysOff);
        }

        return $daysOff;
    }

}

if (!function_exists('getStartOfWeek')) {

    function getStartOfWeek()
    {
        return Carbon::SUNDAY;
    }

}

if (!function_exists('getEndOfWeek')) {

    function getEndOfWeek()
    {
        return Carbon::SATURDAY;
    }

}

if (!function_exists('getExceptionMethod')) {

    function getExceptionMethod(Exception $e)
    {
        // Get the stack trace
        $trace = $e->getTrace();

// The first entry is where the exception was thrown

// The second entry is the caller of that method (where it was called)
        if (isset($trace[1])) {
            $caller = $trace[1];
            if (isset($caller['class']) && isset($caller['function'])) {
                return $caller['class'] . '::' . $caller['function'];
            } elseif (isset($caller['function'])) {
                return $caller['function'];
            }

        }

        return 'Unknown method';
    }

}

if (!function_exists('addDataToSession')) {

    function addDataToSession(User $user)
    {

        unsetWizardAndReportConfig();

        $sessionData = isset($_SESSION["srm_access_session_key"]) ? $_SESSION["srm_access_session_key"] : "";

        $requiredKeys = [
            "srm_access_role",
            "srm_access_userid",
            "srm_access_username",
            "srm_access_email",
            "srm_access_group"
        ];

        if (
            empty($sessionData) ||
            !(
                is_array($sessionData) &&
                array_keys_exists($requiredKeys, $sessionData)
            )
        ) {
            $_SESSION["srm_access_session_key"] = [
                "srm_access_role"     => $user->getUserType(),
                "srm_access_userid"   => $user->user_ID,
                "srm_access_username" => $user->user_name,
                "srm_access_email"    => $user->Email,
                "srm_access_group"    => $user->getUserType() === "user" ? $user->group_id : ""
            ];
        }

    }

}

if (!function_exists('unsetWizardAndReportConfig')) {

    function unsetWizardAndReportConfig()
    {
        unset($_SESSION['srm_wizard_config']);
        unset($_SESSION['srm_report_config']);
    }

}

if (!function_exists('getOSInformation')) {

    function getOSInformation()
    {
        $osName = php_uname('s');

        try {

            if ($osName === 'Linux') {
                if (file_exists('/etc/os-release')) {
                    $osRelease = parse_ini_file('/etc/os-release');
                    if (isset($osRelease['PRETTY_NAME'])) {
                        return $osRelease['PRETTY_NAME'];
                    }

                }

                $distro = shell_exec('lsb_release -d');
                if ($distro) {
                    return trim(str_replace('Description:', '', $distro));
                }

            } elseif ($osName === 'Windows') {
                $output = shell_exec('ver');
                if ($output) {
                    return trim($output);
                }

            }

            return false;
        } catch (\Exception $e) {
            return false;
        }

    }

}

if (!function_exists('getSrmVersion')) {

    function getSrmVersion()
    {
        return InstalledVersion::where('is_current', 1)
            ->first()->version;

    }

}

if (!function_exists('getInstallationMethod')) {

    function getInstallationMethod()
    {
        return ucfirst(getSettingsValue('installation_method'));

    }

}

if (!function_exists('getCronJobScript')) {

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

        $basepath = dirname(base_path()) . "/";

        $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);
    }

}

if (!function_exists('isDocker')) {

    function isDocker($config = false)
    {
        if ($config) {
            return strtolower(config("srm_config.installer.installation_method")) == "docker";

        }

        return strtolower(getSettingsValue("installation_method")) == "docker";
    }

}

if (!function_exists('isHostedVersion')) {

    function isHostedVersion($config = false)
    {
        if ($config) {
            return strtolower(config("srm_config.installer.installation_method")) == "hosted_version";

        }

        return strtolower(getSettingsValue("installation_method")) == "hosted_version";
    }

}

if (!function_exists('getTimeZones')) {

    function getTimeZones()
    {

        $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;

    }

}

if (!function_exists('array_keys_exists')) {

    function array_keys_exists(array $keys, array $arr)
    {
        return !array_diff_key(array_flip($keys), $arr);
    }

}

if (!function_exists('checkMetricAccessPermission')) {

    function checkMetricAccessPermission(Resource $metric)
    {
        if (
            !((auth()->user() && auth()->user()->isAdminOrOwner()) || strtolower($metric->access_control_type) == "public" ||
                (auth()->user() && in_array(auth()->user()->group_id, $metric->resource_permissions->pluck("group_ID")->toArray())))
        ) {
            return false;
        }

        return true;
    }

}

if (!function_exists('sendApiNotification')) {

    function sendApiNotification($url, $data)
    {
        $ch = curl_init();

        $sharedKey = config('srm_config.dashboard.demo.shared_key');

        if (is_null($sharedKey)) {
            return;
        }

        $headers = [
            'Shared-Key: ' . $sharedKey
        ];

        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);

        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));

        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

        $response = curl_exec($ch);

        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);

        if ($httpCode == 200) {
            return true;
        } else {
            throw new \Exception("Error sending data");
        }

    }

}

if (!function_exists('formatCurrencyCompact')) {

    function formatCurrencyCompact($value, $currencySymbol = '$')
    {
        if (!is_numeric($value)) {
            return $value;
        }

        $isNegative = $value < 0;
        $value      = abs($value);

        $suffixes = ['T' => 1e12, 'B' => 1e9, 'M' => 1e6, 'K' => 1e3];

        foreach ($suffixes as $suffix => $threshold) {

            if ($value >= $threshold) {
                $formattedValue = $value / $threshold;

                $formattedValue = (abs($formattedValue - round($formattedValue, 0)) < 0.01) ?
                round($formattedValue) :
                number_format($formattedValue, 2);

                return $currencySymbol . ' ' . ($isNegative ? '-' : '') . $formattedValue . $suffix;
            }

        }

        $formattedValue = ($value == floor($value)) ?
        number_format($value) :
        number_format($value, 2);

        return $currencySymbol . ' ' . ($isNegative ? '-' : '') . $formattedValue;
    }

}

if (!function_exists('formatStandardCurrency')) {

    function formatStandardCurrency($value, $currencySymbol = '$')
    {

        if (!is_numeric($value)) {
            return $value;
        }

        $isNegative = $value < 0;
        $value      = abs($value);

        if ($value == floor($value)) {
            $formattedValue = number_format($value);
        } else {
            $formattedValue = number_format($value, 2);
        }

        return $currencySymbol . ' ' . ($isNegative ? '-' : '') . $formattedValue;
    }

}