<?php

/*
ET-Chat Copyright by SEDesign | ET-Chat v3.x.x Lizenz: CCPL | Autor: Evgeni Tcherkasski (info@s-e-d.de)
ET-Chat_T-FISH-MOD Weiterentwicklungen, Optimierungen und Ergänzungen am Code sind das geistige Eigentum von Tommy (Thomas Kuhn) und Harlekin (Bernd Witte).

Die darauf folgende Optimierungen und Ergänzungen am Code sind das Geistige Eigentum von Powermen (Christian K.) 
PHP 8/9 Ready, XML Parser, PDO Prepared Statements Get Set sicherheit usw.
*/

class UserCheckerAndInserter extends EtChatConfig
{
    private ConnectDB $dbObj;

    protected $_user_exists;
    protected string $_user;
    protected string $_pw;
    protected $_gender;
    protected $_lang;

    public $status;

    private int $guestAccessAllowed;
    private int $adminAccessAllowed;

    private string $sessionPrefix;

    public function __construct($dbObj, $user_exists, $user, $pw, $gender, $lang)
    {
        parent::__construct();

        if (session_status() === PHP_SESSION_NONE) {
            session_start();
        }

        $this->dbObj        = $dbObj;
        $this->_user_exists = $user_exists;
        $this->_user        = trim((string)$user);
        $this->_pw          = (string)$pw;
        $this->_gender      = $gender;
        $this->_lang        = $lang;

        $this->sessionPrefix = "etchat_" . $this->_prefix;

        $this->guestAccessAllowed = (int)($_SESSION[$this->sessionPrefix . "gast_zugang"] ?? 0);
        $this->adminAccessAllowed = (int)($_SESSION[$this->sessionPrefix . "wartung"] ?? 1);

        if ($this->_user === '' || mb_strlen($this->_user) > 30) {
            $this->status = "invalid_username";
            return;
        }

        if (!is_array($this->_user_exists)) {

            if ($this->adminAccessAllowed === 1) {
                $this->status = "maintenance_denied";
                return;
            }

            if ($this->guestAccessAllowed === 0) {
                $this->status = "guest_denied";
                return;
            }

            $this->createNewUser();
            return;
        }

        $userPriv = $this->_user_exists[0][3] ?? '';

        if ($this->adminAccessAllowed === 1 && !in_array($userPriv, ["admin", "co_admin"])) {
            $this->status = "maintenance_denied";
            return;
        }

        $userId = (int)$this->_user_exists[0][0];

        $gender = is_array($this->_gender) ? ($this->_gender[0] ?? '') : $this->_gender;
        $gender = trim((string)$gender);

        $ip = $_SERVER['REMOTE_ADDR'] ?? '';
        if (!filter_var($ip, FILTER_VALIDATE_IP)) {
            $ip = '0.0.0.0';
        }

        $this->dbObj->sqlSet(
            "UPDATE {$this->_prefix}etchat_user
             SET etchat_usersex = :gender,
                 etchat_logintime = :time,
                 etchat_last_ip = :ip
             WHERE etchat_user_id = :id",
            [
                ":gender" => $gender,
                ":time"   => time(),
                ":ip"     => $ip,
                ":id"     => $userId
            ]
        );

        if ($this->_pw === '') {
            $this->userWithoutPw();
        } else {
            $this->userWithPw();
        }
    }

    private function createNewUser()
    {
        $gender = is_array($this->_gender) ? ($this->_gender[0] ?? '') : $this->_gender;

        $ip = $_SERVER['REMOTE_ADDR'] ?? '';
        if (!filter_var($ip, FILTER_VALIDATE_IP)) {
            $ip = '0.0.0.0';
        }

        $this->dbObj->sqlSet(
            "INSERT INTO {$this->_prefix}etchat_user
            (etchat_username, etchat_usersex, etchat_logintime, etchat_last_ip)
            VALUES (:user, :gender, :time, :ip)",
            [
                ":user"   => $this->_user,
                ":gender" => $gender,
                ":time"   => time(),
                ":ip"     => $ip
            ]
        );

        $user = $this->dbObj->sqlGet(
            "SELECT etchat_user_id, etchat_username, etchat_userprivilegien
             FROM {$this->_prefix}etchat_user
             WHERE etchat_username = :user
             LIMIT 1",
            [":user" => $this->_user]
        );

        if (!empty($user[0])) {

            $_SESSION[$this->sessionPrefix . "user_id"]  = $user[0][0];
            $_SESSION[$this->sessionPrefix . "username"] = $user[0][1];
            $_SESSION[$this->sessionPrefix . "user_priv"] = $user[0][2];
        }

        $this->status = 1;
    }

    private function userWithPw()
    {
        $dbHash = (string)($this->_user_exists[0][2] ?? '');
        $userId = (int)$this->_user_exists[0][0];

        $loginOk = false;

        if ($dbHash === '') {
            $this->status = $this->getLangText('pw_falsch');
            return;
        }

        if (password_verify($this->_pw, $dbHash)) {

            $loginOk = true;

            if (password_needs_rehash($dbHash, PASSWORD_DEFAULT)) {

                $newHash = password_hash($this->_pw, PASSWORD_DEFAULT);

                $this->dbObj->sqlSet(
                    "UPDATE {$this->_prefix}etchat_user
                     SET etchat_userpw = :pw
                     WHERE etchat_user_id = :id",
                    [
                        ":pw" => $newHash,
                        ":id" => $userId
                    ]
                );
            }
        }

        elseif (strlen($dbHash) === 32 && md5($this->_pw) === $dbHash) {

            $loginOk = true;

            $newHash = password_hash($this->_pw, PASSWORD_DEFAULT);

            $this->dbObj->sqlSet(
                "UPDATE {$this->_prefix}etchat_user
                 SET etchat_userpw = :pw
                 WHERE etchat_user_id = :id",
                [
                    ":pw" => $newHash,
                    ":id" => $userId
                ]
            );
        }

        if ($loginOk) {

            $_SESSION[$this->sessionPrefix . "user_id"]  = $this->_user_exists[0][0];
            $_SESSION[$this->sessionPrefix . "username"] = $this->_user_exists[0][1];
            $_SESSION[$this->sessionPrefix . "user_priv"] = $this->_user_exists[0][3];

            if (in_array($_SESSION[$this->sessionPrefix . "user_priv"], ["admin", "mod"])) {
                $this->setLoginCookie();
            }

            $this->status = 1;

        } else {

            $this->status = $this->getLangText('pw_falsch');
        }
    }

    private function userWithoutPw()
    {
        $userPriv = $this->_user_exists[0][3] ?? '';

        if (!empty($this->_user_exists[0][2])) {

            $this->status = ($userPriv === "admin") ? "pw+invisible" : "pw";
            return;
        }

        if ($userPriv === "gast" && $this->guestAccessAllowed === 0) {

            $this->status = "guest_denied";
            return;
        }

        $_SESSION[$this->sessionPrefix . "user_id"]  = $this->_user_exists[0][0];
        $_SESSION[$this->sessionPrefix . "username"] = $this->_user_exists[0][1];
        $_SESSION[$this->sessionPrefix . "user_priv"] = $userPriv;

        if (in_array($userPriv, ["admin", "mod"])) {
            $this->setLoginCookie();
        }

        $this->status = 1;
    }

    private function setLoginCookie()
    {
        setcookie(
            "cookie_anzahl_logins_in_XX_sek",
            "1",
            [
                "expires" => time() + 3600,
                "path" => "/",
                "secure" => isset($_SERVER['HTTPS']),
                "httponly" => true,
                "samesite" => "Lax"
            ]
        );
    }

    private function getLangText($key)
    {
        return $this->_lang->{$key}[0]->tagData ?? 'Passwort falsch';
    }
}