<?php

namespace ModulesGarden\Servers\ProxmoxVps\Packages\WhmcsService;

use ModulesGarden\Servers\ProxmoxVps\Core\HandlerError\Exceptions\Exception;
use ModulesGarden\Servers\ProxmoxVps\Core\HandlerError\ErrorCodes\ErrorCodesLib;
use ModulesGarden\Servers\ProxmoxVps\Core\Models\ProductSettings\Repository;
use ModulesGarden\Servers\ProxmoxVps\Core\Models\Whmcs\Currency;
use ModulesGarden\Servers\ProxmoxVps\Packages\WhmcsService\Config\Enum;
use ModulesGarden\Servers\ProxmoxVps\Core\Traits\AppParams;
use ModulesGarden\Servers\ProxmoxVps\Packages\WhmcsService\Traits\ConfigurableOptionsConfig;

use ModulesGarden\Servers\ProxmoxVps\Packages\WhmcsService\Traits\CustomFieldsConfig;
use WHMCS\Database\Capsule;

class Product
{
    use ConfigurableOptionsConfig;
    use CustomFieldsConfig;
    use AppParams;

    protected $productId = null;
    protected $product = null;

    protected $configOptions = null;

    protected $configurableOptionsGroupCreated = false;

    public function __construct($productId = null)
    {
        $this->setProductId($productId);

        $this->loadWhmcsService();
    }

    protected function setProductId($productId = null)
    {
        $relationId = (int)$productId;
        if ($relationId <= 0)
        {
            throw new Exception(ErrorCodesLib::CORE_WS_000002);
        }

        $this->productId = $relationId;
    }

    protected function loadWhmcsService()
    {
        $this->product = \WHMCS\Product\Product::find($this->productId);
    }

    public function loadConfigOptions($force = false)
    {
        if ($force || $this->configOptions === null)
        {
            $this->configOptions = Capsule::table('tblproductconfigoptions')
                ->leftJoin('tblproductconfiglinks', 'tblproductconfigoptions.gid', '=', 'tblproductconfiglinks.gid')
                ->join('tblproductconfiggroups', 'tblproductconfigoptions.gid', '=', 'tblproductconfiggroups.id')
                ->select('tblproductconfigoptions.id', 'tblproductconfigoptions.optionname', 'tblproductconfigoptions.gid')
                ->where('tblproductconfiglinks.pid', $this->productId)->get();
        }
    }

    public function doesConfigurableOptionExist($optionName = null)
    {
        if (!is_string($optionName) || trim($optionName) === '')
        {
            return false;
        }

        $this->loadConfigOptions();

        $rawOptionName = $this->configOptionNameToRaw($optionName);
        foreach ($this->configOptions as $option)
        {
            if ($rawOptionName === $this->configOptionNameToRaw($option->optionname))
            {
                return true;
            }
        }

        return false;
    }

    public function getOptionGroupId($optionName = null)
    {
        if (!is_string($optionName) || trim($optionName) === '')
        {
            return false;
        }

        $this->loadConfigOptions();

        $rawOptionName = $this->configOptionNameToRaw($optionName);
        foreach ($this->configOptions as $option)
        {
            if ($rawOptionName === $this->configOptionNameToRaw($option->optionname))
            {
                return $option->gid;
            }
        }

        return false;
    }

    public function getFirstOptionGroupId()
    {
        $this->loadConfigOptions();

        foreach ($this->configOptions as $option)
        {
            return $option->gid;
        }

        $optionGroup = Capsule::table('tblproductconfiggroups')
            ->join('tblproductconfiglinks', 'tblproductconfiglinks.gid', '=', 'tblproductconfiggroups.id')
            ->where('tblproductconfiglinks.pid', $this->productId)->first();

        if (is_object($optionGroup))
        {
            return $optionGroup->gid;
        }

        return false;
    }

    public function createConfigOptionsGroup()
    {
        $productName = $this->product->name;
        $moduleName = $this->getAppParam('name');

        $groupId = Capsule::table('tblproductconfiggroups')->insertGetId([
            'name' => 'Configurable options for ' . $productName . ' product',
            'description' => 'Auto generated by module ' . $moduleName
        ]);

        if (is_int($groupId) && $groupId > 0)
        {
            Capsule::table('tblproductconfiglinks')->insertGetId(['gid' => $groupId, 'pid' => $this->productId]);
        }

        $this->configurableOptionsGroupCreated = true;
    }

    public function configOptionNameToRaw($optionName)
    {
        if (!is_string($optionName) || trim($optionName) === '' || substr($optionName, 0, 1) === '|')
        {
            return '';
        }

        if (strpos($optionName, '|') > 0)
        {
            $parts = explode('|', $optionName);

            return $parts[0];
        }

        return $optionName;
    }

    public function addConfigurableOption($optionName = null)
    {
        if (!$this->canOptionBeAdded($optionName))
        {
            return;
        }

        $gid = $this->getConfigurableOptionGroupId();

        $this->createConfigurableOption($optionName, $gid);
    }

    public function createConfigurableOption($optionName, $gid)
    {
        foreach ($this->configOptionsList as $option)
        {
            if ($option[Enum::OPTION_NAME] === $optionName || $this->configOptionNameToRaw($option[Enum::OPTION_NAME]) === $optionName)
            {
                $optId = Capsule::table('tblproductconfigoptions')->insertGetId([
                    Enum::OPTION_GROUP_ID => $gid,
                    Enum::OPTION_NAME => $option[Enum::OPTION_NAME],
                    Enum::OPTION_TYPE => $option[Enum::OPTION_TYPE],
                    Enum::OPTION_QUANTITY_MIN => $option[Enum::OPTION_QUANTITY_MIN] ? $option[Enum::OPTION_QUANTITY_MIN] : Enum::OPTION_QUANTITY_MIN_DEFAULT,
                    Enum::OPTION_QUANTITY_MAX => $option[Enum::OPTION_QUANTITY_MAX] ? $option[Enum::OPTION_QUANTITY_MAX] : Enum::OPTION_QUANTITY_MAX_DEFAULT,
                    Enum::ORDER => $option[Enum::ORDER] ? $option[Enum::ORDER] : Enum::ORDER_DEFAULT,
                    Enum::HIDDEN => $option[Enum::HIDDEN] ? $option[Enum::HIDDEN] : Enum::HIDDEN_DEFAULT
                ]);

                if ($option[Enum::OPTION_TYPE] == Enum::OPTION_TYPE_QUANTITY && !$option[Enum::CONFIG_SUB_OPTIONS])
                {
                    $defaultConfig = Enum::DEFAULT_QUANTITY_SUB_CONFIG;

                    $this->createConfigurableSubOption($optId, $defaultConfig[Enum::OPTION_SUB_NAME],
                        $defaultConfig[Enum::OPTION_SUB_ORDER], $defaultConfig[Enum::OPTION_SUB_HIDDEN]);
                }

                foreach ($option[Enum::CONFIG_SUB_OPTIONS] as $subOption)
                {
                    $this->createConfigurableSubOption($optId, $subOption[Enum::OPTION_SUB_NAME],
                        $subOption[Enum::OPTION_SUB_ORDER], $subOption[Enum::OPTION_SUB_HIDDEN]);
                }

                foreach ($this->getCallbackSubOptions($optionName) as $subOption)
                {
                    $this->createConfigurableSubOption($optId, $subOption[Enum::OPTION_SUB_NAME],
                        $subOption[Enum::OPTION_SUB_ORDER], $subOption[Enum::OPTION_SUB_HIDDEN]);
                }

                break;
            }
        }
    }

    public function createConfigurableSubOption($optId = null, $optName = null, $sortOrder = 0, $hidden = 0)
    {
        if (!is_string($optName) || trim($optName) === '')
        {
            return;
        }

        $subId = Capsule::table('tblproductconfigoptionssub')->insertGetId([
            Enum::OPTION_SUB_OPTION_ID => (int)$optId,
            Enum::OPTION_SUB_NAME => $optName,
            Enum::OPTION_SUB_ORDER => (int)$sortOrder ? (int)$sortOrder : Enum::OPTION_SUB_ORDER_DEFAULT,
            Enum::OPTION_SUB_HIDDEN => (int)$hidden ? (int)$hidden : Enum::OPTION_SUB_HIDDEN_DEFAULT,
        ]);

        //add default pricing
        $this->insertDefaultConfigOptionPricing($subId);

        return $subId;
    }

    public function insertDefaultConfigOptionPricing($relId = null, $defaultPrice = '0.00')
    {

        $currencyIds = Currency::pluck("id")->all();
        if(empty( $currencyIds)|| !$relId)
        {
            return null;
        }

        foreach ( $currencyIds as $currencyId){
            Capsule::table('tblpricing')->insertGetId([ 'type' => 'configoptions', 'currency' => $currencyId,
                'relid' => $relId, 'msetupfee' => $defaultPrice, 'qsetupfee' => $defaultPrice, 'ssetupfee' => $defaultPrice,
                'asetupfee' => $defaultPrice, 'bsetupfee' => $defaultPrice, 'tsetupfee' => $defaultPrice, 'monthly' => $defaultPrice,
                'quarterly' => $defaultPrice, 'semiannually' => $defaultPrice, 'annually' => $defaultPrice,
                'biennially' => $defaultPrice, 'triennially' => $defaultPrice
            ]);
        }
    }

    public function getConfigurableOptionGroupId()
    {
        $gid = $this->getFirstOptionGroupId();
        if (!$gid)
        {
            $this->createConfigOptionsGroup();
            $this->loadConfigOptions(true);

            $gid = $this->getFirstOptionGroupId();
        }

        return $gid;
    }

    public function canOptionBeAdded($optionName = null)
    {
        if (!is_string($optionName) || trim($optionName) === '')
        {
            return false;
        }

        if ($this->doesConfigurableOptionExist($optionName))
        {
            return false;
        }

        $configOptionParams = $this->getConfigurableOptionConfigParams($optionName);
        if (!$configOptionParams)
        {
            return false;
        }

        return true;
    }

    public function getCallbackSubOptions($optionName = null)
    {
        if(!class_exists('\ModulesGarden\Servers\ProxmoxVps\App\Config\Packages\WhmcsService'))
        {
            return null;
        }

        $service = new \ModulesGarden\Servers\ProxmoxVps\App\Config\Packages\WhmcsService();
        if (method_exists($service, 'getSuboptionsByCallback') && is_callable([$service, 'getSuboptionsByCallback']))
        {
            return $service->getSuboptionsByCallback($optionName);
        }

        return null;
    }

    public function isConfigurableOptionsGroupCreated()
    {
        return $this->configurableOptionsGroupCreated;
    }

    public function getProductConfig()
    {
        $settingRepo = new Repository();

        $productSettings = $settingRepo->getProductSettings($this->productId);

        return $productSettings;
    }
}
