<?php

class InstallationScheduling{
    const ID_ADDITONAL_TYPE = 3;
    const CUSTOMER_ACCEPTANCE_DAYS_INTERVAL = 15;
    const ID_INSTALLATION_CATEGORY = 2;

    /**
     * get all installation companies for the order and package selected
     * @param  Int $idOrder   id of the order
     * @param  Int $idPackage id of the package
     * @return Array          array with all the installation companies
     */
    public function getInstallCompaniesForPackage($idOrder, $idPackage) {
        global $database, $user;

        $idOrder = $database->escapeValue($idOrder);
        $idPackage = $database->escapeValue($idPackage);
        $whereSql = '';
        $installationSelectedArray = [];
        $installationSelected = [];
        $isMyInstallationCompany = false;
        $extraWhere = '';
        $extraJoin = '';

        if(!$idOrder) {
            return [];
        }

        if($user->getUserType() === USER_TYPES['SUPPLIER']) {
            $extraWhere = "AND u.id = ".$user->getUserId();
            $extraJoin = "INNER JOIN ".TABLES['installation_company_selections']." ics
                            ON ics.idProduct = rpp.idProduct
                            AND ics.idPackage = rpp.idPackage
                            AND ics.idOrder = rop.idOrder
                            AND ics.isActive = 1";
        }
        $whereSql = $idPackage != 0 ? "AND os.idPackage = $idPackage" : "";

        $sql = "
                SELECT
                  scp.idProduct AS id,
                  scp.idSupplier,
                  scp.productName AS name
                FROM
                  ".TABLES['order_selections']." os
                  INNER JOIN ".TABLES['suppliers_countries_products']." scp
                    ON scp.idProduct = os.idProduct
                  INNER JOIN ".TABLES['suppliers']." s
                    ON s.id = scp.idSupplier
                  INNER JOIN ".TABLES['users']." u
                    ON u.id = s.idUser
                WHERE os.idOrder = $idOrder
                  $whereSql
                  AND os.selectionFor = 'installation'
                  $extraWhere
                  LIMIT 1
        ";
        $installationSelectedArray = $database->fetchResultArray($sql);
        if(count($installationSelectedArray) > 0) {
            $installationSelected = $installationSelectedArray;
            $isMyInstallationCompany = true;
        }

        $whereSql = $idPackage != 0 ? "AND rpp.idPackage = $idPackage" : "";
        $sql = "
                SELECT
                  scp.idProduct AS id,
                  scp.idSupplier,
                  scp.productName AS name
                FROM
                  ".TABLES['rel_package_products']." rpp
                  INNER JOIN ".TABLES['rel_order_packages']." rop
                    ON rop.idPackage = rpp.idPackage
                    AND rpp.packageInstance = rop.packageInstance
                  INNER JOIN ".TABLES['suppliers_countries_products']." scp
                    ON scp.idProduct = rpp.idProduct
                  INNER JOIN ".TABLES['product_categories']." pc
                    ON pc.id = scp.idProductCategory
                  INNER JOIN ".TABLES['product_types']." pt
                    ON pt.id = pc.idType
                  INNER JOIN ".TABLES['suppliers']." s
                    ON s.id = scp.idSupplier
                  INNER JOIN ".TABLES['users']." u
                    ON u.id = s.idUser
                    $extraJoin
                WHERE pt.type = 'installation'
                    AND rop.idOrder = $idOrder
                    $whereSql
                    $extraWhere
        ";
        $availableCompanies = $database->fetchResultArray($sql);
        if(count($availableCompanies) === 1) {
            $installationSelected = $availableCompanies;
            if(!$isMyInstallationCompany) {
                $isMyInstallationCompany = true;
            }
        }

        return [
            'available' => $availableCompanies,
            'selected' => $installationSelected,
            'isMyInstallationCompany' => $isMyInstallationCompany
        ];
    }

    /**
     * save the installation company
     * @param  [type] $idOrder        [description]
     * @param  [type] $idPackage      [description]
     * @param  [type] $idInstallation [description]
     * @return [type]                 [description]
     */
    public function saveInstallationCompany($idOrder, $idPackage, $idInstallation) {
        global $database;

        $idOrder = $database->escapeValue($idOrder);
        $idPackage = $database->escapeValue($idPackage);
        $idInstallation = $database->escapeValue($idInstallation);

        $installationScheduling = new InstallationScheduling();

        if(!$idOrder || !$idPackage || !$idInstallation) {
            $data['messages'][] = [
                'code' => 'error',
                'message' => 'DATA_NOT_SET'
            ];

            return $data;
        }

        $sqlSelect = "
            SELECT idProduct
            FROM ".TABLES['order_selections']."
            WHERE idOrder = $idOrder
                AND idPackage = $idPackage
        ";
        $result = $database->query($sqlSelect);

        if($database->numRows($result) > 0) {
            $sql = "
                UPDATE
                    ".TABLES['order_selections']."
                SET
                    idProduct = $idInstallation
                WHERE idOrder = $idOrder AND idPackage = $idPackage";
        } else {
            $sql = "
                INSERT INTO ".TABLES['order_selections']."
                    (idOrder, idPackage, idProduct, selectionFor)
                VALUES
                    ($idOrder, $idPackage, $idInstallation, 'installation')
            ";
        }
        $result = $database->query($sql);

        $data = self::changeInstallationCompany($idOrder, $idPackage, $idInstallation);
        $data['messages'][] = self::setSchedulingFlagForCustomer($idOrder, $idPackage, 1);

        return $data;
    }

    /**
     * customer change acceptance status for a package
     * @param  INT $idOrder   id for the order
     * @param  INT $idPackage id for the packages
     * @param  String $actionType accept or decline the installation
     * @param  String $declineReason the reason why the customer declined the installation
     * @return Array          update message
     */
    public function acceptDeclineInstallation($idOrder, $idPackage, $actionType, $declineReason){
        global $database;
        $idOrder = $database->escapeValue($idOrder);
        $idPackage = $database->escapeValue($idPackage);
        $actionType = trim($database->escapeValue($actionType));
        $declineReason = trim($database->escapeValue($declineReason));
        $data = [];
        $customerAcceptanceStatus = 1;
        $successMessage = 'INSTALLATION_ACCEPTED';

        if($actionType === 'decline') {
            if(!$declineReason) {
                $data['messages'][] = [
                    'code' => 'error',
                    'message' => 'DECLINE_REASON_EMPTY'
                ];

                return $data;
            }
            $customerAcceptanceStatus = -1;
            $successMessage = 'INSTALLATION_DECLINED';
        }

        $sql = "UPDATE ".TABLES['rel_order_packages']."
                SET customerAccepted=$customerAcceptanceStatus,
                    customerDeclineReason='$declineReason'
                WHERE idOrder=$idOrder AND idPackage=$idPackage";
        $query = $database->query($sql);

        if($database->affectedRows() > 0){
            $data['messages'][] = [
                'code' => 'success',
                'message' => $successMessage
            ];
        }else{
            $data['messages'][] = [
                'code' => 'warning',
                'message' => 'ACCEPTANCE_NOT_UPDATED'
            ];
        }

        return $data;
    }

    /**
     * sets the earliest installation date in DB
     * @param Int $idOrder                  id of the order
     * @param Int $idPackage                id of the package
     * @param String $maxDeliveryDate       maximumDeliveryDate
     * @return Array                        id of the order and package of the row inserted
     */
    public function setEarliestInstallationDateInDb($idOrder, $idPackage, $maxDeliveryDate) {
        global $database, $user;
        $idOrder = $database->escapeValue($idOrder);
        $idPackage = $database->escapeValue($idPackage);
        $maxDeliveryDate = $database->escapeValue($maxDeliveryDate);
        $whereSql = $idPackage != 0 ? "AND idPackage = $idPackage" : "";
        $rowsAffected = 0;
        $data = [];

        if(!$idOrder) {
            $data['messages'][] = [
                'code' => 'error',
                'message' => 'ORDER_NOT_SET'
            ];
        }

        if(empty($maxDeliveryDate)) {
            $data['messages'][] = [
                'code' => 'error',
                'message' => 'DATE_NOT_SET'
            ];
        }

        if(isset($data['messages'])) {
            return $data;
        }

        if($maxDeliveryDate === 'remove'){
            $sql = "
                    UPDATE ".TABLES['rel_order_packages']."
                    SET
                        earliestInstallationDate = null
                    WHERE idOrder = $idOrder $whereSql";
            $result = $database->query($sql);
            $rowsAffected = $database->affectedRows();

            if($rowsAffected > 0) {
                $data = [
                    'idOrder' => $idOrder,
                    'idPackage' => $idPackage
                ];
            }

            $data['messages'][] = $this->removeInstallationDates($idOrder, $idPackage);
            $data['messages'][] = self::setSchedulingFlagForCustomer($idOrder, $idPackage, 0);

            return $data;
        }

        /*if($user->getUserType() !== USER_TYPES['BROKER']) {
            $sql = "SELECT rope.idProduct,
                           rope.estimatedDate,
                           rope.confirmedDate,
                           s.id AS idSupplier
                    FROM ".TABLES['rel_order_products_estimation']." rope
                    INNER JOIN ".TABLES['suppliers_countries_products']." scp
                        ON scp.idProduct=rope.idProduct
                    INNER JOIN ".TABLES['suppliers']." s
                        ON s.id=scp.idSupplier
                    WHERE idOrder=$idOrder
                        $whereSql
                        AND scp.idProductCategory!=".self::ID_INSTALLATION_CATEGORY."
                    ORDER BY s.id,
                        scp.productName";
            $query = $database->query($sql);
            while($row = $database->fetchArray($query)){
                if(!$row['estimatedDate'] || !$row['confirmedDate']) {
                    return $data;
                }
            }
        }*/

        $sql = "SELECT
                  p.additionalInstallDays,
                  p.id AS idPackage,
                  c.code AS countryCode
                FROM
                  ".TABLES['packages']." p
               INNER JOIN ".TABLES['countries']." c
                    ON c.id = p.idCountry
                INNER JOIN ".TABLES['rel_order_packages']." rop
                    ON rop.idPackage=p.id
                WHERE rop.idOrder=$idOrder $whereSql";
        $query = $database->query($sql);
        $rowsAffected = 0;

        while($row = $database->fetchArray($query)){
            $additionalDays = intval($row['additionalInstallDays']);
            $interval = 'P'.$additionalDays.'D';
            $packageMaxDeliveryDate = new DateTime($maxDeliveryDate);
            $packageMaxDeliveryDate->add(new DateInterval($interval));
            $earliestInstallationDate = $packageMaxDeliveryDate->format('Y-m-d');
            $sql = "
                    UPDATE ".TABLES['rel_order_packages']."
                    SET
                        earliestInstallationDate = '$earliestInstallationDate'
                    WHERE idOrder = $idOrder AND idPackage=".$row['idPackage'];
            $result = $database->query($sql);
            $rowsAffected += $database->affectedRows();
            if($rowsAffected > 0) {
                $data = self::checkIfInstallationDateIsValid($idOrder, $row['idPackage'], $earliestInstallationDate);
                $data['idOrder'] = $idOrder;
                $data['idPackage'] = $row['idPackage'];
                if(array_key_exists('messages', $data)) {
                    $data['callConfirmationInstallationDatesFct'] = true;
                }
                $data['messages'][] = self::sendMailIfSchedulingEnabledForCustomer($idOrder, $row['idPackage']);
            }
        }

        return $data;
    }

    /**
     * verifies if the installation dates are still valid after changing the earliest installation date
     * @param  Int  $idOrder                     id of the order
     * @param  Int  $idPackage                   id of the package
     * @param  String $earliestInstallationDate  empty if not passed or the earliest installation date set
     * @return Array                             array with update messages
     */
    public function checkIfInstallationDateIsValid($idOrder, $idPackage, $earliestInstallationDate = '') {
        global $database;
        $idOrder = $database->escapeValue($idOrder);
        $idPackage = $database->escapeValue($idPackage);
        $earliestInstallationDate = $database->escapeValue($earliestInstallationDate);
        $invalidDates = [];
        $revalidDates = [];
        $acceptedDate = '';
        $data = [];

        if(!$earliestInstallationDate) {
            $earliestInstallationDate = self::getInstallationScheduleEID($idOrder, $idPackage);
        }

        $installationDates = $this->getInstallationDates($idOrder, $idPackage);
        foreach ($installationDates as $installDate => $details) {
            if($installDate < $earliestInstallationDate && $details['lastStatus'] !== 'invalid') {
                array_push($invalidDates, $installDate);
                if($details['lastStatus'] === 'accepted') {
                    $acceptedDate = $installDate;
                }
            } else if($installDate > $earliestInstallationDate && $details['lastStatus'] === 'invalid') {
                array_push($revalidDates, $installDate);
            }
        }

        if(count($invalidDates)) {
            if($message = $this->changeInstallationDatesStatus($idOrder, $idPackage, $invalidDates, 'invalid')) {
                $data['messages'][] = $message;
            }
            if($acceptedDate) {
                $mailDetails = [
                    'idOrder' => $idOrder,
                    'acceptedDate' => $acceptedDate
                ];
                $mailTitle = 'Installation date not valid anymore';
                $templateUrl = 'installationDateInvalidTemplate.php';
                $data['messages'][] = self::sendInstallationSchedulingMail($mailDetails, $mailTitle, $templateUrl);
            }
        }

        if(count($revalidDates)) {
            if($message = $this->changeInstallationDatesStatus($idOrder, $idPackage, $revalidDates, 'proposed')) {
                $data['messages'][] = $message;
            }
        }

        return $data;
    }

    /**
     * changes the installation dates statuses if the earliest installation date has changed
     * @param  Int $idOrder      id of the order
     * @param  Int $idPackage    id of the package
     * @param  Array $dates      array with the dates that need a status change
     * @param  String $status    the future status for the selected installation dates
     * @return Array             update messages
     */
    private function changeInstallationDatesStatus($idOrder, $idPackage, $dates, $status) {
        global $database, $user;
        $extraWhere = '';
        if($idPackage) {
            $extraWhere = " AND idPackage=$idPackage";
        }

        if(count($dates)) {
            $statusUpdated = 0;
            foreach($dates as $installationDate) {
                $sql = "INSERT INTO ".TABLES['installation_schedule_dates']." (
                          idCompanySelection,
                          idUser,
                          date,
                          status
                        )
                        (SELECT
                          id,
                          ".$user->getUserId().",
                          '".$installationDate."',
                          '".$status."'
                        FROM
                          ".TABLES['installation_company_selections']."
                        WHERE idOrder = $idOrder
                          $extraWhere)";
                $query = $database->query($sql);
                $statusUpdated += $database->affectedRows();
            }
            if(count($dates) === $statusUpdated) {
                return [
                    'code' => 'success',
                    'message' => 'INSTALLATION_DATES_STATUS_CHANGED'
                ];
            }
        }

        return;
    }

    /**
     * returns the earliest installation date based on the maximum delivery date plus the additional days
     * @param  Int $idOrder             the id of the order
     * @param  Int $idPackage           the id of the package
     * @return Array                    the earliest installation date or error message
     */
    public function getEarliestInstallationDate($idOrder, $idPackage) {
        global $database;
        $idOrder = $database->escapeValue($idOrder);
        $idPackage = $database->escapeValue($idPackage);
        $data = [];

        $earliestInstallationDate = self::getInstallationScheduleEID($idOrder, $idPackage);

        $data = [
            'earliestInstallationDate' => $earliestInstallationDate,
            'idOrder' => $idOrder,
            'idPackage' => $idPackage
        ];

        return $data;
    }

    /**
     * returns an update message
     * @param  Int $idOrder             the id of the order
     * @param  Int $idPackage           the id of the package
     * @return Array                    update messages
     */
    private function removeInstallationDates($idOrder, $idPackage) {
        global $database;
        $idOrder = $database->escapeValue($idOrder);
        $idPackage = $database->escapeValue($idPackage);
        $whereSql = $idPackage != 0 ? "AND idPackage = $idPackage" : "";
        $data = [];

        $sql = "
                DELETE
                  isd
                FROM
                  ".TABLES['installation_schedule_dates']." isd
                  INNER JOIN ".TABLES['installation_company_selections']." ics
                    ON isd.idCompanySelection = ics.id
                    AND idOrder = $idOrder
                    $whereSql
                    AND isActive = 1";
        $query = $database->query($sql);

        if($database->affectedRows()) {
            $data['messages'][] = [
                'code' => 'success',
                'message' => 'INSTALLATION_DATES_REMOVED'
            ];
        }

        return $data;
    }

    /**
     * get installation dates for each package in order
     * @param  INT $idOrder       id for the order
     * @param  INT $idPackage     id for the package
     * @return Array                array of installation dates
     */
    public function getInstallationDates($idOrder, $idPackage){
        global $database, $user;
        $data = [];
        $idOrder = $database->escapeValue($idOrder);
        $idPackage = $database->escapeValue($idPackage);
        $whereSql = $idPackage != 0 ? "AND ics.idPackage = $idPackage" : "";

        $sql = "
                SELECT
                  isd.date,
                  isd.status,
                  isd.idUser,
                  isd.currentDate,
                  u.username,
                  ut.type AS userType
                FROM
                  ".TABLES['installation_schedule_dates']." isd
                  INNER JOIN ".TABLES['installation_company_selections']." ics
                    ON isd.idCompanySelection = ics.id
                  INNER JOIN ".TABLES['users']." u
                    ON u.id = isd.idUser
                  INNER JOIN ".TABLES['rel_user_type']." rut
                    ON rut.idUser = u.id
                  INNER JOIN ".TABLES['user_types']." ut
                    ON ut.id = rut.idType
                WHERE ics.idOrder = $idOrder $whereSql AND ics.isActive = 1
                ORDER BY isd.date, isd.currentDate
        ";

        $result = $database->query($sql);
        while($row = $database->fetchArray($result)) {
            $data[$row['date']]['isProposedByMe'] = intval($row['idUser']) === intval($user->getUserId());
            unset($row['idUser']);
            $data[$row['date']]['details'][] = $row;
            $data[$row['date']]['lastStatus'] = $row['status'];
        }

        return $data;
    }

    /**
     * Update the estimation date for the installation
     * @param  Int $idOrder        Id of the order to be modified
     * @param  Int $idPackage      id of the package to be modified
     * @param  String $newDate     the date set by the user for the installation
     * @param  String $status      the status of the date to be added
     * @return array                 response message for the update
     */
    public function updateInstallationDate($idOrder, $idPackage, $newDate, $status) {
        global $database, $user;
        $idOrder = $database->escapeValue($idOrder);
        $idPackage = $database->escapeValue($idPackage);
        $newDate = $database->escapeValue($newDate);
        $status = $database->escapeValue($status);
        $data = [];
        $userType = $user->getUserType();
        $mailTitle = '';
        $templateUrl = '';

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

            return $data;
        }
        $checkDate = $database->invalidDate('INVALID_DATE_ESTIMATED', $newDate);
        if($checkDate){
            $data['messages'][] = $checkDate;

            return $data;
        }
        if(!$status) {
            $data['messages'][] = [
                'code' => 'error',
                'message' => 'STATUS_NOT_SET'
            ];

            return $data;
        }

        $earliestInstallationDate = self::getInstallationScheduleEID($idOrder, $idPackage);
        if(!$earliestInstallationDate) {
            $data['messages'][] = [
                'code' => 'error',
                'message' => 'EID_NOT_SET'
            ];

            return $data;
        }

        $idCompanySelection = $this->getActiveInstallationCompanyId($idOrder, $idPackage);
        if(!$idCompanySelection) {
            $data['messages'][] = [
                'code' => 'error',
                'message' => 'RELATION_NOT_FOUND'
            ];

            return $data;
        }

        if($userType === USER_TYPES['CUSTOMER']) {
            $brokerMails = (array) UtilsModel::getBrokersMail();
            $supplierMail = (array) $this->getSupplierMail($idCompanySelection);
            $mail = array_merge($brokerMails, $supplierMail);
        } else if($userType === USER_TYPES['SUPPLIER']){
            $mail = self::getCustomerMail($idOrder);
        } else {
            $customerMail = (array) self::getCustomerMail($idOrder);
            $supplierMail = (array) self::getSupplierMail($idCompanySelection);
            $mail = array_merge($customerMail, $supplierMail);
        }

        $mailDetails = [
            'idOrder' => $idOrder,
            'idCompanySelection' => $idCompanySelection,
            'orderNumber' => UtilsModel::getOrderNumberById($idOrder),
            'acceptedDate' => $newDate,
            'proposedDate' => $newDate,
            'actionDoneBy' => $user->getUserFullName(),
            'mail' => $mail
        ];

        if($status === 'proposed') {
            $mailTitle = 'New installation date proposed';
            $templateUrl = 'installationProposedTemplate.php';
            if($newDate < $earliestInstallationDate) {
                $data['messages'][] = [
                    'code' => 'error',
                    'message' => 'PAST_DATE',
                    'key' => $earliestInstallationDate
                ];

                return $data;
            }

            $sql = "
                    SELECT id
                        FROM ".TABLES['installation_schedule_dates']."
                    WHERE idCompanySelection = $idCompanySelection
                        AND date='$newDate' AND status='proposed'";
            $result = $database->query($sql);
            if($database->numRows($result) === 1) {
                $data['messages'][] = [
                    'code' => 'error',
                    'message' => 'PROPOSED_DATE_EXISTS'
                ];

                return $data;
            }

            if($userType === USER_TYPES['BROKER']) {
                $earliestInstallationDate = new DateTime($earliestInstallationDate);
                $maxSLAInstallDate = $earliestInstallationDate->add(new DateInterval('P'.ADDITIONAL_MAX_INSTALL_DAYS.'D'));
                $maxSLAInstallDate = $maxSLAInstallDate->format('Y-m-d');
                if($maxSLAInstallDate < $newDate) {
                    $data['messages'][] = [
                        'code' => 'warning',
                        'message' => 'MAX_SLA_EXCEEDED',
                        'key' => $maxSLAInstallDate
                    ];
                }
            }
        }

        $lastStatuses = $this->getInstallationDateLastStatus($idCompanySelection);

        if($status === 'accepted') {
            $mailTitle = 'Installation date accepted';
            $templateUrl = 'installationAcceptedTemplate.php';
            $isinstallationAccepted = $this->installationDateIsAlreadyAccepted($lastStatuses, $newDate, $idCompanySelection);

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

            $sql = "UPDATE ".TABLES['orders']."
                    SET acceptanceDueDate=DATE_ADD('$newDate', INTERVAL ".self::CUSTOMER_ACCEPTANCE_DAYS_INTERVAL." DAY)
                    WHERE id=$idOrder";
            $query = $database->query($sql);
        }

        $database->beginTransaction();
        $sql = "
            INSERT INTO ".TABLES['installation_schedule_dates']." (
                idCompanySelection,
                idUser,
                date,
                status
                )
            VALUES(
                    $idCompanySelection,
                    ".$user->getUserId().",
                    '$newDate',
                    '$status'
            )";
        $query = $database->query($sql);
        if($query){
            $database->commit();
            $message = [
                'code' => 'success',
                'message' => 'INSTALLATION_DATE_UPDATED'
            ];
        }else{
            $database->rollback();
            $message = [
                'code' => 'error',
                'message' => 'SERVER_ERROR'
            ];
        }
        $data['messages'][] = $message;

        if($status === 'declined') {
            $confirmationDates = $this->getInstallationDates($idOrder, $idPackage);

            if($confirmationDates) {
                if(count($confirmationDates) > 0) {
                   $allDatesDeclined = true;

                   forEach($confirmationDates as $date => $details) {
                       if($details['lastStatus'] !== 'declined') {
                           $allDatesDeclined = false;
                       }
                   }

                   if($allDatesDeclined) {
                       $mailTitle = 'Installation dates declined';
                       $templateUrl = 'installationDeclinedTemplate.php';
                   }
               }
           }
        }

        if($mailTitle && $templateUrl) {
            $data['messages'][] = self::sendInstallationSchedulingMail($mailDetails, $mailTitle, $templateUrl);
        }

        return $data;
    }

    /**
     * returns the id of the installation company active for order and package
     * @param  Int $idOrder   id of the order
     * @param  Int $idPackage id of the package
     * @return Int            id of the relation
     */
    private function getActiveInstallationCompanyId($idOrder, $idPackage) {
        global $database;

        $sql = "
            SELECT
              ics.id AS selectionId
            FROM
              ".TABLES['installation_company_selections']." ics
            WHERE ics.idOrder = $idOrder AND ics.idPackage = $idPackage AND ics.isActive = 1";
        $data = $database->fetchResultArray($sql);

        if($data && $data[0]['selectionId']) {
            return $data[0]['selectionId'];
        }

        return 0;
    }

    /**
     * checks if an installation date is already accepted, and puts it in canceled state if so
     * @param  Array $lastStatuses        the last status for each date
     * @param  String $newDate            the date to be updated
     * @param  Int $idCompanySelected     id of the installation company selected
     * @return Boolean                    true or false if the installation date is accepted for the order package
     */
    private function installationDateIsAlreadyAccepted($lastStatuses, $newDate, $idCompanySelected) {
        global $database, $user;
        $dateCanceled = 0;

        foreach($lastStatuses as $installationDate => $lastStatus) {
            if($installationDate !== $newDate && $lastStatus === 'accepted') {
                $sql = "INSERT INTO ".TABLES['installation_schedule_dates']."
                        (idCompanySelection, idUser, date, status)
                        VALUES (
                            $idCompanySelected,
                            ".$user->getUserId().",
                            '$installationDate',
                            'canceled'
                            )
                ";
                $result = $database->query($sql);

                if($database->affectedRows()) {
                    $dateCanceled++;
                }
            }
        }

        return false;
    }

    /**
     * checks if there is at least one already accepted installation date
     * @param  Int $idOrder         the id of the order
     * @param  Int $idPackage       the id of the package
     * @return Boolean              true or false if the installation has an already accepted date
     */
    public function checkIfDateAlreadyAccepted($idOrder, $idPackage) {
        global $database;

        $idCompanySelection = $this->getActiveInstallationCompanyId($idOrder, $idPackage);
        $installationDateLastStatuses = $this->getInstallationDateLastStatus($idCompanySelection);

        foreach($installationDateLastStatuses as $status) {
            if($status === 'accepted') {
                return true;
            }
        }

        return false;
    }

    /**
     * remove the date from the order package
     * @param  Int $idOrder          id of the order
     * @param  Int $idPackage        id of the package
     * @param  String $installationDate the installation date to be removed
     * @return Array                  confirmation messages
     */
    public function removeMyDate($idOrder, $idPackage, $installationDate) {
        global $database;
        $idOrder = $database->escapeValue($idOrder);
        $idPackage = $database->escapeValue($idPackage);
        $installationDate = $database->escapeValue($installationDate);

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

            return $data;
        }

        $idCompanySelection = $this->getActiveInstallationCompanyId($idOrder, $idPackage);
        if(!$idCompanySelection) {
            $data['messages'][] = [
                'code' => 'error',
                'message' => 'RELATION_NOT_FOUND'
            ];

            return $data;
        }

        $lastStatus = $this->getInstallationDateLastStatus($idCompanySelection);
        if($lastStatus[$installationDate] !== 'proposed') {
            $data['messages'][] = [
                'code' => 'error',
                'message' => 'INSTALLATION_DATE_NOT_REMOVED'
            ];

            return $data;
        }

        $sql = "
                DELETE
                FROM
                  ".TABLES['installation_schedule_dates']."
                WHERE idCompanySelection = $idCompanySelection
                  AND date = '$installationDate'";

        $result = $database->query($sql);

        if($database->affectedRows() === 1) {
            $data['messages'][] = [
                'code' => 'success',
                'message' => 'INSTALLATION_DATE_REMOVED'
            ];
        } else {
            $data['messages'][] = [
                'code' => 'error',
                'message' => 'INSTALLATION_DATE_REMOVE_ERROR'
            ];
        }

        return $data;
    }

    /**
     * gets the lastest status of the earliest installation date for an order
     * @param  Int $idCompanySelected     the id of the insatllation company selected
     * @return String                     the latest status or empty string
     */
    private function getInstallationDateLastStatus($idCompanySelected) {
        global $database;
        $data = [];

        $sql = "
                SELECT
                  isd.date AS installationDate,
                  isd.status AS lastStatus
                FROM
                  ".TABLES['installation_schedule_dates']." isd
                  INNER JOIN
                    (SELECT
                      isdd.date AS installationDate,
                      MAX(isdd.currentDate) AS maxDate
                    FROM
                     ".TABLES['installation_schedule_dates']." isdd
                    WHERE isdd.idCompanySelection = $idCompanySelected
                    GROUP BY isdd.date) installations_max_dates
                    ON installations_max_dates.installationDate = isd.date
                    AND installations_max_dates.maxDate = isd.currentDate
                WHERE isd.idCompanySelection = $idCompanySelected
                ORDER BY isd.date";
        $query = $database->query($sql);
        while($row = $database->fetchArray($query)) {
            $data[$row['installationDate']] = $row['lastStatus'];
        }

        return $data;
    }

    /**
     * checks if the user logged is the owner of the product
     * @param  Int  $idProduct the id of the product
     * @return boolean            true if the user is the owner of the product
     */
    private function isProductOwner($idProduct){
        global $user, $database;

        if($user->getUserType() === USER_TYPES['BROKER']){
            return true;
        }else if($user->getUserType() === USER_TYPES['SUPPLIER']){
            $sql = "SELECT s.id
                    FROM ".TABLES['suppliers']." s
                    INNER JOIN ".TABLES['suppliers_countries_products']." scp
                    ON scp.idSupplier=s.id
                    WHERE s.idUser=".$user->getUserId();
            $query = $database->query($sql);

            return $database->numRows($query) > 0;
        }

        return false;
    }

    /**
     * change the installation company for the order and package selected
     * @param  Int $idOrder               id of the order
     * @param  Int $idPackage             id of the package
     * @param  Int $idInstallationCompany id of the installation company product
     * @return Array                      update messages
     */
    public function changeInstallationCompany($idOrder, $idPackage, $idInstallationCompany) {
        global $database;

        $idOrder = $database->escapeValue($idOrder);
        $idPackage = $database->escapeValue($idPackage);
        $idInstallationCompany = $database->escapeValue($idInstallationCompany);
        $rowsAffected = 0;

        $sqlSelectProduct = "
                SELECT
                  ics.id AS idCompany
                FROM
                  ".TABLES['installation_company_selections']." ics
                WHERE ics.idOrder = $idOrder AND ics.idPackage = $idPackage";

        $data = $database->fetchResultArray($sqlSelectProduct);
        if(count($data)) {
            $idScheduleInfo = $data[0]['idCompany'];
            $sqlUpdateCompanyStatus = "
                    UPDATE
                      ".TABLES['installation_company_selections']."
                    SET
                      isActive = 0
                    WHERE idOrder = $idOrder AND idPackage = $idPackage";
            $query = $database->query($sqlUpdateCompanyStatus);
        }

        $sqlInsertUpdateCompany = "
                INSERT INTO
                  ".TABLES['installation_company_selections']." (
                  idProduct,
                  idOrder,
                  idPackage
                )
                VALUES
                    ($idInstallationCompany, $idOrder, $idPackage)
                ON DUPLICATE KEY UPDATE
                    isActive = 1";
        $result = $database->query($sqlInsertUpdateCompany);
        $rowsAffected += $database->affectedRows();

        if($rowsAffected) {
            $data['messages'][] = [
                'code' => 'success',
                'message' => 'INSTALLATION_SAVED'
            ];

            $data['messages'][] = self::sendMailIfSchedulingEnabledForCustomer($idOrder, $idPackage);
        } else {
            $data['messages'][] = [
                'code' => 'error',
                'message' => 'INSTALLATION_NOT_SAVED'
            ];
        }

        return $data;
    }

    /**
     * returns the id of the installation info
     * @param  Int $idOrder   id of the order
     * @param  Int $idPackage id of the package
     * @return Array or Int   error messages or id of the package
     */
    public function getInstallationScheduleEID($idOrder, $idPackage) {
        global $database;
        $whereSql = $idPackage != 0 ? "AND idPackage = $idPackage" : "";
        $data = [];

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

            return $data;
        }

        $sql = "SELECT MAX(earliestInstallationDate) AS earliestInstallationDate
                FROM
                (SELECT
                  IFNULL(earliestInstallationDate, '-') AS earliestInstallationDate
                FROM
                  ".TABLES['rel_order_packages']."
                WHERE idOrder = $idOrder
                  $whereSql) eid
                ";
        $result = $database->fetchResultArray($sql);

        return $result && $result[0] ? $result[0]['earliestInstallationDate'] : '';
    }

    /**
     * send mail if scheduling is enabled for customer
     * @param  Int $idOrder      id of the order
     * @param  Int $idPackage    id of the package
     * @return Array
     */
    public function sendMailIfSchedulingEnabledForCustomer($idOrder, $idPackage) {
        global $database;
        $data = [];
        $idOrderPackagePair = $idOrder . '-' . $idPackage;
        $stepsName = json_encode([
            'firstStepEnabled' => 5,
            'lastStepEnabled' => 6
        ]);
        $orderExtraActions = new orderExtraActions();
        $installationScheduling = new InstallationScheduling();

        $isSchedulingAlreadyEnabled = self::checkIfSchedulingAlreadyEnabledForCustomer($idOrder, $idPackage);
        if(!intval($isSchedulingAlreadyEnabled)) {
            $installCompanySelected = $installationScheduling->getInstallCompaniesForPackage($idOrder, $idPackage)['selected'];
            $earliestInstallationDate = self::getInstallationScheduleEID($idOrder, $idPackage);
            $isNextStepWanted = $orderExtraActions->checkIfIsNextStepWanted($idOrder, $stepsName);

            if($installCompanySelected && count($installCompanySelected) > 0 &&
               $earliestInstallationDate &&
               $isNextStepWanted === false) {

               $message = self::setSchedulingFlagForCustomer($idOrder, $idPackage, 1);
               if($message['code'] === 'warning') {
                   return;
               }

               $customerInfo = UtilsModel::getDataForMailToCustomer($idOrder);

               $sqlPackageInfo = "
                                SELECT
                                    p.name AS packageName,
                                    s.name AS supplierName
                                FROM ".TABLES['packages']." p
                                INNER JOIN ".TABLES['rel_order_packages']." rop
                                    ON rop.idPackage = p.id
                                    AND rop.idOrder = $idOrder
                                    AND rop.idPackage = $idPackage
                                INNER JOIN ".TABLES['installation_company_selections']." ics
                                    ON ics.idOrder = rop.idOrder
                                INNER JOIN ".TABLES['suppliers_countries_products']." scp
                                    ON scp.idProduct = ics.idProduct
                                INNER JOIN ".TABLES['suppliers']." s
                                    ON s.id = scp.idSupplier";
               $query = $database->query($sqlPackageInfo);
               $packageInfo = $database->fetchArray($query);
               $params = [
                   'wiaas' => WIAAS_URL,
                   'ordersUrl' => WIAAS_URL.'/orders/'.$idOrder,
                   'orderNumber' => $customerInfo['orderNumber'],
                   'packageName' => $packageInfo['packageName'],
                   'supplierName' => $packageInfo['supplierName']
               ];
               $response = Mail::sendMail($customerInfo['mail'], 'Schedule installation function is now enabled', 'customerScheduleInstallationEnabled.php', $params);

               if($response){
                   $data = [
                       'code' => 'success',
                       'message' => 'SCHEDULING_ENABLED_MAIL'
                   ];
               } else {
                   $data = [
                       'code' => 'error',
                       'message' => 'ERROR_MAIL_SENT'
                   ];
               }
            }
        }

        return $data;
    }

    /**
     * check if the scheduling is already available for customer
     * @param  INT $idOrder    id of the order
     * @param  INT $idPackage  id of the package
     * @return Bool            1 if the scheduling is already enabled
     */
    public function checkIfSchedulingAlreadyEnabledForCustomer($idOrder, $idPackage) {
        global $database;
        $extraWhere = '';
        if($idPackage) {
            $extraWhere = " AND rop.idPackage = $idPackage";
        }

        $sql = "SELECT
                  rop.isSchedulingEnabledForCustomer
                FROM
                  ".TABLES['rel_order_packages']." rop
                WHERE rop.idOrder = $idOrder
                   $extraWhere";
        $result = $database->fetchResultArray($sql);

        return $result ? $result[0]['isSchedulingEnabledForCustomer'] : 0;
    }

    /**
     * sets the scheduling available or not available for customer
     * @param  INT $idOrder    id of the order
     * @param  INT $idPackage  id of the package
     * @return Bool            1 if the scheduling is already enabled
     */
    public function setSchedulingFlagForCustomer($idOrder, $idPackage, $flag) {
        global $database;
        $flag = intval($database->escapeValue($flag));
        $extraWhere = '';
        $message = [];

        if($flag !== 0 && $flag !== 1) {
            return [
                'code' => 'error',
                'message' => 'FLAG_NOT_AVAILABLE'
            ];
        }

        if($idPackage) {
            $extraWhere = " AND idPackage = $idPackage";
        }

        $sql = "UPDATE
                  ".TABLES['rel_order_packages']."
                SET
                  isSchedulingEnabledForCustomer = $flag
                WHERE idOrder = $idOrder
                  $extraWhere";

        $result = $database->query($sql);
        $affectedRows = $database->affectedRows();

        if($affectedRows > 0) {
            $message = [
                'code' => 'success',
                'key' => $flag ? 'enabled' : 'disabled',
                'message' => 'SCHEDULE_FLAG_UPDATED'
            ];
        }

        if($flag === 0) {
            $mailTitle = 'Installation scheduling is disabled';
            $templateUrl = 'installationSchedulingDisabled.php';
            $mailDetails = [
                'idOrder' => $idOrder
            ];
            $message = self::sendInstallationSchedulingMail($mailDetails, $mailTitle, $templateUrl);
        }

        return count($message) ? $message : [
            'code' => 'warning',
            'message' => 'SCHEDULE_FLAG_NO_UPDATE'
        ];
    }

    /**
     * send mail for installation scheduling functionality
     * @param  Array $info          array with all neccessary data about the order
     * @param  String $mailTitle    the title of the mail
     * @param  String $templateUrl the mail template to be sent
     * @return Array                update message
     */
    public function sendInstallationSchedulingMail($info, $mailTitle, $templateUrl) {
        global $user;
        $userType = $user->getUserType();
        $idOrder = array_key_exists('idOrder', $info) ? $info['idOrder'] : 0;
        $idCompanySelection = array_key_exists('idCompanySelection', $info) ? $info['idCompanySelection'] : 0;
        $orderNumber = array_key_exists('orderNumber', $info) ? $info['orderNumber'] : 0;
        $acceptedDate = array_key_exists('acceptedDate', $info) ? $info['acceptedDate'] : '';
        $proposedDate = array_key_exists('proposedDate', $info) ? $info['proposedDate'] : '';
        $actionDoneBy = array_key_exists('actionDoneBy', $info) ? $info['actionDoneBy'] : '-';

        if(!$idOrder) {
            return [
                'code' => 'error',
                'message' => 'ID_ORDER_NOT_SET'
            ];
        }

        if(!$orderNumber) {
            $orderNumber = UtilsModel::getOrderNumberById($idOrder);
        }

        if(array_key_exists('mail', $info)) {
            $mail = $info['mail'];
        } else {
            if($userType === USER_TYPES['CUSTOMER']) {
                $brokerMails = (array) UtilsModel::getBrokersMail();
                $supplierMail = (array) self::getSupplierMail($idCompanySelection);
                $mail = array_merge($brokerMails, $supplierMail);
            } else {
                $mail = self::getCustomerMail($idOrder);
            }
        }

        if($acceptedDate && $proposedDate) {
            $acceptedDate = new DateTime($acceptedDate);
            $acceptedDate = $acceptedDate->format('jS M, Y');
            $proposedDate = new DateTime($proposedDate);
            $proposedDate = $proposedDate->format('jS M, Y');
        }

        $params = [
            'wiaas' => $userType === USER_TYPES['CUSTOMER'] ? WIAAS_URL.'/api-wiaas' : WIAAS_URL,
            'ordersUrl' => $userType === USER_TYPES['CUSTOMER'] ? WIAAS_URL.'/api-wiaas/orders?subModule=orders_steps&idOrder='.$idOrder.'&orderNumber='.$orderNumber : WIAAS_URL.'/orders/'.$idOrder,
            'orderNumber' => $orderNumber,
            'acceptedDate' => $acceptedDate,
            'proposedDate' => $proposedDate,
            'actionDoneBy' => $actionDoneBy
        ];

        $response = Mail::sendMail($mail, $mailTitle, $templateUrl, $params);
        if($response){
            $message = [
                'code' => 'success',
                'message' => 'MAIL_SENT'
            ];
        } else {
            $message = [
                'code' => 'error',
                'message' => 'ERROR_MAIL_SENT'
            ];
        }

        return $message;
    }

    /**
     * return the mail of the supplier of the installation company
     * @param   Int     $idCompanySelection the id of the company selection (install company-order-package)
     * @return  Array   the email of the supplier for th installation company per order package
     */
    public function getSupplierMail($idCompanySelection) {
        global $database;

        $sql = "
                SELECT
                  u.mail
                FROM
                  ".TABLES['users']." u
                  INNER JOIN ".TABLES['suppliers']." s
                    ON s.idUser = u.id
                  INNER JOIN ".TABLES['suppliers_countries_products']." scp
                    ON scp.idSupplier = s.id
                  INNER JOIN ".TABLES['installation_company_selections']." ics
                    ON ics.idProduct = scp.idProduct
                    AND ics.id = $idCompanySelection";
        $mail = $database->fetchResultArray($sql);

        return count($mail) ? $mail[0]['mail'] : '';
    }

    /**
     * returns the customer mail for the order selected
     * @param  Int $idOrder  id of the order
     * @return Array
     */
    public function getCustomerMail($idOrder) {
        global $database;

        $sql = "
                SELECT
                  u.mail
                FROM
                  ".TABLES['users']." u
                  INNER JOIN ".TABLES['customers']." c
                    ON c.idUser = u.id
                  INNER JOIN ".TABLES['rel_commercial_lead_customers']." rclc
                    ON rclc.idCustomer = c.id
                  INNER JOIN ".TABLES['orders']." o
                    ON o.idCustomerInstance = rclc.id
                    AND o.id = $idOrder";
        $mail = $database->fetchResultArray($sql);

        return count($mail) ? $mail[0]['mail'] : '';
    }

 }
