<?php
class Users{
    public $username;
    public $email;
    public $pass;
    public $gender;
    public $password;
    public $country;
    public $city;
    public $dob;
    public $allowedSettings = array('gender', 'dob', 'sexuality', 'sexualActivity', 'lookingFor', 'country', 'city', 'height', 'weight', 'hair', 'facialHair', 'pubicHair', 'bodyHair', 'hairColor', 'tattoo', 'piercing', 'eyeColor', 'breastSize', 'penisSize', 'abs', 'bottomSizes', 'bodyTypes', 'ethnicities', 'fitnessLevels', 'dietaryPreferences', 'healthHabits', 'exerciseFrequency', 'sleepingHabits', 'foodAllergies', 'alcoholConsumptions', 'smoking', 'jobs', 'netWorth', 'yearlySalary', 'mainLiving', 'financialGoals', 'spendingHabits', 'financialIndependence', 'inDebt', 'hasKids', 'wantKids', 'fetishes', 'personalities', 'hobbiesAndActivities', 'movieGenres', 'bookGenres', 'highestGraduation', 'education', 'travelPreferences', 'religion', 'languages', 'currentSituation', 'pets');
    public $personalSettings = array(
        'gender' => array(
            'function' => 'update_general_preference',
            'name' => 'gender',
        ),
        'dob' => array(
            'function' => 'update_general_preference',
            'name' => 'dob',
        ),
        'sexuality' => array(
            'function' => 'update_general_preference',
            'name' => 'sexuality'
        ),
        'lookingFor' => array(
            'function' => 'update_general_preference',
            'name' => 'lookingFor',
        ),
        'country' => array(
            'function' => 'update_general_preference',
            'name' => 'country',
        ),
        'city' => array(
            'function' => 'update_general_preference',
            'name' => 'city',
        ),
    );
    // public function __construct(){
    // }

    public function email_exists(){
        global $db_con;
        $pre_sql = $db_con->prepare('SELECT u_email FROM users WHERE u_email = :email');
        $pre_sql->bindValue(':email', $this->email);
        $pre_sql->execute();
        $_res = $pre_sql->rowCount();
        if($_res > 0){
            return true;
        }else{
            return false;
        }
    }

    public function username_exists(){
        global $db_con;
        $pre_sql = $db_con->prepare('SELECT uname FROM users WHERE uname = :uname');
        $pre_sql->bindValue(':uname', $this->username);
        $pre_sql->execute();
        $_res = $pre_sql->rowCount();
        if($_res > 0){
            return true;
        }else{
            return false;
        }
    }

    public function setLogin($id){
        global $db_con;
        $hex = bin2hex(random_bytes(36 / 2));
        $sql_con = $db_con->prepare("UPDATE users SET login_session_id = :hex WHERE id = :id");
        $sql_con->bindValue(':hex', $hex);
        $sql_con->bindValue(':id', $id);
        $sql_con->execute();

        return $hex;
    }

    public function logout(){
        global $db_con;
        $sql = $db_con->prepare("UPDATE users SET login_session_id = '' WHERE id = :id");
        $sql->bindValue(':id', $_COOKIE['authId']);
        $sql->execute();
        setcookie('authCookie','', time() - 7200);
        setcookie('authId', '', time() - 7200);
        session_destroy();
    }

    public function isAuth(){
        global $db_con;
        if(isset($_COOKIE['authCookie'])){
            $token = $_COOKIE['authCookie'];
            $uId = $_COOKIE['authId'];
            $sql_con = $db_con->prepare('SELECT * FROM users WHERE login_session_id = :session_key AND id = :id');
            $sql_con->bindValue(':session_key', $token);
            $sql_con->bindValue(':id', $uId);
            $sql_con->execute();
            $rowCount = $sql_con->rowCount();
            if($rowCount !== 0){
                return true;
            }else{
                return false;
            }
        }else{
            return false;
        }
    }

    public function register(){
        global $db_con;
        $sql_con = $db_con->prepare('INSERT INTO users SET uname = :username, u_email = :email,  psw = :psw, dob = :dob');
        $sql_con->bindValue(':username', $this->username);
        $sql_con->bindValue(':email', $this->email);
        $sql_con->bindValue(':psw', $this->password);
        $sql_con->bindValue(':dob', $this->dob);
        $sql_con->execute();

        $sql_con = $db_con->prepare('SELECT id FROM users WHERE u_email = :u_email');
        $sql_con->bindValue(':u_email', $this->email);
        $sql_con->execute();
        $temp_user_data = $sql_con->fetch(PDO::FETCH_ASSOC);

        $user_id = $temp_user_data['id'];

        if(!empty($user_id)){
            $this->update_user_data('gender', $this->gender, $user_id);
            $this->update_user_data('country', $this->country, $user_id);
            $this->update_user_data('dob', '', $user_id);
        }

        $cu_name = md5(time());
        $date = new DateTime();
        $date->modify('+30 days');
        $cu_exp = $date->getTimestamp();
        $sql = $db_con->prepare('INSERT INTO stripe_user_data (cu_name, exp_date) VALUES (:cu_name, :exp)');
        $sql->bindValue(':cu_name', $cu_name);
        $sql->bindValue(':exp', $cu_exp);
        $sql->execute();

        $sql_con = $db_con->prepare('UPDATE users SET stripe_cu = :stripe_cu WHERE id = :user_id');
        $sql_con->bindValue(':stripe_cu', $cu_name);
        $sql_con->bindValue(':user_id', $user_id);
        $sql_con->execute();             
    }

    public function login(){
        global $db_con;

        $sql_con = $db_con->prepare('SELECT * FROM users WHERE uname = :uname');
        $sql_con->bindValue(':uname', $this->username);
        $sql_con->execute();

        $user = $sql_con->fetch(PDO::FETCH_ASSOC);
        return $user;
    }

    public function update_user_data($name, $value, $user){
        global $db_con;
        if(is_array($value)){
            $value = implode(",", $value);
        }
        $sql_con = $db_con->prepare('SELECT * FROM user_data WHERE data_name = :data_name AND user_id = :user_id');
        $sql_con->bindValue(':data_name', $name);
        $sql_con->bindValue(':user_id', $user);
        $sql_con->execute();

        $num_rows = $sql_con->rowCount();
        if($num_rows > 0){
            $sql_con = $db_con->prepare('UPDATE user_data SET data_value = :data_value WHERE user_id = :user_id AND data_name = :data_name');
            $sql_con->bindValue(':data_name', $name);
            $sql_con->bindValue(':data_value', $value);
            $sql_con->bindValue(':user_id', $user);
            $sql_con->execute();
        }else{
            $sql_con = $db_con->prepare('INSERT INTO user_data (data_name, data_value, user_id) VALUES (:data_name, :data_value, :user_id)');
            $sql_con->bindValue(':data_name', $name);
            $sql_con->bindValue(':data_value', $value);
            $sql_con->bindValue(':user_id', $user);
            $sql_con->execute();
        }
        // echo 'Executed ' . $name . ' with value ' . $value . '<br>';
    }

    public function allowedSetting($setting){
        if(in_array($setting, $this->allowedSettings)){
            return true;
        }else{
            return false;
        }
    }

    public function locateAtts($setting){
        if(key_exists($setting, $this->personalSettings)){
            return $this->personalSettings;
        }
    }

    public function initUserSettings(){
        global $db_con;
        if($this->isAuth()){
            $sql_con = $db_con->prepare("SELECT u.uname, u.u_email, ud.data_name, ud.data_value
            FROM users u
            JOIN user_data ud ON u.id = ud.user_id
            WHERE ud.user_id = :user_id");
            $sql_con->bindValue(':user_id', $_COOKIE['authId']);
            $sql_con->execute();
            $sql_rows = $sql_con->fetchaLL(PDO::FETCH_ASSOC);
            $userSettings = new stdClass();
            foreach($sql_rows as $row){
                $userSettings->{$row['data_name']} = $row['data_value'];
            }
            $userSettings = json_encode($userSettings);
            return $userSettings;
        }else{
            return null;
        }
    }

    public function updateAvatar($avatar, $ext){
        global $db_con;
        $uid = $_COOKIE['authId'];
        $allowedPhotos = array('jpg', 'jpeg', 'png', 'gif');
        $name = $this->generateRandomName();
        $name = $name . '.' . $ext;
        $path = $_SERVER['DOCUMENT_ROOT'] . '/uploads/';

        if (in_array($ext, $allowedPhotos)) {
            move_uploaded_file($avatar, $path . $name);
        }

        $stmt = $db_con->prepare('UPDATE users SET avatar = :avatar WHERE id = :id');
        $stmt->bindValue(':avatar', $name);
        $stmt->bindValue(':id', $uid);
        $stmt->execute();
    }

    public function updateBanner($banner, $ext){
        global $db_con;
        $uid = $_COOKIE['authId'];
        $allowedPhotos = array('jpg', 'jpeg', 'png', 'gif');
        $name = $this->generateRandomName();
        $name = $name . '.' . $ext;
        $path = $_SERVER['DOCUMENT_ROOT'] . '/uploads/';

        if (in_array($ext, $allowedPhotos)) {
            move_uploaded_file($banner, $path . $name);
        }

        $stmt = $db_con->prepare('UPDATE users SET banner = :banner WHERE id = :id');
        $stmt->bindValue(':banner', $name);
        $stmt->bindValue(':id', $uid);
        $stmt->execute();
    }

    public function updateBio($bio){
        global $db_con;
        $uid = $_COOKIE['authId'];
        $stmt = $db_con->prepare('UPDATE users SET bio = :bio WHERE id = :id');
        $stmt->bindValue(':bio', $bio);
        $stmt->bindValue(':id', $uid);
        $stmt->execute();
    }

    public function generateRandomName($length = 32) {
        $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
        $randomName = '';
        $maxIndex = strlen($characters) - 1;
        
        for ($i = 0; $i < $length; $i++) {
            $randomName .= $characters[rand(0, $maxIndex)];
        }
        
        return $randomName;
    }

    public function initUser(){
        global $db_con;
        $id = $_COOKIE['authId'];

        $stmt = $db_con->prepare('SELECT * FROM users WHERE id = :id');
        $stmt->bindValue(':id', $id);
        $stmt->execute();
        $defaultUser = $stmt->fetch(PDO::FETCH_ASSOC);

        $user = new stdClass();
        $user->username = $defaultUser['uname'];
        $user->avatar = isset($defaultUser['avatar']) && !empty($defaultUser['avatar']) ? $defaultUser['avatar'] : 'default.png';
        $user->banner = isset($defaultUser['banner']) && !empty($defaultUser['banner']) ? $defaultUser['banner'] : 'defaultBG.png';
        $user->bio = isset($defaultUser['bio']) && !empty($defaultUser['bio']) ? $defaultUser['bio'] : '';
        $user->country = $this->get_data_value('country', $id);
        $user->city = $this->get_data_value('city', $id);
        $user->gender = $this->get_data_value('gender', $id);
        $user->sexuality = $this->get_data_value('sexuality', $id);
        $dob = isset($defaultUser['dob']) && !empty($defaultUser['dob']) ? $defaultUser['dob'] : '';
        if(isset($dob) && !empty($dob)){
            $user->age = $this->calcAge($dob);
        }else{
            $user->age = '';
        }

        if(isset($user->username)){
            $user->status = "Success";
        }

        // Get userData:
        $sql_con = $db_con->prepare("SELECT u.uname, u.u_email, ud.data_name, ud.data_value
        FROM users u
        JOIN user_data ud ON u.id = ud.user_id
        WHERE ud.user_id = :user_id");
        $sql_con->bindValue(':user_id', $_COOKIE['authId']);
        $sql_con->execute();
        $sql_rows = $sql_con->fetchaLL(PDO::FETCH_ASSOC);
        $userData = new stdClass();
        foreach($sql_rows as $row){
            $userData->{$row['data_name']} = $row['data_value'];
        }
        $user->userData = $userData;

        // Get user images:
        $sql_con = $db_con->prepare("SELECT image_name FROM user_gallery WHERE user_id = :user_id");
        $sql_con->bindValue(':user_id', $_COOKIE['authId']);
        $sql_con->execute();
        $sql_rows = $sql_con->fetchaLL(PDO::FETCH_ASSOC);
        $userGallery = array();
        foreach($sql_rows as $row){
            $userGallery[] = $row['image_name'];
        }

        $user->userGallery = $userGallery;
        $user = json_encode($user);


        return $user;
    }

    public function getUser($id){
        global $db_con;

        $stmt = $db_con->prepare('SELECT * FROM users WHERE id = :id');
        $stmt->bindValue(':id', $id);
        $stmt->execute();
        $defaultUser = $stmt->fetch(PDO::FETCH_ASSOC);

        $user = new stdClass();
        $user->id = $defaultUser['id'];
        $user->username = $defaultUser['uname'];
        $user->avatar = isset($defaultUser['avatar']) && !empty($defaultUser['avatar']) ? $defaultUser['avatar'] : 'default.png';
        $user->banner = isset($defaultUser['banner']) && !empty($defaultUser['banner']) ? $defaultUser['banner'] : 'defaultBG.png';
        $user->bio = isset($defaultUser['bio']) && !empty($defaultUser['bio']) ? $defaultUser['bio'] : '';
        $user->country = $this->get_data_value('country', $id);
        $user->city = $this->get_data_value('city', $id);
        $user->gender = $this->get_data_value('gender', $id);
        $user->sexuality = $this->get_data_value('sexuality', $id);
        $dob = isset($defaultUser['dob']) && !empty($defaultUser['dob']) ? $defaultUser['dob'] : '0';
        if(isset($dob) && !empty($dob)){
            $user->age = $this->calcAge($dob);
        }else{
            $user->age = '';
        }

        if(isset($user->username)){
            $user->status = "Success";
        }

        // Get userData:
        $sql_con = $db_con->prepare("SELECT u.uname, u.u_email, ud.data_name, ud.data_value
        FROM users u
        JOIN user_data ud ON u.id = ud.user_id
        WHERE ud.user_id = :user_id");
        $sql_con->bindValue(':user_id', $id);
        $sql_con->execute();
        $sql_rows = $sql_con->fetchaLL(PDO::FETCH_ASSOC);
        $userData = new stdClass();
        foreach($sql_rows as $row){
            $userData->{$row['data_name']} = $row['data_value'];
        }
        $user->userData = $userData;

        // Get user images:
        $sql_con = $db_con->prepare("SELECT image_name FROM user_gallery WHERE user_id = :user_id");
        $sql_con->bindValue(':user_id', $id);
        $sql_con->execute();
        $sql_rows = $sql_con->fetchaLL(PDO::FETCH_ASSOC);
        $userGallery = array();
        foreach($sql_rows as $row){
            $userGallery[] = $row['image_name'];
        }

        $user->userGallery = $userGallery;
        $user = json_encode($user);


        return $user;
    }

    private function get_data_value($name, $id){
        global $db_con;

        $stmt = $db_con->prepare("SELECT data_value FROM user_data WHERE data_name = :data_name AND user_id = :user_id");
        $stmt->bindValue(':data_name', $name);
        $stmt->bindValue(':user_id', $id);
        $stmt->execute();

        $holder = $stmt->fetch(PDO::FETCH_ASSOC);
        if(isset($holder['data_value']) && !empty($holder['data_value'])){
            $value = $holder['data_value'];
        }else{
            $value = '';
        }

        return $value;
    }

    private function calcAge($dob) {
        $dobDate = new DateTime($dob);
        $currentDate = new DateTime();
        $age = $currentDate->diff($dobDate);
        return $age->y;
    }

    public function uploadGalleryImage($image, $ext){
        global $db_con;
        $uid = $_COOKIE['authId'];
        $allowedPhotos = array('jpg', 'jpeg', 'png', 'gif');
        $name = $this->generateRandomName();
        $name = $name . '.' . $ext;
        $path = $_SERVER['DOCUMENT_ROOT'] . '/uploads/';

        if (in_array($ext, $allowedPhotos)) {
            move_uploaded_file($image, $path . $name);
        }

        $stmt = $db_con->prepare('INSERT INTO user_gallery (user_id, image_name) VALUES (:id, :image_name)');
        $stmt->bindValue(':image_name', $name);
        $stmt->bindValue(':id', $uid);
        $stmt->execute();
    }

    public function deleteImage($image){
        global $db_con;
        $path = $_SERVER['DOCUMENT_ROOT'] . '/uploads/';

        $sql = $db_con->prepare("SELECT * FROM user_gallery WHERE user_id = :user_id AND image_name = :image_name");
        $sql->bindValue(':image_name', $image);
        $sql->bindValue(':user_id', $_COOKIE['authId']);
        $sql->execute();

        $nums = $sql->rowCount();
        if($nums > 0){
            if(file_exists($path . $image)){
                unlink($path . $image);
                $sql = $db_con->prepare('DELETE FROM user_gallery WHERE user_id = :user_id AND image_name = :image_name');
                $sql->bindValue(':image_name', $image);
                $sql->bindValue(':user_id', $_COOKIE['authId']);
                $sql->execute();
            }
        }
    }


    public function receive_messages($user_id){
        global $db_con;
        $current_user = intval($_COOKIE['authId']);
        $message_user = intval($user_id);

        // Receive user data
        $sql = $db_con->prepare("SELECT uname, avatar FROM users WHERE id = :id");
        $sql->bindValue(':id', $current_user);
        $sql->execute();
        $current_user_data = $sql->fetch(PDO::FETCH_ASSOC);

        // Receive messager data
        $sql = $db_con->prepare("SELECT uname, avatar FROM users WHERE id = :id");
        $sql->bindValue(':id', $message_user);
        $sql->execute();
        $message_user_data = $sql->fetch(PDO::FETCH_ASSOC);

        // Set username and avatar
        $cua = $current_user_data['avatar'];
        $cuu = $current_user_data['uname'];
        $mua = $message_user_data['avatar'];
        $muu = $message_user_data['uname'];


        // Receive messages
        $sql = $db_con->prepare('SELECT * 
        FROM user_chats 
        WHERE (sender_id = :current_user AND receiver_id = :message_user) 
           OR (sender_id = :message_user AND receiver_id = :current_user) 
        ORDER BY id ASC');
        $sql->bindValue(':message_user', $message_user);
        $sql->bindValue(':current_user', $current_user);
        $sql->execute();
        $sql_messages = $sql->fetchAll(PDO::FETCH_ASSOC);
        $messages = array();

        foreach($sql_messages as $message){
            $msg = new stdClass();
            if($message['sender_id'] == $current_user){
                $msg->uid = $current_user;
                $msg->sender = 'me';
                $msg->avatar = $cua;
                $msg->username = $cuu;
            }else{
                $msg->uid = $message_user;
                $msg->sender = 'other';
                $msg->avatar = $mua;
                $msg->username = $muu;
            }
            $msg->content = $message['user_message'];
            $messages[] = $msg;
        }

        $stm = $db_con->prepare("UPDATE user_chats SET readStatus = 0 WHERE receiver_id = :user_id AND sender_id = :sender_id");
        $stm->bindValue(':user_id', $current_user);
        $stm->bindValue(':sender_id', $message_user);
        $stm->execute();

        $messages = json_encode($messages);
        return $messages;
    }

    public function sendMessage($user_id, $message){
        global $db_con;
        $user_id = intval($user_id);
        $current_user = $_COOKIE['authId'];
        $message = htmlspecialchars($message);


        $sql = $db_con->prepare('INSERT INTO user_chats (sender_id, receiver_id, user_message, message_type) VALUES (:sender_id, :receiver_id, :user_message, :message_type)');
        $sql->bindValue(':sender_id', $current_user);
        $sql->bindValue(':receiver_id', $user_id);
        $sql->bindValue(':user_message', $message);
        $sql->bindValue(':message_type', 'text');
        $sql->execute();
    }

    public function get_conversations(){
        global $db_con;
        $user_id = $_COOKIE['authId'];

        $sql = $db_con->prepare("SELECT DISTINCT IF(sender_id = :user_id, receiver_id, sender_id) AS chat_partner_id
        FROM user_chats
        WHERE sender_id = :user_id OR receiver_id = :user_id");

        $sql->bindParam(':user_id', $user_id);
        $sql->execute();
        $chat_partners = $sql->fetchAll(PDO::FETCH_COLUMN);
        // $chat_partners = array_diff($chat_partners, [$user_id]);

        $conversations = array();
        foreach($chat_partners as $chat){
            $conversation = new stdClass();
            $msg_id = intval($chat);

            // Get last message
            $sql = $db_con->prepare("SELECT user_message, time_received 
            FROM user_chats 
            WHERE (sender_id = :user_id AND receiver_id = :msg_id) 
                OR (sender_id = :msg_id AND receiver_id = :user_id) 
            ORDER BY id DESC 
            LIMIT 1");
            $sql->bindValue(':msg_id', $msg_id);
            $sql->bindValue(':user_id', $user_id);
            $sql->execute();
            $_msg = $sql->fetch(PDO::FETCH_ASSOC);
            $msg = $_msg['user_message'];
            $time_rec = $_msg['time_received']; 

            $stmt = $db_con->prepare('SELECT uname, avatar FROM users WHERE id = :id');
            $stmt->bindValue(':id', $msg_id);
            $stmt->execute();
            $msg_info =  $stmt->fetch(PDO::FETCH_ASSOC);

            $conversation->avatar = $msg_info['avatar'];
            $conversation->username = $msg_info['uname'];
            $conversation->message = $msg;
            $conversation->time = $time_rec;
            $conversation->user_id = $msg_id;
            $conversations[] = $conversation;
        }
        usort($conversations, function($a, $b) {
            return strtotime($b->time) - strtotime($a->time);
        });
        return json_encode($conversations);
    }

    public function checkUnread(){
        global $db_con;
        $id = $_COOKIE['authId'];

        $sql = $db_con->prepare('SELECT * FROM user_chats WHERE receiver_id = :user_id AND readStatus = 1');
        $sql->bindValue(':user_id', $id);
        $sql->execute();
        $numRows = $sql->rowCount();
        if($numRows > 0){
            $status = true;
        }else{
            $status = false;
        }
        $response = new stdClass();
        $response->status = $status;
        $response = json_encode($response);
        return $response;
    }

    public function updatePassword($current_password, $new_password, $confirm_password){
        global $db_con;
        $id = $_COOKIE['authId'];

        $sql = $db_con->prepare("SELECT psw FROM users WHERE id = :id");
        $sql->bindValue(':id', $id);
        $sql->execute();
        $_psw = $sql->fetch(PDO::FETCH_ASSOC);
        $psw = $_psw['psw'];
        $response = new stdClass();
        
        if(password_verify($current_password, $psw)){
            if($new_password == $confirm_password){
                $new_psw = password_hash($new_password, PASSWORD_BCRYPT, ["cost" => 12]);
                $stmt = $db_con->prepare("UPDATE users SET psw = :psw WHERE id = :id");
                $stmt->bindValue(':psw', $new_psw);
                $stmt->bindValue(':id', $id);
                $stmt->execute();
                $response->status = 'success';
            }else{
                $response->status = 'error';
                $response->message = 'Passwords does not match';
            }
        }else{
            $response->status = 'error';
            $response->message = 'Incorrect password';
        }

        $response = json_encode($response);
        return $response;
    }

    public function isPaid(){
        global $db_con;
        $id = intval($_COOKIE['authId']);
        $sql = $db_con->prepare('SELECT u.stripe_cu, st.exp_date FROM users u LEFT JOIN stripe_user_data st ON st.cu_name = u.stripe_cu WHERE u.id = :id');
        $sql->bindValue(':id', $id);
        $sql->execute();
        if($sql->rowCount() > 0){
            $date_query = $sql->fetch(PDO::FETCH_ASSOC);
            $sub_date = intval($date_query['exp_date']);
            $current_date = intval(time());
            if($current_date > $sub_date){
                return false;
            }else{
                return true;
            }

        }else{
            return false;
        }
    }

    public function hasPaid(){
        global $db_con;
        $id = intval($_COOKIE['authId']);
        $sql = $db_con->prepare('SELECT u.stripe_cu, st.exp_date FROM users u LEFT JOIN stripe_user_data st ON st.cu_name = u.stripe_cu WHERE u.id = :id');
        $sql->bindValue(':id', $id);
        $sql->execute();
        if($sql->rowCount() > 0){
            $date_query = $sql->fetch(PDO::FETCH_ASSOC);
            $sub_date = intval($date_query['exp_date']);
            $current_date = intval(time());
            if($current_date > $sub_date){
                return false;
            }else{
                return true;
            }

        }else{
            return false;
        }
    }
}
?>
