<?php

class PacakgeOptionsManager{
    const PACKAGE_TYPES = [
        'ID_STANDARD_TYPE' => 1,
        'ID_OPTION_TYPE' => 2,
        'ID_ADDITIONAL_TYPE' => 3
    ];

    /**
     * get options bu group
     * @return ARRAY list of options
     */
    private function getGroupOptions($packagePrices){
        global $database;
        $data = [];

        $sql = "SELECT
                    rgo.idGroup,
                    rgo.idOptionPackage AS idPackage,
                    rgo.isDefault,
                    p.name AS packageName
                FROM ".TABLES['rel_group_options']." rgo
                INNER JOIN ".TABLES['packages']." p
                    ON p.id=rgo.idOptionPackage
                ORDER BY p.name ASC";
        $query = $database->query($sql);
        while($row = $database->fetchArray($query)){
            $row['prices'] = isset($packagePrices[$row['idPackage']]['broker']) ? $packagePrices[$row['idPackage']]['broker'] : [];
            $row['commercialLeadPrices'] = isset($packagePrices[$row['idPackage']]['commercial_lead']) ? $packagePrices[$row['idPackage']]['commercial_lead'] : [];
            $data[$row['idGroup']][] = $row;
        }

        return $data;
    }

    /**
     * get groups for packages
     * @return ARRAY list of option groups
     */
    private function getPackagesOptionGroups($packagePrices) {
        global $database;
        $data = [];
        $groupOptions = $this->getGroupOptions($packagePrices);

        $sql = "SELECT
                pog.id AS idGroup,
                pog.idPackage,
                pog.name AS groupName
                FROM ".TABLES['package_option_groups']." pog";
        $query = $database->query($sql);
        while($row = $database->fetchArray($query)){
            $idPackage = $row['idPackage'];
            $row['options'] = isset($groupOptions[$row['idGroup']]) ? $groupOptions[$row['idGroup']] : [];
            $data[$idPackage][] = $row;
        }

        return $data;
    }

    /**
     * get additional packages
     * @return ARRAY list of additional packages
     */
    private function getAdditionalPackages($packagePrices) {
        global $database;
        $data = [];

        $sql = "SELECT
                    rap.idAdditionalPackage AS idPackage,
                    rap.idPackage AS idParentPackage,
                    p.name AS packageName
                FROM ".TABLES['rel_additional_packages']." rap
                INNER JOIN ".TABLES['packages']." p
                ON p.id=rap.idAdditionalPackage
                ORDER BY p.name ASC";
        $query = $database->query($sql);
        while($row = $database->fetchArray($query)){
            $row['prices'] = isset($packagePrices[$row['idPackage']]['broker']) ? $packagePrices[$row['idPackage']]['broker'] : [];
            $row['commercialLeadPrices'] = isset($packagePrices[$row['idPackage']]['commercial_lead']) ? $packagePrices[$row['idPackage']]['commercial_lead'] : [];
            $data[$row['idParentPackage']][] = $row;
        }

        return $data;
    }

    private function getPackagePrices($onlyLinked) {
        global $database, $user;
        $extraJoin = "";
        $extraFields = "";
        $whereSql = "WHERE 1=1 ";
        $data = [];

        if($onlyLinked){
            $extraJoin = "INNER JOIN ".TABLES['packages']." p
                          ON plb.idPackage=p.id";
            $whereSql = " AND p.idPackageType IN(".self::PACKAGE_TYPES['ID_OPTION_TYPE'].", ".self::PACKAGE_TYPES['ID_ADDITIONAL_TYPE'].")";
        }

        if($user->getUserType() === USER_TYPES['COMMERCIAL_LEAD']){
            $extraJoin .= " LEFT OUTER JOIN
                            (
                                SELECT plcl.idPackage, plcl.idPaymentType
                                FROM ".TABLES['price_list_commercial_lead']." plcl
                                INNER JOIN ".TABLES['commercial_leads']." cl
                                ON cl.id=plcl.idCommercialLead
                                WHERE plcl.idCustomer IS NULL AND cl.idUser=".$user->getUserId()."
                            ) plcl
                            ON plcl.idPackage=plb.idPackage AND plcl.idPaymentType=plb.idPaymentType
                            ";
            $extraFields = 'plcl.idPaymentType AS clPaymentType,';
        }

        $sql = "SELECT
                    $extraFields
                    plb.idPackage,
                    plb.idPaymentType
                FROM ".TABLES['price_list_broker']." plb
                INNER JOIN ".TABLES['payment_types']." pt
                    ON pt.id=plb.idPaymentType
                $extraJoin
                $whereSql";
        $query = $database->query($sql);
        while($row = $database->fetchArray($query)){
            $data[$row['idPackage']]['broker'][] = $row['idPaymentType'];
            if(isset($row['clPaymentType'])){
                $data[$row['idPackage']]['commercial_lead'][] = $row['clPaymentType'];
            }
        }

        return $data;
    }

    /**
     * get all packages by package type
     * @return ARRAY list of packages
     */
    public function getOptionsAndPackages() {
        global $database;

        $data = [
            'standard' => [],
            'option' => [],
            'additional' => []
        ];
        $packageTypesIds = [
            'STANDARD' => 1,
            'OPTIONS' => 2,
            'ADDITIONALS' => 3
        ];
        $packagePrices = $this->getPackagePrices(false);
        $packageOptionGroups = $this->getPackagesOptionGroups($packagePrices);
        $additionalPackages = $this->getAdditionalPackages($packagePrices);

        $sql = "SELECT p.id AS idPackage,
                    p.name AS packageName,
                    pt.id AS idPackageType,
                    pt.packageType,
                    c.code AS countryCode
                FROM ".TABLES['packages']." p
                INNER JOIN ".TABLES['package_types']." pt
                    ON pt.id=p.idPackageType
                INNER JOIN ".TABLES['countries']." c
                    ON c.id=p.idCountry
                INNER JOIN (
                    SELECT
                        DISTINCT idPackage
                    FROM ".TABLES['price_list_broker']."
                ) plb
                ON plb.idPackage=p.id
                ORDER BY p.name ASC";
        $query = $database->query($sql);
        while($row = $database->fetchArray($query)){
            if(intval($row['idPackageType']) === $packageTypesIds['STANDARD']){
                $row['groups'] = isset($packageOptionGroups[$row['idPackage']]) ? $packageOptionGroups[$row['idPackage']] : [];
                $row['additionalPackages'] = isset($additionalPackages[$row['idPackage']]) ? $additionalPackages[$row['idPackage']] : [];
            }
            $row['prices'] = isset($packagePrices[$row['idPackage']]) ? $packagePrices[$row['idPackage']]['broker'] : [];
            $data[$row['packageType']][] = $row;
        }

        return $data;
    }

    /**
     * add new option group
     * @param INT $idPackage id for package
     * @param String $name      id for the option group
     * @return INT              inserted group id
     */
    private function addOptionGroup($idPackage, $name){
        global $database;

        $sql = "INSERT INTO ".TABLES['package_option_groups']."
                (idPackage, name)
                VALUES($idPackage, '$name')";
        $query = $database->query($sql);

        return $database->getInsertId();
    }

    /**
     * update options in a group
     * @param INT $idPackage id for the pacakge
     * @param ARRAY $group     list of options for a group
     * @return ARRAY           update message
     */
    private function addGroupOptions($idPackage, $group){
        global $database;
        $data = ['updated' => 0];

        $group->idGroup = $database->escapeValue($group->idGroup);
        $group->groupName = $database->escapeValue($group->groupName);
        if(!$group->groupName){
            $data['messages'][] = [
                'code' => 'error',
                'message' => 'INVALID_GROUP_NAME',
                'key' => $group->groupName
            ];

            return $data;
        }

        if(strpos($group->idGroup, 'new') !== false){
            $group->idGroup = $this->addOptionGroup($idPackage, $group->groupName);
        }

        if(empty($group->options)){
            $data['messages'][] = [
                'code' => 'error',
                'message' => 'INVALID_OPTIONS'
            ];

            return $data;
        }

        $optionsToNotDelete = [];
        $optionValues = "";

        foreach ($group->options as $option) {
            $optionValues .= "(".$group->idGroup.",".$option->idPackage.", ".$option->isDefault."),";
            $optionsToNotDelete[] = $option->idPackage;
        }
        $optionValues= rtrim($optionValues, ',');
        $sqlInsertOption = "INSERT INTO ".TABLES['rel_group_options']."
                            (idGroup, idOptionPackage, isDefault)
                            VALUES $optionValues
                            ON DUPLICATE KEY UPDATE
                            isDefault=VALUES(isDefault)";
        $query = $database->query($sqlInsertOption);
        $updated = $database->affectedRows();

        $optionsToNotDelete = implode(',', $optionsToNotDelete);
        $sqlDelete = "DELETE FROM ".TABLES['rel_group_options']."
                    WHERE idGroup=".$group->idGroup." AND idOptionPackage NOT IN(".$optionsToNotDelete.")";
        $query = $database->query($sqlDelete);
        $updated += $database->affectedRows();

        $data['updated'] = $updated;
        $data['updatedGroupId'] = $group->idGroup;

        return $data;
    }

    /**
     * update additional packages link
     * @param  INT $idPackage             id for package
     * @param  ARRAY $additionalPackages  list of additional packages
     * @return ARRAY                      update message
     */
    public function updateAdditionalForPackage($idPackage, $additionalPackages){
        global $database;
        $data = ['updated' => 0];

        $additionalsToNotDelete = [];
        $additonalValues = "";

        if(!empty($additionalPackages)){
            foreach ($additionalPackages as $additionaPackage) {
                $additionaPackage->idPackage = $database->escapeValue($additionaPackage->idPackage);
                $additonalValues .= "(".$idPackage.", ".$additionaPackage->idPackage."),";
                $additionalsToNotDelete[] = $additionaPackage->idPackage;
            }
            $additonalValues= rtrim($additonalValues, ',');

            $sqlInsertAdditional = "INSERT IGNORE INTO ".TABLES['rel_additional_packages']."
                                    (idPackage, idAdditionalPackage)
                                    VALUES $additonalValues";
            $query = $database->query($sqlInsertAdditional);
            $data['updated'] += $database->affectedRows();

            $additionalsToNotDelete = implode(',', $additionalsToNotDelete);
            $sqlDelete = "DELETE FROM ".TABLES['rel_additional_packages']."
                        WHERE idPackage=".$idPackage." AND idAdditionalPackage NOT IN(".$additionalsToNotDelete.")";
            $query = $database->query($sqlDelete);
            $data['updated'] += $database->affectedRows();
        }else{
            $sqlDelete = "DELETE FROM ".TABLES['rel_additional_packages']."
                        WHERE idPackage=".$idPackage."";
            $query = $database->query($sqlDelete);
            $data['updated'] += $database->affectedRows();
        }

        return $data;
    }

    /**
     * update package options and addiitonal packages
     * @param  INT $idPackage             id for the package for witch we do the link
     * @param  String $groups             list of groups to be linked
     * @param  String $additionalPackages list of additional packages to be linked
     * @return ARRAY                      update message
     */
    public function updatePackageOptions($idPackage, $groups, $additionalPackages){
        global $database;
        $data = ['messages' => []];
        $idPackage = $database->escapeValue($idPackage);
        $groups = json_decode($groups);
        $additionalPackages = json_decode($additionalPackages);

        $database->beginTransaction();
        $updated = 0;

        $updateMessage = $this->updateAdditionalForPackage($idPackage, $additionalPackages);
        $updated += $updateMessage['updated'];
        if(isset($updateMessage['messages'])){
            $data['messages'] = array_merge($data['messages'], $updateMessage['messages']);
        }

        $groupsToNotDelete = [];
        foreach ($groups as $group) {
            $updateMessage = $this->addGroupOptions($idPackage, $group);
            $updated += $updateMessage['updated'];
            if(isset($updateMessage['updatedGroupId'])){
                $groupsToNotDelete[] = $updateMessage['updatedGroupId'];
            }
            if(isset($updateMessage['messages'])){
                $data['messages'] = array_merge($data['messages'], $updateMessage['messages']);
            }
        }

        if(!empty($data['messages'])){
            $database->rollback();

            return $data;
        }

        if(!empty($groupsToNotDelete)){
            $groupsToNotDelete = implode(',', $groupsToNotDelete);
            $sqlDelete = "DELETE FROM ".TABLES['package_option_groups']."
                        WHERE idPackage=$idPackage AND id NOT IN($groupsToNotDelete)";
            $query = $database->query($sqlDelete);
            $updated += $database->affectedRows();
        }else{
            $sqlDelete = "DELETE FROM ".TABLES['package_option_groups']."
                        WHERE idPackage=$idPackage";
            $query = $database->query($sqlDelete);
            $updated += $database->affectedRows();
        }

        $database->commit();
        if($updated === 0){
            $data['messages'][] = [
                'code' => 'warning',
                'message' => 'NO_CHANGES'
            ];
        }else{
            $data['messages'][] = [
                'code' => 'success',
                'message' => 'OPTIONS_UPDATED'
            ];
        }


        return $data;
    }

    /**
     * get extra packages that are linked to standard pacakges
     * @return HashArray list of additional packages and option groups
     */
    public function getExtraLinkedPackages(){
        global $database;
        $data = [];

        $packagePrices = $this->getPackagePrices(true);
        $data['groups'] = $this->getPackagesOptionGroups($packagePrices);
        $data['additionalPackages'] = $this->getAdditionalPackages($packagePrices);

        return $data;
    }

}
