<?php
declare(strict_types=1);
if (!defined('GRPG_INC')) {
    exit;
}

/**
 *
 */
class User
{
    public int $cocaine;
    public int $houseawake = 0;
    public int $eqweapon = 0;
    public int $eqarmor = 0;
    public int $id = 0;
    public int $level = 0;
    public int $city = 0;
    public int $marijuana = 0;
    public int $potseeds = 0;
    public int $nodoze = 0;
    public int $genericsteroids = 0;
    public int $hookers = 0;
    public int $ban = 0;
    public int $age_int = 0;
    public int $rmdays = 0;
    public int $house = 0;
    public int $admin = 0;
    public int $gang = 0;
    public int $whichbank = 0;
    public int $gangleader = 0;
    public int $jail = 0;
    public int $job = 0;
    public int $hospital = 0;
    public int $searchdowntown = 0;
    public string $weaponname = '';
    public string $weaponimg = '';
    public string $armorname = '';
    public string $armorimg = '';
    public string $housename = '';
    public string $ip = '';
    public string $cityname = '';
    public string $citydesc = '';
    public string $signature = '';
    public string $username = '';
    public string $gender = '';
    public string $formattedexp = '';
    public string $formattedhp = '';
    public string $formattedenergy = '';
    public string $formattednerve = '';
    public string $formattedawake = '';
    public string $lastactive = '';
    public string $signuptime = '';
    public string $age = '';
    public string $formattedlastactive = '';
    public string $email = '';
    public string $quote = '';
    public string $avatar = '';
    public string $class = '';
    public string $gangname = '';
    public string $gangtag = '';
    public string $gangdescription = '';
    public string $formattedgang = '';
    public string $formattedname = '';
    public string $type = '';
    public string $formattedonline = '';
    public float $weaponoffense = 0;
    public float $armordefense = 0;
    public float $speedbonus = 0;
    public float $exp = 0;
    public float $maxexp = 0;
    public float $exppercent = 0;
    public float $money = 0;
    public float $bank = 0;
    public float $maxhp = 0;
    public float $energy = 0;
    public float $maxenergy = 0;
    public float $nerve = 0;
    public float $maxnerve = 0;
    public float $awake = 0;
    public float $maxawake = 0;
    public float $hppercent = 0;
    public float $energypercent = 0;
    public float $nervepercent = 0;
    public float $awakepercent = 0;
    public float $workexp = 0;
    public float $strength = 0;
    public float $defense = 0;
    public float $speed = 0;
    public float $totalattrib = 0;
    public float $battlewon = 0;
    public float $battlelost = 0;
    public float $battletotal = 0;
    public float $battlemoney = 0;
    public float $crimesucceeded = 0;
    public float $crimefailed = 0;
    public float $crimetotal = 0;
    public float $crimemoney = 0;
    public float $points = 0;
    public float $hp = 0;
    public float $moddedstrength = 0;
    public float $moddedspeed = 0;
    public float $moddeddefense = 0;
    public bool $validated = false;
    private database $db;

    /**
     * @param int $id
     */
    public function __construct(int $id = 0)
    {
        $this->db = database::getInstance();
        if (!is_numeric($id)) {
            code_error('Invalid ID passed to User');
            return;
        }
        $this->db->query('SELECT * FROM users WHERE id = ?', [$id]);
        $row = $this->db->fetch(true);
        if ($row === null) {
            return;
        }
        $this->db->query('SELECT COUNT(id) FROM pending_validations WHERE username = ?', [$row['username']]);
        $this->validated = (bool)$this->db->result() !== true;
        $this->populateEquipment($row);
        $this->db->query('SELECT id, name, awake FROM houses WHERE id = ?', [$row['house']]);
        $house            = $this->db->fetch(true) ?? ['name' => '', 'awake' => 100];
        $this->housename  = $house['name'];
        $this->houseawake = (int)$house['awake'];
        $this->id         = (int)$row['id'];
        $this->ip         = $row['ip'];
        $this->exp        = (float)$row['experience'];
        $this->level      = Get_The_Level($this->exp);
        $this->maxexp     = experience($this->level + 1);
        $this->exppercent = (float)($this->exp > 0 && $this->maxexp > 0 ? floor(($this->exp / $this->maxexp) * 100) : 0);
        $this->populateCity($row);
        $this->signature       = $row['signature'];
        $this->username        = $row['username'];
        $this->marijuana       = (int)$row['marijuana'];
        $this->potseeds        = (int)$row['potseeds'];
        $this->nodoze          = (int)$row['nodoze'];
        $this->genericsteroids = (int)$row['genericsteroids'];
        $this->hookers         = (int)$row['hookers'];
        $this->money           = (float)$row['money'];
        $this->bank            = (float)$row['bank'];
        $this->points          = (float)$row['points'];
        $this->rmdays          = (int)$row['rmdays'];
        $this->gender          = $row['gender'];
        $this->whichbank       = (int)$row['whichbank'];
        $this->ban             = (int)$row['ban'];
        $this->populateStats($row);
        $this->workexp             = (float)$row['workexp'];
        $this->lastactive          = $row['lastactive'];
        $this->signuptime          = $row['signuptime'];
        $this->age                 = howlongago($this->signuptime);
        $this->age_int             = time() - strtotime($this->signuptime);
        $this->formattedlastactive = howlongago($this->lastactive, true);
        $this->house               = (int)$row['house'];
        $this->email               = $row['email'];
        $this->admin               = (int)$row['admin'];
        $this->quote               = $row['quote'];
        $this->avatar              = $row['avatar'];
        $this->gang                = (int)$row['gang'];
        $this->class               = $row['class'];
        $this->populateGang();
        $this->jail           = (int)$row['jail'];
        $this->job            = (int)$row['job'];
        $this->hospital       = (int)$row['hospital'];
        $this->searchdowntown = (int)$row['searchdowntown'];
        $this->setFormattedName();
        $this->setFormattedOnline();
        if ($this->exp >= $this->maxexp) {
            ++$this->level;
            $exp_remaining = $this->exp - $this->maxexp;
            $this->db->query('UPDATE users SET level = ?, experience = ? WHERE id = ?', [$this->level, $exp_remaining, $this->id]);
        }
    }

    /**
     * @param array $row
     * @return void
     */
    private function populateEquipment(array $row): void
    {
        $equipment   = [];
        $equip_array = [$row['eqweapon'], $row['eqarmor']];
        $equip_ids   = array_filter($equip_array, fn($key): bool => $key !== 0);
        if (count($equip_ids) > 0) {
            $this->db->query('SELECT id, offense, defense, name, image FROM items WHERE id IN (' . implode(', ', $equip_ids) . ')');
            $this->db->execute();
            $equip_rows = $this->db->fetch();
            if ($equip_rows !== null) {
                foreach ($equip_rows as $equip_row) {
                    $equipment[$equip_row['id']] = $equip_row;
                }
            }
        }
        if (isset($equipment[$row['eqweapon']])) {
            $wep                 = $equipment[$row['eqweapon']];
            $this->eqweapon      = (int)$wep['id'];
            $this->weaponoffense = (int)$wep['offense'];
            $this->weaponname    = $wep['name'];
            $this->weaponimg     = $wep['image'];
        }
        if (isset($equipment[$row['eqarmor']])) {
            $arm                = $equipment[$row['eqarmor']];
            $this->eqarmor      = (int)$arm['id'];
            $this->armordefense = (int)$arm['defense'];
            $this->armorname    = $arm['name'];
            $this->armorimg     = $arm['image'];
        }
    }

    /**
     * @param array $row
     * @return void
     */
    private function populateCity(array $row): void
    {
        $this->city = (int)$row['city'];
        $this->db->query('SELECT id, name, description FROM cities WHERE id = ?', [$row['city']]);
        $city = $this->db->fetch(true);
        if (!empty($city)) {
            $this->cityname = $city['name'];
            $this->citydesc = $city['description'];
        }
    }

    /**
     * @param array $row
     * @return void
     */
    private function populateStats(array $row): void
    {
        $this->cocaine = (int)$row['cocaine'];
        $this->db->query('SELECT COUNT(id) FROM effects WHERE userid = ? AND LOWER(effect) = \'cocaine\'', [$row['id']]);
        $this->cocaine += $this->db->result();
        if ($this->cocaine > 0) {
            $this->speedbonus = floor($row['speed'] * .3);
        }
        $this->hp              = (float)$row['hp'];
        $this->maxhp           = $this->level * 50;
        $this->energy          = (float)$row['energy'];
        $this->maxenergy       = $this->level + 9;
        $this->nerve           = (float)$row['nerve'];
        $this->maxnerve        = $this->level + 4;
        $this->awake           = (float)$row['awake'];
        $this->maxawake        = (float)$this->houseawake;
        $this->hppercent       = $this->hp > 0 ? floor(($this->hp / $this->maxhp) * 100) : 0;
        $this->energypercent   = $this->energy > 0 ? floor(($this->energy / $this->maxenergy) * 100) : 0;
        $this->nervepercent    = $this->nerve > 0 ? floor(($this->nerve / $this->maxnerve) * 100) : 0;
        $this->awakepercent    = $this->awake > 0 ? floor(($this->awake / $this->maxawake) * 100) : 0;
        $this->formattedexp    = $this->exp . ' / ' . $this->maxexp . ' [' . $this->exppercent . '%]';
        $this->formattedhp     = $this->hp . ' / ' . $this->maxhp . ' [' . $this->hppercent . '%]';
        $this->formattedenergy = $this->energy . ' / ' . $this->maxenergy . ' [' . $this->energypercent . '%]';
        $this->formattednerve  = $this->nerve . ' / ' . $this->maxnerve . ' [' . $this->nervepercent . '%]';
        $this->formattedawake  = $this->awake . ' / ' . $this->maxawake . ' [' . $this->awakepercent . '%]';
        $this->strength        = (float)$row['strength'];
        $this->defense         = (float)$row['defense'];
        $this->speed           = (float)$row['speed'];
        $this->totalattrib     = $this->speed + $this->strength + $this->defense;
        $this->battlewon       = (float)$row['battlewon'];
        $this->battlelost      = (float)$row['battlelost'];
        $this->battletotal     = $this->battlewon + $this->battlelost;
        $this->battlemoney     = (float)$row['battlemoney'];
        $this->crimesucceeded  = (float)$row['crimesucceeded'];
        $this->crimefailed     = (float)$row['crimefailed'];
        $this->crimetotal      = $this->crimesucceeded + $this->crimefailed;
        $this->crimemoney      = (float)$row['crimemoney'];
        $this->moddedstrength  = $this->strength * ($this->weaponoffense * .01 + 1);
        $this->moddedspeed     = $this->speed + $this->speedbonus;
        $this->moddeddefense   = $this->defense * ($this->armordefense * .01 + 1);
    }

    /**
     * @return void
     */
    private function populateGang(): void
    {
        if ($this->gang) {
            $this->db->query('SELECT id, name, leader, tag, description FROM gangs WHERE id = ?', [$this->gang]);
            $gang = $this->db->fetch(true);
            if ($gang !== null) {
                $this->gangname        = $gang['name'];
                $this->gangleader      = (int)$gang['leader'];
                $this->gangtag         = $gang['tag'];
                $this->gangdescription = $gang['description'];
                $this->formattedgang   = '<a href="viewgang.php?id=' . $this->gang . '">' . $this->gangname . '</a>';
                $this->formattedname   = '<a href="viewgang.php?id=' . $this->gang . '" ' . ($this->gangleader === $this->id ? 'title="Gang Leader">[<strong>' . $this->gangtag . '</strong>]' : '>[' . $this->gangtag . ']') . '</a> ';
            } else {
                generate_ticket('Non-existent gang', 'ID: ' . $this->gang);
            }
        }
    }

    /**
     * @return void
     */
    private function setFormattedName(): void
    {
        $color = $this->getTypeColor();
        if ($this->rmdays > 0) {
            $this->formattedname .= '<a href="profiles.php?id=' . $this->id . '" style="font-weight:700;' . ($color !== '' ? 'color:' . $color . ';' : '') . '" title="Respected Mobster [' . $this->rmdays . ' RM Day' . s($this->rmdays) . ' Left]">' . $this->username . '</a>';
        } elseif ($this->admin > 0) {
            $this->formattedname .= '<a href="profiles.php?id=' . $this->id . '" style="font-weight:700;' . ($color !== '' ? 'color:' . $color . ';' : '') . '">' . $this->username . '</a>';
        } else {
            $this->formattedname .= '<a href="profiles.php?id=' . $this->id . '" ' . ($color !== '' ? 'style="color:' . $color . ';"' : '') . '>' . $this->username . '</a>';
        }
    }

    /**
     * @return string
     */
    private function getTypeColor(): string
    {
        $color = '';
        if ($this->rmdays !== 0) {
            $this->type = 'Respected Mobster';
            $color      = 'green';
        } else {
            $this->type = 'Regular Mobster';
        }
        if ($this->admin === 1) {
            $this->type = 'Admin';
            $color      = 'blue';
        }
        if ($this->admin === 2) {
            $this->type = 'Staff';
        }
        if ($this->admin === 3) {
            $this->type = 'To be filled';
            $color      = 'red';
        }
        if ($this->admin === 4) {
            $this->type = 'Congress';
            $color      = 'red';
        }
        return $color;
    }

    /**
     * @return void
     */
    private function setFormattedOnline(): void
    {
        $conf                  = match ((time() - strtotime($this->lastactive ?? '0')) <= 300) {
            true => [
                'color' => 'green',
                'text' => '[online]',
            ],
            false => [
                'color' => 'red',
                'text' => 'offline',
            ],
        };
        $this->formattedonline = '<span style="color:' . $conf['color'] . ';padding:2px;font-weight:bold;">' . $conf['text'] . '</span>';
    }
}
