<?php
class UtilsModel{
    const ID_TYPE_CUSTOMER = 2;

    public function saveJSError($message, $stack){
        global $database, $errorHandler;

        $message = $database->escapeValue($message);
        $stack = $database->escapeValue($stack);

        $errorHandler->addLog('JavaScript' . PHP_EOL . $message . PHP_EOL . $stack);
    }

    public function checkActivityStatus(){
        global $user;

        $lastActivity = $user->getLastActivity();

        $data['hasSessionExpired'] = (time() - $lastActivity) >= SESSION_LIFE_TIME;

        return $data;
    }

    public function sendTestMail(){
        $response = Mail::sendMail('snr_dash@saguaronet.ro', 'test mail ', 'testTemplate.php', ['variable' => 'This is a dynamic value']);

        if($response){
            return "Mail has been sent!";
        }

        return "Mail send has failed!";
    }

    /**
     * changes the password for the current user
     * @param  String $password if empty, a random pass will be generated
     * @return Array            confirmation message
     */
    public static function changePassword($passwords, $username = '') {
        global $database, $user;
        $passwords = (array) json_decode($passwords);
        if($userInfo = self::getUserData($username)) {
            $userInfo = $userInfo[0];
        } else {
            $data['messages'][] = [
                'code' => 'error',
                'message' => 'WRONG_USERNAME'
            ];

            return $data;
        }
        $isForReset = $username ? true : false;

        if($data = self::validatePassword($userInfo['username'], $passwords, $isForReset)) {
            return $data;
        }

        $password = $passwords['newPassword'];
        $passwordHashed = $user->hashPassword($database->escapeValue($password));

        $sql = "UPDATE
                    ".TABLES['users']." u
                SET
                    u.password='".$passwordHashed."',
                    u.token=null,
                    u.tokenTS=null
                WHERE u.username='".$database->escapeValue($userInfo['username'])."'";

        $result = $database->query($sql);
        if($database->affectedRows() == 1) {
            $data['messages'][] = [
                'code' => 'success',
                'message' => 'PASSWORD_GENERATED'
            ];
        } else {
            $data['messages'][] = [
                'code' => 'error',
                'message' => 'ERROR_PASSWORD_GENERATED'
            ];
        }
        $data['messages'][] = self::sendUserConfirmationMail($userInfo, $userInfo['mail'], 'change');

        return $data;
    }

    public function generateTokenForAllUsersPassword($userInfo){
        global $database;
        $userInfo = json_decode($userInfo);
        $userInfo->mail = $database->escapeValue($userInfo->mail);
        $data = ['messages' => []];

        $sql = "SELECT
                u.id AS idUser,
                u.username
                FROM ".TABLES['users']." u
                WHERE u.mail='".$userInfo->mail."'";
        $query = $database->query($sql);

        while($row = $database->fetchArray($query)){
            $newMessage = $this->generateTokenForUserPassword(json_encode($row));
            if(isset($newMessage['messages'])){
                $data['messages'] = array_merge($data['messages'], $newMessage['messages']);
            }
        }

        return $data;

    }

    /**
     * generates a new random password for the user provided
     * @param  Array $userInfo  contains username and password for the user of the password to change
     * @return Array            confirmation message
     */
    public static function generateTokenForUserPassword($userInfo) {
        global $database, $user;
        $userInfo = (array) json_decode($userInfo);
        if($userInfo = self::getUserData($userInfo['username'])) {
            $userInfo = $userInfo[0];
        } else {
            $data['messages'][] = [
                'code' => 'error',
                'message' => 'WRONG_USERNAME'
            ];

            return $data;
        }

        $token = bin2hex(random_bytes(16));
        $tokenTimestamp = new DateTime();
        $sql = "UPDATE
                    ".TABLES['users']." u
                SET
                    u.token='".$token."',
                    u.tokenTS='".$tokenTimestamp->format('Y-m-d H:i:s')."'
                WHERE u.username='".$database->escapeValue($userInfo['username'])."'";

        $result = $database->query($sql);
        if($database->affectedRows() == 1) {
            $data['messages'][] = [
                'code' => 'success',
                'message' => 'PASSWORD_GENERATED'
            ];
        } else {
            $data['messages'][] = [
                'code' => 'error',
                'message' => 'ERROR_PASSWORD_GENERATED'
            ];
        }

        $data['messages'][] = self::sendUserConfirmationMail($userInfo, $userInfo['mail'], 'generate', $token);

        return $data;
    }

    /**
     * send confirmation mail to user for creation
     * @param  String $userInfo
     * @param  String $password
     * @param  String $mail
     * @return Array confirmation message
     */
    public static function sendUserConfirmationMail($userInfo, $mail, $action, $token = '') {

        switch($action) {
            case 'create':
                $mailTitle = APPLICATION_NAME.' user created';
                $templateUrl = 'createUserTemplate.php';
                break;
            case 'generate':
                $mailTitle = APPLICATION_NAME.' password generated';
                $templateUrl = 'generatePasswordUserTemplate.php';
                break;
            case 'change':
                $mailTitle = APPLICATION_NAME.' password changed';
                $templateUrl = 'changedPasswordTemplate.php';
                break;
            default:
                return [
                    'code' => 'error',
                    'message' => 'ACTION_NOT_SET'
                ];

        }

        $passwordValidationUrl = $userInfo['idUserType'] == self::ID_TYPE_CUSTOMER ? WIAAS_URL.'/changePassword/' . $token : WIAAS_URL.'/api-wiaas/login?token=' . $token;

        $params = [
            'username' => $userInfo['username'],
            'wiaas' => $userInfo['type'] === USER_TYPES['CUSTOMER'] ? WIAAS_URL : WIAAS_URL.'/api-wiaas',
            'urlValidate' => $passwordValidationUrl
        ];

        $response = Mail::sendMail($mail, $mailTitle, $templateUrl, $params);

        if($response){
            return [
                'code' => 'success',
                'message' => 'MAIL_SENT'
            ];
        }

        return [
            'code' => 'error',
            'message' => 'ERROR_MAIL_SENT'
        ];
    }

    private static function validatePassword($username, $passwordData, $isForReset = false) {
        global $database, $user;
        $data = [];

        if ((!array_key_exists('newPassword', $passwordData) || $passwordData['newPassword'] === '') ||
            (!array_key_exists('confirmPassword', $passwordData) || $passwordData['confirmPassword'] === '')) {
            $data['messages'][] = [
                'code' => 'error',
                'message' => 'PASSWORDS_MISSING'
            ];

            return $data;
        }

        $newPassword = $database->escapeValue($passwordData['newPassword']);
        $confirmPassword = $database->escapeValue($passwordData['confirmPassword']);

        if(!$isForReset) {
            if($data = self::validateOldPassword($passwordData, $username)) {
                return $data;
            }
            $oldPassword = $database->escapeValue($passwordData['oldPassword']);
            if($oldPassword === $newPassword) {
                $data['messages'][] = [
                    'code' => 'error',
                    'message' => 'PASSWORD_SAME'
                ];
                return $data;
            }
        }

        if($newPassword !== $confirmPassword) {
            $data['messages'][] = [
                'code' => 'error',
                'message' => 'PASSWORD_MISMATCH'
            ];

            return $data;
        }

        if((strlen($newPassword) < 8) ||
            !preg_match("/((?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[!@#$%-_]).{8,20})/", $newPassword)
            ) {
            $data['messages'][] = [
                'code' => 'error',
                'message' => 'PASSWORD_INCORRECT'
            ];
        }

        return $data;
    }

    private static function validateOldPassword($passwordData, $username) {
        global $database, $user;
        $data = [];

        $oldPassword = $database->escapeValue($passwordData['oldPassword']);

        if (!array_key_exists('oldPassword', $passwordData) || $passwordData['oldPassword'] === '') {
            $data['messages'][] = [
                'code' => 'error',
                'message' => 'PASSWORDS_MISSING'
            ];

            return $data;
        }

        $sql = "SELECT u.password
                    FROM ".TABLES['users']." u
                WHERE  u.username='".$database->escapeValue($username)."'
                LIMIT 1";
        $row = $database->fetchResultArray($sql);

        if($row[0] && $row[0]['password'] && !password_verify($oldPassword, $row[0]['password'])) {
            $data['messages'][] = [
                'code' => 'error',
                'message' => 'OLD_PASSWORD_MISMATCH'
            ];
        }

        return $data;
    }

    /**
     * fetches the username and the email for the user logged in
     * @return Array    username and mail
     */
    private static function getUserData($username = '') {
        global $database, $user;

        $username = $username ? $username : $user->getUser();

        $sql = "SELECT
                  u.id AS idUser,
                  u.mail,
                  u.username,
                  ut.type,
                  rut.idType AS idUserType
                FROM ".TABLES['users']." u
                INNER JOIN ".TABLES['rel_user_type']." rut
                    ON rut.idUser=u.id
                INNER JOIN ".TABLES['user_types']." ut
                    ON ut.id=rut.idType
                WHERE u.username='".$database->escapeValue($username)."'";

        return $database->fetchResultArray($sql);
    }

    /**
     * send order confirmation email to user
     * @param  Array $cartPackages contains the packages ordered
     * @param  String $userType    customer or broker
     * @param  Array $orderInfo    contains information about the order like id, order number and so on
     * @return Array               confirmation message
     */
    public static function sendOrderConfirmationMail($cartPackages, $userType, $orderInfo) {
        $mail = '';
        $orderUrl = WIAAS_URL.'/api-wiaas/orders?subModule=orders_steps&idOrder='.$orderInfo['idOrder'].'&orderNumber='.$orderInfo['orderNumber'];

        if($userType === USER_TYPES['CUSTOMER']) {
            $templateUrl = 'orderConfirmationTemplate.php';
            $mailTitle = 'Order successfully placed';
            $userData = self::getUserData();

            if($userData && $userData[0]['mail']) {
                $mail = $userData[0]['mail'];
            }
            $message = 'MAIL_SENT';
            $orderUrl = WIAAS_URL.'/orders/'.$orderInfo['idOrder'];
        } else if($userType === USER_TYPES['BROKER']){
            $templateUrl = 'orderConfirmationBrokerTemplate.php';
            $mailTitle = 'New order placed';
            $brokerData = self::getBrokersMail();

            if($brokerData) {
                $mail = $brokerData;
            }
            $message = 'BROKER_MAIL_SENT';
        }

        $currentDate = new DateTime();
        $currentDate = $currentDate->format('d-m-Y H:i');

        $params = [
            'cartPackages' => $cartPackages,
            'currentDate' => $currentDate,
            'orderNumber' => $orderInfo['orderNumber'],
            'orderDate' => $orderInfo['orderDate'],
            'orderUrl' => $orderUrl
        ];
        $response = Mail::sendMail($mail, $mailTitle, $templateUrl, $params);

        if($response){
            return [
                'code' => 'success',
                'message' => $message
            ];
        }

        return [
            'code' => 'error',
            'message' => 'ERROR_MAIL_SENT'
        ];
    }

    public static function getBrokersMail() {
        global $database;

        $sql="SELECT u.mail
                FROM ".TABLES['brokers']." b
                INNER JOIN ".TABLES['users']." u
                    ON u.id = b.idUser";

        $result = $database->query($sql);
        while($row = $database->fetchArray($result)) {
            if($row['mail'] !== '') {
                $mailArray[] = $row['mail'];
            }
        }
        return (count($mailArray) === 0 || count($mailArray) > 1) ? $mailArray : $mailArray[0];
    }

    public static function sendOrderUpdateMail($mailType, $params, $mailTitle, $mails) {
        global $user;
        $templateUrl = $mailType.'Template.php';
        $response = '';

        if(array_key_exists('customer', $mails) && count($mails['customer'])) {
            $response = Mail::sendMail($mails['customer'], $mailTitle, $templateUrl, $params);
        }

        if($user->getUserType() !== USER_TYPES['BROKER']) {
            $usersMails = array_key_exists('other', $mails) ? (array) $mails['other'] : [];
            $brokerMails = (array) self::getBrokersMail();
            $mails['other'] = array_merge($usersMails, $brokerMails);
            $params['orderUrl'] = $params['apiOrderUrl'];
        }

        if(array_key_exists('other', $mails)) {
            $response = Mail::sendMail($mails['other'], $mailTitle, $templateUrl, $params);
        }

        if($response){
            return [
                'code' => 'success',
                'message' => 'ORDER_UPDATE_MAIL_SENT'
            ];
        }

        return [
            'code' => 'error',
            'message' => 'ERROR_MAIL_SENT'
        ];
    }

    public function downloadFile($idDocument, $fileName, $fileType){
        $fileManager = new FileManager();

        return $fileManager->downloadFile($idDocument, $fileName, $fileType);
    }

    /**
     * returns the mail and order number for an order
     * @param  Int $idOrder    the id of the order
     * @return Array           mail of the customer and the order number
     */
    public static function getDataForMailToCustomer($idOrder) {
        global $database;

        $sqlCustomerInfo = "SELECT u.mail,
                                o.orderNumber
                            FROM ".TABLES['customers']." c
                            INNER JOIN ".TABLES['rel_commercial_lead_customers']." rclc
                                ON c.id=rclc.idCustomer
                            INNER JOIN ".TABLES['users']." u
                                ON u.id = c.idUser
                            INNER JOIN ".TABLES['orders']." o
                                ON o.idCustomerInstance=rclc.id
                            WHERE o.id=$idOrder
                            LIMIT 1";
        $query = $database->query($sqlCustomerInfo);

        return $database->fetchArray($query);
    }

    /**
     * get the orderNumber based on the order id
     * @param  Int $idOrder the id of the order
     * @return Int           the order number of that order
     */
    public static function getOrderNumberById($idOrder) {
        global $database;

        $sql = "
            SELECT
                o.orderNumber
            FROM
                ".TABLES['orders']." o
            WHERE o.id = $idOrder
            LIMIT 1
        ";
        $orderNumberArray = $database->fetchResultArray($sql);
        if($orderNumberArray && $orderNumberArray[0]) {
            return array_key_exists('orderNumber', $orderNumberArray[0]) ? $orderNumberArray[0]['orderNumber'] : '';
        }

        return '';
    }
}
