<?php

namespace App;

use Illuminate\Database\Eloquent\Model;
use DB;
use RoleColor;
use RoleId;

/**
 * A site user account.
 */
class User extends Model {
    /**
     * Returns HTML for displaying a user's name, or HTML for an anonymous user if the user is null.
     * @param User|null $user The user, or null if anonymous.
     * @param bool $includeRank Whether to include rank HTML for the user.
     * @param bool $openInNewTab Whether to open the user link in a new tab. Optional.
     * @param string $usernameColor The username color to use. Optional.
     * @param string $usernameCss Extra username CSS to use. Optional.
     * @return string The user's name HTML or anonymous user HTML.
     */
    public static function getNameHtmlOrAnonymous(?self $user, bool $includeRank, bool $openInNewTab = false, string $usernameColor = '#2a9fd6', string $usernameCss = ''): string {
        if ($user === null) {
            return "<span "
                . "class=\"dox-username\" "
                . "title=\"Anonymous\" "
                . ">Anonymous</a>";
        } else {
            return $user->getNameHtml($includeRank, $openInNewTab, $usernameColor, $usernameCss);
        }
    }

    protected $fillable = [
        'id',
        'username',
        'email',
        'password',
        'session',
        'sess_end',
        'comments',
        'pastes',
        'joindate',
        'last_seen',
        'role',
        'admin',
        'is_manager',
        'is_developer',
        'mod',
        'council',
        'profile_pic',
        'has_small_profile_pic',
        'bio',
        'has_name_color',
        'name_color',
        'name_css',
    ];
    const UPDATED_AT = null;

    public function getProfilePicture($small = false){
        if (!$this->profile_pic) {
            return 'default.jpg';
        }
        if ($small) {
            if ($this->has_small_profile_pic) {
                $picture = explode('.', $this->profile_pic);
                return $picture[0].'_50x50.'.$picture[1];
            }
        }
        return $this->profile_pic;
    }

    public function pasteHighlightColor(): string {
        if ($this->role == RoleId::ADMIN) { // admin role ID
            return 'admin-post';
        } else if ($this->role == RoleId::MANAGER) { // Manager role ID.
            return 'manager-post';
        } else if ($this->role == RoleId::MOD) { // mod role ID
            return 'mod-post';
        } else if ($this->role == RoleId::COUNCIL) { // council role ID
            return 'council-post';
        } else if ($this->role == 96) { // founder role ID
            return 'founder-post';
        } else if ($this->role == 95) {
            return 'clique-post';
        } else if ($this->role == 3) {
            return 'rich-post';
        } else if ($this->role == 2) {
            return 'criminal-post';
        } else if ($this->role == 1) {
            return 'vip-post';
        } else {
            return '';
        }
    }

    public function getNameStyle($c = '#2a9fd6', $e = ''): string {
        $color = 'color: '. htmlspecialchars($c) . ';' . htmlspecialchars($e);

        if ($this->name_color != null) {
            
            $color = 'color: #'.$this->name_color.';';
            
            // Changed this to have the font-weight bold for the Developer role
            if ($this->role >= RoleId::DEVELOPER) {
                $color .= 'font-weight: bold;';
            }
            
            $role = DB::table('roles')->where('id', $this->role)->first();

            if (!is_null($role) && $this->role < RoleId::MOD) { // add role css (rich sparkles)
                $color .= 'font-weight: bold;' . htmlspecialchars($role->css);
            }
        } else if ($this->role == RoleId::ADMIN) {

            $color = 'color: #' . RoleColor::ADMIN . '; font-weight: bold;';

        } else if ($this->role == RoleId::MANAGER) {

            $color = 'color: #' . RoleColor::MANAGER . '; font-weight: bold;';

        } else if($this->role == RoleId::MOD) {

            $color = 'color: #' . RoleColor::MOD . '; font-weight: bold;';

        } else if ($this->role == RoleId::COUNCIL) {

            $color = 'color: #' . RoleColor::COUNCIL . '; font-weight: bold;';

        } else if($this->role != 0) {

            $role = DB::table('roles')->where('id', $this->role)->first();

            if(!is_null($role)){
                $color = 'color: #' . $role->color . '; font-weight: bold;'.$role->css;
            }

        }
        if ($this->name_css != null) { // add extra css if used
            $color .= $this->name_css;
        }

        return $color;
    }

    public function getRankHtml() {
        $style = '';

        if ($this->isAdmin()) {
            $style = '<span style="color:#' . RoleColor::ADMIN . ';font-weight:bold;">[Admin]</span>';
        } else if ($this->isManager()) {
            $style = '<span style="color:#' . RoleColor::MANAGER . ';font-weight:bold;">[Manager]</span>';
        } else if ($this->isMod()) {
            $style = '<span style="color:#' . RoleColor::MOD . ';font-weight:bold;">[Mod]</span>';
        } else if ($this->isCouncil()) {
            $style = '<span style="color:#' . RoleColor::COUNCIL . ';font-weight:bold;">[Council]</span>';
        } else if ($this->role != 0) {
            $role = DB::table('roles')
                ->where('id', $this->role)
                ->first();
            
            if (!is_null($role)) {
                $style = '<span style="color: #' . htmlspecialchars($role->color) . ';' . htmlspecialchars($role->css) . '">[' . htmlspecialchars($role->text) . ']</span>';
            }
        }

        return $style;
    }

    public function getNameHtml(bool $includeRank, bool $openInNewTab = false, string $usernameColor = '#2a9fd6', string $usernameCss = ''): string {
        $usernameSanitized = htmlspecialchars($this->username);
        $target = $openInNewTab ? '_blank' : '_self';
        $suffix = $includeRank ? ' ' . $this->getRankHtml() : '';

        return "<a "
            . "class=\"dox-username\" "
            . "href=\"/user/$usernameSanitized\" "
            . "title=\"$usernameSanitized\" "
            . "target=\"$target\" "
            . "style=\"" . $this->getNameStyle($usernameColor, $usernameCss) . "\" "
            . ">$this->username$suffix</a>";
    }

    public function getNavNameHtml(string $defaultUsernameColor = '#2a9fd6', string $defaultUsernameCss = '', bool $includeRank = false) {

        $element = '<p class="dropbtn" style="display:inline-block;'. $this->getNameStyle($defaultUsernameColor, $defaultUsernameCss) .'">'.$this->username.'</p>';

        if ($includeRank) {
            $element .= ' ' . $this->getRankHtml();
        }

        return $element;
    }

    public function getPasteCount($role=0) {
        if ($role < RoleId::MOD) {
            return Paste::where(['created_by' => $this->id, 'hidden' => 0, 'private' => 0, 'unlisted' => 0])->count();
        } else if ($role == RoleId::MOD) {
            return Paste::where(['created_by' => $this->id, 'private' => 0, 'unlisted' => 0])->where(function($q){
                $q->whereDate('hidden_at', '>=', Carbon\Carbon::now());
                $q->orWhere('hidden_at', '=', null);
            })->count();
        } else if ($role > RoleId::ADMIN) {
            return Paste::where('created_by',$this->id)->count();
        }
    }

    public function getCommentCount($role=0): int {
        if ($role < RoleId::MOD) {
            return DB::table('comments')->where(['created_by' => $this->id, 'hidden' => 0])->count();
        } else {
            return DB::table('comments')->where('created_by', $this->id)->count();
        }
    }

    public function isFollowing($uid) {
        if ($this->following < 1 || !is_numeric($uid)) {
            return (int)false;
        }
        $following = DB::table('followers')->where(['uid' => $uid, 'fid' => $this->id])->count();

        return (int)($following > 0);
    }

    /**
     * Returns whether the user is an administrator (or higher if specified).
     * @param bool $orHigher Whether to also return true if the user possesses a higher role. Default is false. Currently has no effect.
     * @return bool Whether the user is an administrator.
     */
    public function isAdmin(bool $orHigher = false): bool {
        return (bool)($this->admin);
    }

    /**
     * Returns whether the user is a manager (or higher if specified).
     * @param bool $orHigher Whether to also return true if the user possesses a higher role. Default is false.
     * @return bool Whether the user is a manager.
     */
    public function isManager(bool $orHigher = false): bool {
        return (bool)($orHigher ? ($this->is_manager || $this->admin) : $this->is_manager);
    }

    /**
     * Returns whether the user is a moderator (or higher if specified).
     * @param bool $orHigher Whether to also return true if the user possesses a higher role. Default is false.
     * @return bool Whether the user is a moderator.
     */
    public function isMod(bool $orHigher = false): bool {
        return (bool)($orHigher ? ($this->mod || $this->is_manager || $this->admin) : $this->mod);
    }

    /**
     * Returns whether the user is a developer (or higher if specified).
     * @param bool $orHigher Whether to also return true if the user possesses a higher role. Default is false.
     * @return bool Whether the user is a developer.
     */
    public function isDeveloper(bool $orHigher = false): bool {
        return (bool)($orHigher ? ($this->is_developer || $this->mod || $this->is_manager || $this->admin) : $this->is_developer);
    }

    /**
     * Returns whether the user is a Council member (or higher if specified).
     * @param bool $orHigher Whether to also return true if the user possesses a higher role. Default is false.
     * @return bool Whether the user is a Council member.
     */
    public function isCouncil(bool $orHigher = false): bool {
        return (bool)($orHigher ? ($this->council || $this->is_developer || $this->mod || $this->is_manager || $this->admin) : $this->council);
    }

    /**
     * Returns the user's bio HTML.
     * If the user is a developer & manager or higher, the bio will be returned verbatim.
     * If not, the user's bio will be escaped to prevent XSS.
     * @return string The user's bio HTML.
     */
    public function getBioHtml(): string {
        $bio = $this->bio;
        if ($bio == null) {
            return '';
        } else if ($this->isCouncil(true) || $this->id == 1 || $this->id == 2 || $this->id == 42663 || $this->id == 357260 || $this->id == 279720) { // allows for council+ to have html in bio. only allowed certain tags to be used. this is fine for everyone including admins as we only use these tags anyways. Reiko, Mar 15th 2024
            $bio = strip_tags($bio, '<b><i><u><em><strong><a>'); // only tags allow. Reiko, Mar 15th 2024
            return $bio;
        } else {
            return htmlspecialchars($bio);
        }
    }
    
    public function applyUpgrade($productId, $notify = true, $invoiceId = null) {
        $order = null;
        if (!is_null($invoiceId)) {
            $order = Order::where('order_id', $invoiceId)->first();
                
            if (is_null($order)) {
                return "error";
            }
        }
        $save = false;
        $removed = false; // did something get removed from the user?
        if (is_null($order) || !$order->complete) { // if theres an order, and its not completed already
            if ($productId == 1) {       // Name Colors
                if ($this->has_name_color) { // already has it; remove
                    $this->has_name_color = 0;
                    $notify = false;
                    $removed = true;
                    $save = true;
                } else {
                    $this->has_name_color = 1;
                    $save = "Change name color";
                }

            } else if ($productId > 1 && $productId < 5) { // a rank
                if ($this->role == $productId - 1) { // if they have it; remove
                    $this->role = 0;
                    $this->name_changes = 0;
                    $notify = false;
                    $removed = true;
                    $save = true;
                } else if ($productId == 2) { // VIP
                    $this->role = 1;
                    $save = "VIP rank";
                    $this->name_changes = 1;
                } else if($productId == 3) { // Criminal
                    $this->role = 2;
                    $save = "Criminal rank";
                    $this->name_changes = 2;
                } else if($productId == 4) { // Rich
                    $this->role = 3;
                    $save = "Rich rank";
                    $this->name_changes = 3;
                }
            }
        }

        if ($save) {
            $this->save();

            if (!is_null($order)) {
                $order->complete = 1;
                $order->save();
            }

            if ($notify) {
                DB::table('notifications')->insert(['uid' => $this->id, 'type' => 6, 'text' => 'Your purchase of \'' . $save . '\' was successful.', 'date' => floor(microtime(true) * 1000)]);
            }
        }

        if ($removed) {
            return "removed";
        }
        return "done";
    }
}
