<?php

class User
{
    public $id = 0;
    public $login = '<em>Некто</em>';
    public $pass;
    public $email = '<em>неизвестно</em>';
    public $realname;
    public $borndate;
    public $info;
    public $level = 0;
    public $align = 0;
    public $clan = 0;
    public $money = 0;
    public $strength = 0;
    public $dexterity = 0;
    public $intuition = 0;
    public $endurance = 0;
    public $intelligence = 0;
    public $wisdom = 0;
    public $health;
    public $mana;
    public $ip;
    public $session_id;
    public $admin = 0;
    public $enter_game;
    public $room;
    public $block;
    public $shadow;
    // Удар кулаком всегда 1-2.
    public $minDamage = 1;
    public $maxDamage = 2;
    //Броня без предметов не существует.
    public $headArmor = 0;
    public $chestArmor = 0;
    public $legArmor = 0;
    public $free_stat_points = 0;
    public const STAT_MAXIMUM_AMOUNT = 40;
    private const ERROR_STAT_IS_MAXIMUM = 'Ошибка: Параметр достиг своего лимита!';
    private const ERROR_STAT_UNKNOWN = 'Ошибка: Неизвестный параметр!';
    // Пока несуществующие, для совместимости.
    public $married = 'Someone или нет.';
    public $experience = 200;
    public $battle = 0;
    public $in_tower = 0; // Скорее башню похороним чем запустим...
    public $zayavka = 0;
    // Динамически рассчитываемые
    public $maxHealth = 5;
    public $maxMana = 5;
    //Статусы того, кто смотрит на информацию.
    public $watcher_id;
    protected $watcherIsAdmin;
    protected $watcherIsModerator;

    use Rooms;

    public function __construct($user)
    {
        $user_query = db::c()->query('SELECT * FROM users WHERE id = "?s" OR login = "?s"', $user, $user)->fetch_assoc();
        foreach ($this as $key => $value) {
            if (isset($user_query[$key])) {
                $this->$key = $user_query[$key];
            }
        }
        $this->maxHealth = round(($this->endurance * 3) + ($this->endurance / 2) * ($this->level - 1) + ($this->endurance / 5) * (($this->level - 1) * ($this->level - 2) / 2));
        $this->maxMana = round(($this->wisdom * 3) + ($this->wisdom / 2) * ($this->level - 1) + ($this->wisdom / 5) * (($this->level - 1) * ($this->level - 2) / 2));
    }

    /**
     * Отображает куклу персонажа (образ и слоты).
     *
     * @param int $isBattle - установить 1, если куклу нужно отобразить в поединке (показывает параметры при наведении
     *                      на образ).
     * @param int $isMain   - установить 1, если куклу надо показать на странице игрока (по клику на предмет снимает
     *                      его).
     *
     * @throws \Krugozor\Database\Mysql\Exception
     */
    private function UserInfoDoll($isBattle = 0, $isMain = 0)
    {
        //https://jsfiddle.net/ngx0yvhc
        //TODO переверстать grid, чтобы он касался только куклы.
        $di = new DressedItems($this->id);
        $dressedItems = $di->getItemsInSlots();
        for ($i = 1; $i <= 12; $i++) {
            echo sprintf('<div class="slot-%s">', $i);
            if (!empty($dressedItems[$i])) {
                if (!$isBattle && $isMain) {
                    $itemString = '<a href="?edit=1&drop=%s"><img src="/i/sh/%s" class="item-wrap-normal" alt="%s" title="%s"></a>';
                    echo sprintf($itemString, $i, $dressedItems[$i]['image'], $dressedItems[$i]['name'], $dressedItems[$i]['name']);
                } else {
                    $itemString = '<img src="/i/sh/%s" class="item-wrap-normal tip" alt="%s"><span class="tiptext"><strong>%s</strong></span>';
                    echo sprintf($itemString, $dressedItems[$i]['image'], $dressedItems[$i]['name'], $dressedItems[$i]['name']);
                }
            } else {
                echo sprintf('<img src="/i/sh/noitem.png" class="item-wrap-normal" title="Пустой слот [%s]" alt="Пустой слот [%s]">', $i, $i);
            }
            echo sprintf('</div><!-- slot-%s -->', $i);
        }
        echo '<div class="slot-image">';
        if ($isBattle) {
            $sh = '<img src="/i/shadow/%s" alt="%s" class="tip"><span class="tiptext"><b>%s</b>Уровень: %s<br>Сила: %s<br>Ловкость: %s<br>Интуиция: %s<br>Выносливость: %s<br>Интеллект: %s<br>Мудрость: %s</span>';
            echo sprintf($sh, $this->shadow, $this->login, $this->login, $this->level, $this->strength, $this->dexterity, $this->intuition, $this->endurance, $this->intelligence, $this->wisdom);
            unset($sh);
        } else {
            echo '<img src="/i/shadow/' . $this->shadow . '" alt="' . $this->login . '">';
        }
        echo '</div><!-- slot-image -->';
    }

    private function UserInfoStats($isMainWindow = 0)
    {
        $captions = 'Уровень:<br>Сила:<br>Ловкость:<br>Интуиция:<br>Выносливость:<br>Интеллект:<br>Мудрость:<br>Местонахождение:';
        $variables = $this->level . '<br>' . $this->getStrength() . '<br>' . $this->getDexterity() . '<br>' . $this->getIntuition() . '<br>' . $this->getEndurance() . '<br>' . $this->getIntelligence() . '<br>' . $this->getWisdom() . '<br>' . $this->getRoomName($this->room);
        if ($isMainWindow) {
            $this->Bank = new Bank($this->id);
            $captions = 'Уровень:<br>Здоровье:<br>Сила:<br>Ловкость:<br>Интуиция:<br>Выносливость:<br>Интеллект:<br>Мудрость:<br>Опыт:<br>Очки характеристик:<br>Деньги:<br>Деньги в банке:';
            $variables = $this->level . '<br>' . $this->health . '<br>' . $this->getStrength(1) . '<br>' . $this->getDexterity(1) . '<br>' . $this->getIntuition(1) . '<br>' . $this->getEndurance(1) . '<br>' . $this->getIntelligence(1) . '<br>' . $this->getWisdom(1) . '<br>' . $this->experience . '<br>' . $this->free_stat_points . '<br>' . $this->money . '<br>' . $this->Bank->money;
        }

        if ($this->align) {
            $nameString = sprintf('<img src="/i/align_%s.png" >', $this->align);
        }
        if ($this->block) {
            $nameString .= '<span class="private"><s>' . $this->login . '</s></span>';
        } else {
            $nameString .= ' <b>' . $this->login . '</b> ';
        }
        if ($this->clan) {
            $nameString .= sprintf('<img src="/i/clan/%s.png" >', $this->clan);
        }
        echo '<div class="user-info">';
        echo '<div class="info">';
        echo '<b>' . $nameString . '</b>';
        echo '</div><!-- info -->';
        echo '<div class="stats-container">';
        echo '<div class="column">';
        echo $captions;
        echo '</div><!-- column -->';
        echo '<div class="column">';
        echo $variables;
        echo '</div><!-- column -->';
        echo '</div><!-- stats-container -->';
        echo '<div class="debug">TODO: Сделать рассчёт модификаторов. Вывести полоску здоровья когда будет от чего отталкиваться.</div>';
        echo '</div><!-- user-info -->';
    }

    public function getStrength($isMainWindow = 0)
    {
        if ($this->free_stat_points && $isMainWindow && $this->strength < self::STAT_MAXIMUM_AMOUNT) {
            //main.php?edit=1&ups=sila
            return sprintf('%s <a href="#">[+]</a>', $this->strength);
        }
        return $this->strength;
    }

    public function getDexterity($isMainWindow = 0)
    {
        if ($this->free_stat_points && $isMainWindow && $this->dexterity < self::STAT_MAXIMUM_AMOUNT) {
            //main.php?edit=1&ups=lovk
            return sprintf('%s <a href="#">[+]</a>', $this->dexterity);
        }
        return $this->dexterity;
    }

    public function getIntuition($isMainWindow = 0)
    {
        if ($this->free_stat_points && $isMainWindow && $this->intuition < self::STAT_MAXIMUM_AMOUNT) {
            //main.php?edit=1&ups=inta...
            return sprintf('%s <a href="#">[+]</a>', $this->intuition);
        }
        return $this->intuition;
    }

    public function getEndurance($isMainWindow = 0)
    {
        if ($this->free_stat_points && $isMainWindow && $this->endurance < self::STAT_MAXIMUM_AMOUNT) {
            return sprintf('%s <a href="#">[+]</a>', $this->endurance);
        }
        return $this->endurance;
    }

    public function getIntelligence($isMainWindow = 0)
    {
        if ($this->free_stat_points && $isMainWindow && $this->intelligence < self::STAT_MAXIMUM_AMOUNT) {
            return sprintf('%s <a href="#">[+]</a>', $this->intelligence);
        }
        return $this->intelligence;
    }

    public function getWisdom($isMainWindow = 0)
    {
        if ($this->free_stat_points && $isMainWindow && $this->wisdom < self::STAT_MAXIMUM_AMOUNT) {
            return sprintf('%s <a href="#">[+]</a>', $this->wisdom);
        }
        return $this->wisdom;
    }

    public function setStrength()
    {
        if ($this->strength <= self::STAT_MAXIMUM_AMOUNT && $this->free_stat_points > 0) {
            db::c()->query('UPDATE users SET strength = strength + 1, free_stat_points = free_stat_points - 1 WHERE id = ?i', $this->id);
        } else {
            throw new Exception(self::ERROR_STAT_IS_MAXIMUM);
        }
    }

    public function setDexterity()
    {
        if ($this->dexterity <= self::STAT_MAXIMUM_AMOUNT && $this->free_stat_points > 0) {
            db::c()->query('UPDATE users SET dexterity = dexterity + 1, free_stat_points = free_stat_points - 1 WHERE id = ?i', $this->id);
        } else {
            throw new Exception(self::ERROR_STAT_IS_MAXIMUM);
        }
    }

    public function setIntuition()
    {
        if ($this->intuition <= self::STAT_MAXIMUM_AMOUNT && $this->free_stat_points > 0) {
            db::c()->query('UPDATE users SET intuition = intuition + 1, free_stat_points = free_stat_points - 1 WHERE id = ?i', $this->id);
        } else {
            throw new Exception(self::ERROR_STAT_IS_MAXIMUM);
        }
    }

    public function setEndurance()
    {
        if ($this->endurance <= self::STAT_MAXIMUM_AMOUNT && $this->free_stat_points > 0) {
            db::c()->query('UPDATE users SET endurance = endurance + 1, free_stat_points = free_stat_points - 1 WHERE id = ?i', $this->id);
        } else {
            throw new Exception(self::ERROR_STAT_IS_MAXIMUM);
        }
    }

    public function setIntelligence()
    {
        if ($this->intelligence <= self::STAT_MAXIMUM_AMOUNT && $this->free_stat_points > 0) {
            db::c()->query('UPDATE users SET intelligence = intelligence + 1, free_stat_points = free_stat_points - 1 WHERE id = ?i', $this->id);
        } else {
            throw new Exception(self::ERROR_STAT_IS_MAXIMUM);
        }
    }

    public function setWisdom()
    {
        if ($this->wisdom <= self::STAT_MAXIMUM_AMOUNT && $this->free_stat_points > 0) {
            db::c()->query('UPDATE users SET wisdom = wisdom + 1, free_stat_points = free_stat_points - 1 WHERE id = ?i', $this->id);
        } else {
            throw new Exception(self::ERROR_STAT_IS_MAXIMUM);
        }
    }

    public function addOnePointToStat($stat_name)
    {
        $allowed = ['strength', 'dexterity', 'intuition', 'endurance', 'intelligence', 'wisdom'];
        if (in_array($stat_name, $allowed)) {
            if ($this->free_stat_points > 0 && $this->$stat_name <= self::STAT_MAXIMUM_AMOUNT) {
                $query = 'UPDATE users SET ?f = ?f + 1, free_stat_points = free_stat_points - 1 WHERE id = ?i';
                db::c()->query($query, $stat_name, $stat_name, $this->id);
            } else {
                throw new Exception(self::ERROR_STAT_IS_MAXIMUM);
            }
        } else {
            throw new Exception(self::ERROR_STAT_UNKNOWN);
        }

    }

    private function UserInfo()
    {
        echo '<div class="user-info-container">';
        $this->UserInfoDoll();
        $this->UserInfoStats();
        echo '<div class="slot-lower">';
        if ($this->married) {
            echo sprintf('<a href = "inf.php?%s" target = _blank ><img alt = "В браке с %s" src = "i/married.gif" title = "В браке с %s"></a >', $this->married, $this->married, $this->married);
        }
        echo '</div><!-- slot-lower -->';
        echo '<div class="user-signs">';
        echo sprintf('<img src="i/zodiac/%s.png" alt="Родовой знак">', $this->showStarSign());
        echo '</div><!-- user-signs -->';
        echo '</div><!-- user-info-container -->';
        echo '<hr><!-- Нижняя часть -->';
        echo '<div class="user-info-container-lower">';
        echo '<h2>Об игроке</h2>';
        if ($this->realname) {
            echo sprintf('Имя: %s<br>', $this->realname);
        }
        if ($this->info) {
            echo nl2br($this->info);
        }
        echo '</div><!-- user-info-container-lower -->';

        if ($this->watcherIsAdmin || $this->watcherIsModerator) {
            echo '<div class="secret-info">';
            $infoString = 'E-Mail: %s<br>  ДР Игрока: %s<br> IP Регистрации: %s';
            echo sprintf($infoString, $this->email, date('d.m.Y', strtotime($this->borndate)), $this->ip);
            if ($this->watcherIsAdmin) {
                $this->Bank = new Bank($this->id);
                $infoString = '<br><span>ИД Игрока: %s<br> ИД Комнаты: %s<br> Деньги: %s<br> Деньги в банке: %s<br> Опыт: %s<br> Нераспределённые очки: %s<br> Текущая сессия: %s</span>';
                echo sprintf($infoString, $this->id, $this->room, $this->money, $this->Bank->money, $this->experience, $this->free_stat_points, $this->session_id);
            }
            $this->UserLogs = new UserLogModel($this->id);
            echo '<div class="secret-info-user-log"><b>Личное дело</b><br>';
            while ($userLogRow = $this->UserLogs->getUserLog()->fetch_object()) {
                echo sprintf('<code>%s</code><br>', date("d.m.Y H:i ", strtotime($userLogRow->date)) . $userLogRow->text);
            }
            echo '</div><!-- secret-info-user-log -->';
            echo '</div><!-- secret-info -->';
        }
    }

    private function WatcherStatus()
    {
        $query = db::c()->query('SELECT `align`,`admin` FROM `users` WHERE `id` = ?i', $this->watcher_id)->fetch_assoc();
        if ($query['admin']) {
            $this->watcherIsAdmin = 1;
        }
        if ($query['align'] == 1) {
            $this->watcherIsModerator = 1;
        }
    }

    public function showUserInfo()
    {
        $this->effects = new EffectsModel($this->id);
        $this->WatcherStatus();

        if ($this->block && (!$this->watcherIsAdmin || !$this->watcherIsModerator)) {
            throw new Exception('<span class="error">Персонаж ' . $this->login . ' заблокирован!</span>');
        } elseif ($this->effects->getHideUserInfoStatus() && (!$this->watcherIsAdmin || !$this->watcherIsModerator)) {
            if ($this->effects->getHideUserInfoStatus() == -1) {
                $date = 'навсегда';
            } else {
                $date = 'до' . date('d.m.Y', strtotime($this->effects->getHideUserInfoStatus()));
            }
            throw new Exception('<span class="error">Персонаж ' . $this->login . ' обезличен ' . $date . '.</span>');
        } else {
            $this->UserInfo();
        }
    }

    public function showUserDoll($isBattle = 0, $isMain = 0)
    {
        echo '<div class="user-info-container">';
        $this->UserInfoDoll($isBattle, $isMain);
        echo '</div><!-- user-info-container -->';
    }

    public function showUserInfoMain()
    {
        echo '<div class="user-info-container">';
        $this->UserInfoDoll();
        $this->userInfoStats(1);
        echo '</div><!-- user-info-container -->';
    }

    public function showStarSign()
    {
        /*
         * 1 aries
         * 2 taurus
         * 3 gemini
         * 4 cancer
         * 5 leo
         * 6 virgo
         * 7 libra
         * 8 scorpio
         * 9 sagittarios
         * 10 capricorn
         * 11 aquarius
         * 12 pisches
        */
        $zodiac[356] = "10";
        $zodiac[326] = "09";
        $zodiac[296] = "08";
        $zodiac[266] = "07";
        $zodiac[235] = "06";
        $zodiac[203] = "05";
        $zodiac[172] = "04";
        $zodiac[140] = "03";
        $zodiac[111] = "02";
        $zodiac[78] = "01";
        $zodiac[51] = "12";
        $zodiac[20] = "11";
        $zodiac[0] = "10";
        $dayOfYear = date("z", strtotime($this->borndate));
        $isLeapYear = date("L", strtotime($this->borndate)); //Высокосный?
        if ($isLeapYear && $dayOfYear > 59) {
            --$dayOfYear;
        }
        foreach ($zodiac as $day => $sign) {
            if ($dayOfYear > $day) {
                break;
            }
        }
        return $sign ?? null;
    }

    public function getHealth(): string
    {
        return $this->health.'/'.$this->maxHealth;
    }

    public function getMana(): string
    {
        return $this->mana.'/'.$this->maxMana;
    }

    public function setRoom()
    {
        
    }
}