<?php

use App\User;
use Illuminate\Http\Request;

/**
 * Returns all app domains.
 * @return string[]
 */
function appDomains(): array {
    static $domains = null;
    if ($domains === null) {
        $domains = explode(',', env('APP_DOMAINS') ?? '');
    }

    return $domains;
}

function currentDomain() {
    $domain = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : 'doxbin.com';
    if (in_array($domain, appDomains())) {
        return $domain;
    } else {
        exit; // error
    }
}

function sendDiscordWebhook($name, $msg, $embed = null){
    return false;

    $url = env('DISCORD_WEBHOOK');
    $data = ['content' => $msg,
            'username' => $name,
            ];
            
    if(!is_null($embed)){
        $data['embeds'][] = $embed;
    }
    $data = json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE );
    $curl = curl_init($url);
    curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "POST");
    curl_setopt($curl, CURLOPT_HTTPHEADER, array('Content-Type:application/json', "Length" => strlen($data)));
    curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
    // return dd($data);
    return curl_exec($curl);
}

function age($time){
    $time = floor(microtime(true) * 1000) - $time;
    $result = "now";
    if($time > 31557600000)       return floor($time / 31557600000)." year".(floor($time / 31557600000) > 1 ? 's ago' : ' ago');
    if($time > 2592000000)        return floor($time / 2592000000)." month".(floor($time / 2592000000) > 1 ? 's ago' : ' ago');
    if($time > 604800000)         return floor($time / 604800000)." week".(floor($time / 604800000) > 1 ? 's ago' : ' ago');
    if($time > 86400000)          return floor($time / 86400000)." day".(floor($time / 86400000) > 1 ? 's ago' : ' ago');
    if($time > 3600000)           return floor($time / 3600000)." hour".(floor($time / 3600000) > 1 ? 's ago' : ' ago');
    if($time > 60000)             return floor($time / 60000)." minute".(floor($time / 60000) > 1 ? 's ago' : ' ago');
    if($time > 1000)              return floor($time / 1000)." second".(floor($time / 1000) > 1 ? 's ago' : ' ago');
    return $result;
}

function in($time){
    $time -= floor(microtime(true) * 1000);
    $result = "now";
    if($time > 60000)             return floor($time / 60000)." minute".(floor($time / 60000) > 1 ? 's' : '');
    if($time > 1000)              return floor($time / 1000)." second".(floor($time / 1000) > 1 ? 's' : '');
    return $result;
}


function getUser($bypass = false){
    $myUser = null;
    if (isset($_COOKIE['session'])) {
        $temp = DB::table('users')->where('session', $_COOKIE['session'])->limit(1)->get();
        if (count($temp) > 0) {
            if (get_class($temp[0]) == App\User::class) {
                $myUser = $temp[0];
            } else {
                // The object needs to be created manually and filled because it did not come in as a User object.
                $myUser = new App\User();
                $myUser->fill(get_object_vars($temp[0]));
            }

            if ($myUser->sess_end <= floor(microtime(true) * 1000)) {
                DB::table('users')->where('id', $myUser->id)->update(['session' => NULL, 'sess_end' => NULL]);
                setcookie('session', '', 1000, '/');
                $myUser = null;
            } else {
                if (!$bypass) {
                    if ($myUser->tfa_locked) {
                        header('Location: /account/locked');
                        exit();
                    }

                    if ((($myUser->tfa_enabled || $myUser->tfa_forced || $myUser->isCouncil(true)) && !$myUser->tfa_auth)) {
                        if (!$myUser->tfa_enabled) {
                            if($_SERVER['REQUEST_METHOD'] == 'GET'){
                                header('Location: /verify/new');
                                exit;
                            }
                        } else {
                            if($_SERVER['REQUEST_METHOD'] == 'GET'){
                                header('Location: /verify');
                                exit;
                            }
                        }
                        return null; // deny all post requests until they log in
                    }
                }
            }
        }
    }
    return $myUser;
}

function newGetUser(bool $bypass = false): ?User {
    static $withBypass = null;
    static $withoutBypass = null;

    if ($bypass && $withBypass !== null) {
        return $withBypass;
    } else if (!$bypass && $withoutBypass !== null) {
        return $withoutBypass;
    }

    $myUser = null;
    if(isset($_COOKIE['session'])){
        $myUser = User::where('session', $_COOKIE['session'])->first();
        if(!is_null($myUser)){
            if($myUser->sess_end <= floor(microtime(true) * 1000)){
                $myUser->session = NULL;
                $myUser->sess_end = NULL;
                $myUser->tfa_auth = 0;
                setcookie('session', '', 1000, '/');
            }else{
                if(!$bypass){
                    if($myUser->tfa_locked){
                        header('Location: /account/locked');
                        exit();
                    }
                    if ((($myUser->tfa_enabled || $myUser->tfa_forced || $myUser->isCouncil(true)) && !$myUser->tfa_auth)) {
                        if(!$myUser->tfa_enabled){
                            if($_SERVER['REQUEST_METHOD'] == 'GET'){
                                header('Location: /verify/new');
                                exit;
                            }
                        }else{
                            if($_SERVER['REQUEST_METHOD'] == 'GET'){
                                header('Location: /verify');
                                exit;
                            }
                        }
                        return null; // deny all post requests until they log in
                    }
                }
            }
        }
    }

    if ($bypass) {
        $withBypass = $myUser;
    } else {
        $withoutBypass = $myUser;
    }

    return $myUser;
}

/**
 * Returns whether the specified username is on the tracked usernames list.
 * @param string $username The username (case-insensitive).
 * @return bool Whether the username is on the list.
 */
function isUsernameOnTrackedUsernamesList(string $username): bool {
    // Convert for case-insensitivity.
    $username = strtolower($username);

    static $usernames = null;

    if ($usernames === null) {
        $usernames = explode(',', env('TRACKED_USERNAMES'));

        // Process all usernames to ensure that they are trimmed and lowercase.
        // Because we are already iterating over the array, we can return whether the username was found from here.
        $has = false;
        foreach ($usernames as $i => $un) {
            $unProc = strtolower(trim($un));

            if ($username === $unProc) {
                $has = true;
            }

            $usernames[$i] = $unProc;
        }
        return $has;
    }

    // Check for the username in list.
    foreach ($usernames as $un) {
        if ($username === $un) {
            return true;
        }
    }

    // The username was not found.
    return false;
}

/**
 * Logs a user tracking message to the log file.
 * @param string $msg The message to log.
 * @return void
 */
function logUserTrackingMessage(string $msg): void {
    static $file = null;

    if ($file === null) {
        $file = env("TRACKING_FILE");
    }

    // Write log message.
    file_put_contents($file, "$msg\n\n", FILE_APPEND | LOCK_EX);
}

/**
 * Creates a request info dump string containing the following values:
 *  - Date in ISO format
 *  - Path
 *  - IP address (resolved from reverse proxy headers, if appropriate)
 *  - User agent string (if present)
 * @param Request $request The request to use for creating the info dump
 * @return string The request info dump string
 */
function createRequestInfoDump(Request $request): string {
    $date = (new DateTime())->format(DateTimeInterface::ATOM);
    $path = $request->path();
    $ip = $_SERVER[$_SERVER['REAL_IP_HEADER'] ?? 'HTTP_X_FORWARDED_FOR'] ?? $_SERVER['REMOTE_ADDR'];
    $userAgent = $_SERVER['HTTP_USER_AGENT'] ?? 'None';

    // Log message:
    return "Date: $date\nPath: $path\nIP: $ip\nUser-Agent: $userAgent";
}

/**
 * Creates a new User object using user information from an object.
 * This assumes that all columns in the constant MINIMUM_USER_COLUMNS_FOR_DISPLAY are included.
 * If the values are null, null will be returned.
 * @param object $object The object with user info.
 * @param string $userIdKey The foreign key column corresponding to the user's ID.
 * @return User|null The user derived from the object, or null if not present.
 */
function createUserFromObjectWithUserInfo(object $object, string $userIdKey): ?User {
    if ($object == null || ($object->username ?? null) == null) {
        return null;
    }

    $user = new App\User();
    $user->fill([
        'id' => $object->$userIdKey,
        'username' => $object->username,
        'name_color' => $object->name_color,
        'name_css' => $object->name_css,
        'profile_pic' => $object->profile_pic,
        'has_small_profile_pic' => $object->has_small_profile_pic,
        'role' =>$object->role,
        'council' => $object->council,
        'mod' => $object->mod,
        'admin' => $object->admin,
        'is_manager' => $object->is_manager,
        'is_developer' => $object->is_developer,
    ]);

    return $user;
}
