<?php
class DashboardsModel{

    /**
     * get all gadgets by user type (used for creating new dashboards)
     * @param  INT $idDashboard      id of the dashborad
     * @param  INT $selectedUserType id of the user type that was selected
     * @return array                  gadgets array
     */
    public function getAllGadgets($idDashboard, $selectedUserType){
        global $database, $user;

        $idDashboard = $database->escapeValue($idDashboard);
        $idUserType = ($user->getUserType() === USER_TYPES['BROKER'] && intval($selectedUserType) !== 0)
            ? $selectedUserType
            : $user->getIdUserType();

        $sql = "SELECT g.id AS idGadget,
                        g.name,
                        g.module,
                        CASE WHEN rdg.idGadget IS NULL THEN 0 ELSE 1 END AS isSelected
                        FROM ".TABLES['gadgets']." g
                        INNER JOIN ".TABLES['rel_user_types_gadgets']." rutg
                            ON rutg.idGadget=g.id
                        LEFT OUTER JOIN ".TABLES['rel_dashboard_gadgets']." rdg
                            ON rdg.idGadget=g.id AND rdg.idDashboard=$idDashboard
                        WHERE rutg.idUserType=".$idUserType."
                        ORDER BY g.name";

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

    /**
     * get info for a dashbord on edit
     * @param  INT $idDashboard id of the dashborad
     * @return HASHARRAY        dashborad info
     */
    public function getDashboardInfo($idDashboard){
        global $database, $user;
        $data = [];
        $whereSql = $user->getUserType() === USER_TYPES['BROKER']
            ? "AND (d.idUser=".$user->getUserId()." OR d.visibility='public')"
            : "AND (d.idUser=".$user->getUserId().")";

        $idDashboard = intval($database->escapeValue($idDashboard));
        $sql = "SELECT
                    d.id AS idDashboard,
                    d.name,
                    d.visibility,
                    d.idUserType
                FROM ".TABLES['dashboards']." d
                WHERE d.id=$idDashboard $whereSql";
        $info = $database->fetchResultArray($sql);
        if(empty($info)){
            return [
                'messages' => [
                    'code' => 'error',
                    'message' => 'NOT_OWNER_OF_DASHBAORD'
            ]];
        }
        $data['dashboardInfo'] = $info[0];

        return $data;
    }

    /**
     * get all gadgets in a dashborad
     * @param  INT $idDashboard id of the dashborad
     * @return Array            array of gadgets
     */
    private function getGadgets($idDashboard){
        global $database;

        $sql = "SELECT
                    g.id AS idGadget,
                    g.name,
                    g.module,
                    rdg.position
                FROM ".TABLES['gadgets']." g
                INNER JOIN  ".TABLES['rel_dashboard_gadgets']." rdg
                    ON rdg.idGadget=g.id
                WHERE rdg.idDashboard=$idDashboard
                ORDER by rdg.position";

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

    /**
     * get all dashborads for a user (including public ones)
     * @return ARRAY array with all dashborads
     */
    public function getUserDashboards(){
        global $database, $user;
        $data = [];
        $extraFields = '';
        $whereSql = $user->getUserType() === USER_TYPES['BROKER']
            ? ""
            : "AND d.idUserType=".$user->getIdUserType();

        $sql = "SELECT d.id AS idDashboard,
                       d.name,
                       d.visibility,
                       ut.type
                FROM ".TABLES['dashboards']." d
                INNER JOIN ".TABLES['user_types']." ut
                    ON ut.id=d.idUserType
                WHERE d.idUser=".$user->getUserId()." OR (d.visibility='public' $whereSql)
                ORDER BY d.idUserType, d.lastUpdated DESC";
        $query = $database->query($sql);
        while($row = $database->fetchArray($query)){
            $data[$row['type']][] = $row;
        }

        return $data;
    }

    /**
     * get information to show for dashborad view
     * @param  INT $idDashboard id of the dashborad
     * @return HASHARRAY        dahsborad info
     */
    public function getMyDashboard($idDashboard){
        global $database, $user;
        $data = [];
        $whereSql = $user->getUserType() === USER_TYPES['BROKER']
            ? "(d.idUser=".$user->getUserId()." OR d.visibility='public')"
            : "(d.idUser=".$user->getUserId()." OR (d.visibility='public' AND d.idUserType=".$user->getIdUserType()."))";
        $isOwner = $user->getUserType() === USER_TYPES['BROKER']
            ? "1 AS isOwner"
            : "CASE WHEN d.idUser=".$user->getUserId()." THEN 1 ELSE 0 END AS isOwner";
        $idDashboard = intval($database->escapeValue($idDashboard));
        if($idDashboard !== 0){
            $whereSql .= "AND d.id=$idDashboard";
        }

        $sql = "SELECT d.id AS idDashboard,
                       d.name,
                       $isOwner
                FROM ".TABLES['dashboards']." d
                WHERE $whereSql
                ORDER BY d.lastUpdated DESC
                LIMIT 1";
        $data['info'] = $database->fetchResultArray($sql);
        $data['info'] = isset($data['info'][0]) ? $data['info'][0] : [];
        if(!empty($data['info'])){
            $data['gadgets'] = $this->getGadgets($data['info']['idDashboard']);
        }else{
            return $this->getMyDashboard(0);
        }

        return $data;
    }

    /**
     * generate a filter condition on gadget filter
     * @param Array $filters array of filters
     * @return string sql filter condtion
     */
    private function setFilterSql($filters){
        $whereSql = "1=1";

        if(!empty($filters)){
            foreach ($filters as $key => $filterValue) {
                $whereSql .= " AND $key like '%$filterValue%'";
            }
        }

        return $whereSql;
    }

    private function setOrderBySql($sortBy){
        $orderBySql = "";
        if( isset($sortBy->key) && isset($sortBy->direction) ){
            $orderBySql .= $sortBy->key." ".$sortBy->direction;
        }

        return $orderBySql;
    }

    /**
     * get information for the order central gadget
     * @param  Array $filters array of filters to be applied
     * @return Array          array with orders info
     */
    public function getOrderCentralInfo($filters, $sortBy){
        global $database, $user;

        $filters = json_decode($filters);
        $sortBy = json_decode($sortBy);
        $whereSql = $this->setFilterSql($filters);
        $orderBySql = $this->setOrderBySql($sortBy);
        $extraJoin = '';
        $extraWhere = '';
        if(!$orderBySql){
            $orderBySql = "orderDate DESC";
        }

        if($user->getUserType() === USER_TYPES['BROKER']) {
            $extraWhere = "AND (
                                  b.idUser = ".$user->getUserId()."
                                  OR o.assignedTo IS NULL
                              )";
        }

        if($user->getUserType() === USER_TYPES['CUSTOMER']) {
            $extraJoin = "INNER JOIN ".TABLES['rel_commercial_lead_customers']." rclc
                             ON rclc.id = o.idCustomerInstance
                          INNER JOIN ".TABLES['customers']." c
                             ON rclc.idCustomer = c.id
                             AND c.idUser = ".$user->getUserId();
        }

        if($user->getUserType() === USER_TYPES['COMMERCIAL_LEAD']) {
            $extraJoin = "INNER JOIN ".TABLES['rel_commercial_lead_customers']." rclc
                             ON rclc.id = o.idCustomerInstance
                             INNER JOIN ".TABLES['commercial_leads']." cl
                                ON rclc.idCommercialLead = cl.id
                                AND cl.idUser = ".$user->getUserId();
        }

        if($user->getUserType() === USER_TYPES['SUPPLIER']) {
            $extraJoin = "INNER JOIN ".TABLES['rel_package_products']." rpp
                            ON rpp.idPackage=rop.idPackage AND rop.packageInstance=rpp.packageInstance
                        INNER JOIN ".TABLES['suppliers_countries_products']." scp
                            ON scp.idProduct=rpp.idProduct
                        INNER JOIN ".TABLES['suppliers']." s
                            ON s.id=scp.idSupplier
                            AND s.idUser=".$user->getUserId();
        }

        $sql = "SELECT * FROM(
                    SELECT o.id AS idOrder,
                    o.orderNumber,
                    o.orderDate,
                    IF(b.name IS NULL, 'unassigned', b.name) AS assignedTo,
                    SUM(rop.packageFixedPrice * rop.units) AS fixedPrice,
                    SUM((rop.packageRecuringPrice * rop.units) + (rop.packageServicePrice * rop.units)) AS recurringPrice,
                    o.status
                    FROM ".TABLES['orders']." o
                    INNER JOIN ".TABLES['rel_order_packages']." rop
                        ON rop.idOrder=o.id
                    $extraJoin
                    LEFT JOIN ".TABLES['brokers']." b
                        ON o.assignedTo = b.id
                    WHERE o.status!='production' AND o.status!='canceled' AND o.status!='end-of-life'
                        $extraWhere
                    GROUP BY o.id
                ) orders
                WHERE $whereSql
                ORDER BY $orderBySql
                LIMIT 5";

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

    /**
     * get information for the assigned orders gadget
     * @param  Array $filters array of filters to be applied
     * @param  Array $sortBy  array of element to apply the sorting
     * @return Array          array with orders info
     */
    public function getAssignedOrdersInfo($filters, $sortBy){
        global $database, $user;

        $filters = json_decode($filters);
        $sortBy = json_decode($sortBy);
        $whereSql = $this->setFilterSql($filters);
        $orderBySql = $this->setOrderBySql($sortBy);
        if(!$orderBySql){
            $orderBySql = "orderDate DESC";
        }

        $sql = "SELECT * FROM(
                    SELECT o.id AS idOrder,
                    o.orderNumber,
                    o.orderDate,
                    b.name AS assignedTo,
                    SUM(rop.packageFixedPrice * rop.units) AS fixedPrice,
                    SUM((rop.packageRecuringPrice * rop.units) + (rop.packageServicePrice * rop.units)) AS recurringPrice,
                    o.status
                    FROM ".TABLES['orders']." o
                    INNER JOIN ".TABLES['rel_order_packages']." rop
                        ON rop.idOrder=o.id
                    LEFT JOIN ".TABLES['brokers']." b
                        ON o.assignedTo = b.id
                    WHERE o.status!='production' AND o.status!='canceled' AND o.status!='end-of-life'
                        AND b.idUser != ".$user->getUserId()."
                        AND o.assignedTo IS NOT NULL
                    GROUP BY o.id
                ) orders
                WHERE $whereSql
                ORDER BY $orderBySql
                LIMIT 5";

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

    /**
     * get information for next actions gadget
     * @param  Array $filters array of filters to be applied
     * @return Array          array with next actions
     */
    public function getNextActionsInfo($filters, $sortBy){
        global $database, $user;

        $filters = json_decode($filters);
        $whereSql = $this->setFilterSql($filters);
        $orderBySql = $this->setOrderBySql($sortBy);
        $data = [];
        if(!$orderBySql){
            $orderBySql = "idOrder DESC";
        }
        if($user->getUserType() === USER_TYPES['BROKER']){
            $sql = "SELECT * FROM(
                    SELECT
                        DISTINCT o.id as  idOrder,
                        o.orderNumber,
                        ps.shortDesc as stepAction,
                        'in-progress' AS status
                    FROM ".TABLES['rel_order_process_step']." rops
                    INNER JOIN ".TABLES['orders']." o
                        ON o.id=rops.idOrder
                    INNER JOIN ".TABLES['rel_process_steps']." rps
                        ON rps.id=rops.idProcessStep
                    INNER JOIN ".TABLES['process_step']." ps
                        ON ps.id=rps.idStep
                    WHERE rops.status='in-progress'
                    ) actions
                    WHERE $whereSql
                    ORDER BY $orderBySql
                    LIMIT 7";

            $data = $database->fetchResultArray($sql);
        }else{
            $sqlTemp= "CREATE TEMPORARY TABLE temp_next_actions AS (
                SELECT * FROM(
                        SELECT
                            o.id as idOrder,
                            rops.idPackage,
                            o.orderNumber,
                            ps.shortDesc as stepAction,
                            ps.idActionCode
                        FROM ".TABLES['rel_order_process_step']." rops
                        INNER JOIN ".TABLES['orders']." o
                            ON o.id=rops.idOrder
                        INNER JOIN ".TABLES['rel_commercial_lead_customers']." rclc
                            ON rclc.id=o.idCustomerInstance
                        INNER JOIN ".TABLES['customers']." c
                            ON c.id=rclc.idCustomer
                        INNER JOIN ".TABLES['rel_process_steps']." rps
                            ON rps.id=rops.idProcessStep
                        INNER JOIN ".TABLES['process_step']." ps
                            ON ps.id=rps.idStep
                        WHERE c.idUser=" .$user->getUserId(). " AND rops.status='in-progress' AND ps.idActionCode IN(4,6,8)
                        ) actions
                        WHERE $whereSql
                        ORDER BY $orderBySql
                        LIMIT 7
            )";
            $query = $database->query($sqlTemp);

            //questionnaiire validation
            $sql = "SELECT
                        tna.idOrder,
                        tna.orderNumber,
                        tna.stepAction,
                        rod.validation as status
                    FROM temp_next_actions tna
                    INNER JOIN ".TABLES['rel_order_documents']." rod
                        ON rod.idOrder=tna.idOrder AND rod.idPackage=tna.idPackage
                    WHERE tna.idActionCode=4 AND rod.validation='invalid'";
            $data = $database->fetchResultArray($sql);

            //customer acceptance
            $sql = "SELECT
                        tna.idOrder,
                        tna.orderNumber,
                        tna.stepAction,
                        'not-accepted' as status
                    FROM temp_next_actions tna
                    INNER JOIN ".TABLES['rel_order_packages']." rop
                        ON rop.idOrder=tna.idOrder AND rop.idPackage=tna.idPackage
                    WHERE tna.idActionCode=6 AND rop.customerAccepted=0";
            $data = array_merge($data, $database->fetchResultArray($sql) );

            //schedule meeting
            $sql = "SELECT
                        DISTINCT tna.idOrder,
                        tna.orderNumber,
                        tna.stepAction,
                        'pending' as status
                    FROM temp_next_actions tna
                    INNER JOIN ".TABLES['rel_order_scheduled_dates']." rosd
                        ON rosd.idOrder=tna.idOrder AND rosd.idPackage=tna.idPackage
                    WHERE tna.idActionCode=8 AND rosd.isDateConfirmed=0";
            $data = array_merge($data, $database->fetchResultArray($sql) );

            $delSql = "DROP TABLE temp_next_actions";
            $query = $database->query($delSql);
        }

        return $data;
    }

    /**
     * validate data for creating / editing a dashborad
     * @param  INT $idDashboard      id for the dashborad (used only for edit)
     * @param  String $name             name for the deshborad
     * @param  String $visibility       visibility of dashboard (can be public or private)
     * @param  Array $gadgets          array of gadgets for dashborad
     * @param  INT $selectedUserType  id of the user type for witch the gadget is created / edited
     * @return Array                 validation error message or null in case of valid data
     */
    private function validateDashboardData($idDashboard, $name, $visibility, $gadgets, $selectedUserType){
        global $database, $user;
        $data = [];

        if(empty($gadgets)){
            $data['messages'][] =[
                'code' => 'error',
                'message' => 'NO_GADGETS'
            ];

            return $data;
        }

        $idDashboard = $database->escapeValue($idDashboard);
        $name = $database->escapeValue($name);
        $visibility = $database->escapeValue($visibility);
        $selectedUserType = $database->escapeValue($selectedUserType);

        if($idDashboard === 'null'){
            $sql = "SELECT d.id
                    FROM ".TABLES['dashboards']." d
                    WHERE name='$name' AND idUser=".$user->getUserId(). "
                    LIMIT 1";
            $query = $database->query($sql);
            if($database->numRows($query) > 0){
                $data['messages'][] =[
                    'code' => 'error',
                    'message' => 'NAME_ALREADY_EXISTS'
                ];

                return $data;
            }
        }

        if($visibility !== 'private' && $visibility !== 'public'){
            $data['messages'][] =[
                'code' => 'error',
                'message' => 'INVALID_VISIBILITY'
            ];
        }

        $checkMessage = $database->isEmpty('NAME', $name);
        if($checkMessage){
            $data['messages'][] = $checkMessage;
        }

        $checkMessage = $database->invalidLength('NAME', $name, 60);
        if($checkMessage){
            $data['messages'][] = $checkMessage;
        }

        if($visibility === 'public'){
            $checkMessage = $database->isEmpty('UserType', $selectedUserType);
            if($checkMessage){
                $data['messages'][] = $checkMessage;
            }
        }

        return $data;
    }

    /**
     * insert or update the gadgets for a dashborad
     * @param  INT $idDashboard id of the dashboard
     * @param Array $gadgets     array of gadgets
     * @return INT              number of affected rows
     */
    private function insertUpdateGadgets($idDashboard, $gadgets){
        global $database;
        $newIds = "";

        $sql = "INSERT IGNORE INTO ".TABLES['rel_dashboard_gadgets']."
                (idDashboard, idGadget, position)
                VALUES";

        foreach ($gadgets as $gadget) {
            $gadget->idGadget = $database->escapeValue($gadget->idGadget);
            $gadget->position = $database->escapeValue($gadget->position);
            $sql .= "($idDashboard, $gadget->idGadget, $gadget->position),";
            $newIds .= $gadget->idGadget.",";
        }
        $newIds = rtrim($newIds, ',');
        $sql = rtrim($sql, ',');
        $query = $database->query($sql);

        $modified = $database->affectedRows();

        $sql = "DELETE FROM ".TABLES['rel_dashboard_gadgets']."
                WHERE idDashboard=$idDashboard AND idGadget NOT IN($newIds)";
        $query = $database->query($sql);

        $modified += $database->affectedRows();

        return $modified;
    }

    /**
     * create or edit a dashborad
     * @param INT $idDashboard      id of the dashborad(used only for edit)
     * @param  String $name             name for the dashbroad
     *  @param  String $visibility       visibility of dashboard (can be public or private)
     * @param  Array $gadgets          array of gadgets for dashborad
     * @param  INT $selectedUserType  id of the user type for witch the gadget is created / edited
     * @return Array                   update message
     */
    public function createDashboard($idDashboard, $name, $visibility, $gadgets, $selectedUserType){
        global $database, $user;
        $data = [];

        $gadgets = json_decode($gadgets);
        $idUserType = $user->getIdUserType();
        $idUser = $user->getUserId();
        if($visibility === 'public'){
            $selectedUserType = ($user->getUserType() === USER_TYPES['BROKER'] && $selectedUserType !== 0) ? $selectedUserType : $idUserType;
            $idUser = 'null';
        }else{
            $selectedUserType = $idUserType;
        }

        if(intval($idDashboard) !== 0){
            $whereSql = $user->getUserType() !== USER_TYPES['BROKER']
                ? " AND d.idUser=".$user->getUserId()
                : " AND (d.visibility='public' OR d.idUser=".$user->getUserId().")";

            $sql = "SELECT
                        d.id AS idDashboard
                    FROM ".TABLES['dashboards']." d
                    WHERE d.id=$idDashboard $whereSql
                    LIMIT 1";
            $query = $database->query($sql);
            $isMyDashboard = $database->numRows($query) > 0 ? true : false;

            if(!$isMyDashboard){
                $data['messages'][] =[
                    'code' => 'error',
                    'message' => 'NOT_OWNER_OF_DASHBAORD'
                ];

                return $data;
            }
        }else{
            $idDashboard = 'null';
        }

        $data = $this->validateDashboardData($idDashboard, $name,  $visibility, $gadgets, $selectedUserType);

        if(!empty($data)){
            return $data;
        }

        $sql = "INSERT INTO ".TABLES['dashboards']."
                (id, idUser, idUserType, name, visibility)
                VALUES($idDashboard,".$idUser.",'$selectedUserType','$name', '$visibility')
                ON DUPLICATE KEY UPDATE
                name=VALUES(name),
                idUserType=VALUES(idUserType),
                visibility=VALUES(visibility)";
        $query = $database->query($sql);

        $idDashboard = $idDashboard == 'null' ? $database->getInsertId() : $idDashboard;

        $insertGadgetsMessage = $this->insertUpdateGadgets($idDashboard, $gadgets);

        if(intval($idDashboard) !== 0){
            $data['messages'][] =[
                'code' => 'success',
                'message' => 'DASHBORAD_UPDATED'
            ];
        }else{
            $data['messages'][] =[
                'code' => 'success',
                'message' => 'DASHBORAD_CREATED'
            ];
        }

        return $data;
    }

    /**
     * get user types in the system
     * @return Array array with user types
     */
    public function getUserTypes(){
        global $database, $user;

        if($user->getUserType() !== USER_TYPES['BROKER']){
            return [];
        }

        $sql = "SELECT ut.id,
                        ut.type
                FROM ".TABLES['user_types']." ut";

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

    /**
     * remove a dashborad
     * @param  INT $idDashboard id of the dashborad
     * @return Array             update message
     */
    public function removeDashboard($idDashboard){
        global $database, $user;

        $idDashboard = $database->escapeValue($idDashboard);

        $data = [];

        $whereSql = $user->getUserType() === USER_TYPES['BROKER']
            ? "AND (d.idUser=".$user->getUserId()." OR d.visibility='public')"
            : "AND (d.idUser=".$user->getUserId().")";

        $idDashboard = intval($database->escapeValue($idDashboard));
        $sql = "SELECT
                    d.id AS idDashboard
                FROM ".TABLES['dashboards']." d
                WHERE d.id=$idDashboard $whereSql";
        $info = $database->fetchResultArray($sql);
        if(empty($info)){
            $data['messages'][] = [
                    'code' => 'error',
                    'message' => 'NOT_OWNER_OF_DASHBAORD'
            ];

            return $data;
        }

        $sql = "DELETE FROM ".TABLES['dashboards']."
                WHERE id=$idDashboard";

        $query = $database->query($sql);
        if($database->affectedRows() > 0 ){
            $data['messages'][] = [
                    'code' => 'success',
                    'message' => 'DASHBORAD_REMOVED'
            ];

            return $data;
        }

        $data['messages'][] =[
            'code' => 'error',
            'message' => 'DASHBORAD_REMOVE_ERROR'
        ];

        return $data;
    }

}
?>
