<?php

namespace ModulesGarden\Servers\OpenXchange\App\Service\ConfigurableOptions\Abstracts;

use Exception;
use ModulesGarden\Servers\OpenXchange\App\Service\ConfigurableOptions\Models\Option;
use ModulesGarden\Servers\OpenXchange\App\Service\ConfigurableOptions\Models\SubOption;
use ModulesGarden\Servers\OpenXchange\Core\Helper\Lang;
use ModulesGarden\Servers\OpenXchange\Core\Models\Whmcs\Currency;
use ModulesGarden\Servers\OpenXchange\Core\Models\Whmcs\Pricing;
use ModulesGarden\Servers\OpenXchange\Core\Models\Whmcs\Product;
use ModulesGarden\Servers\OpenXchange\Core\Models\Whmcs\ProductConfigGroups;
use ModulesGarden\Servers\OpenXchange\Core\Models\Whmcs\ProductConfigLinks;
use ModulesGarden\Servers\OpenXchange\Core\Models\Whmcs\ProductConfigOptions;
use ModulesGarden\Servers\OpenXchange\Core\Models\Whmcs\ProductConfigOptionsSub;

abstract class AbstractConfigurableOptions
{
    /*
     * @var integer $productID;
     */

    protected $productID;
    /*
     * @var integer $optionsGroupID;
     */
    protected $optionsGroupID;
    /*
     * @var array $options;
     */
    protected $options = [];

    /*
     * Set Product ID
     * 
     * @params integer $productID
     * @return void
     */

    public function __construct($porductID)
    {
        $this->productID = $porductID;
    }

    /*
     * Create and assign configurable options group
     * 
     * @return object $this;
     */


    /*
     * Get Product 
     * 
     * @return object \ModulesGarden\Servers\OpenXchange\Core\Models\Whmcs\Product
     * 
     */

    protected function getProduct()
    {
        return Product::where('id', $this->productID)->first();
    }

    protected function addGroup()
    {
        if (!$this->checkExistAssignedOptionsGroup())
        {
            $this->createOptionsGroup();
            $this->assignGroupToProduct();
            return true;
        }
    }

    /*
     * Check if configurable options exists
     * 
     * $params  integer $productId
     * @throw \Exception
     */

    public function checkExistAssignedOptionsGroup()
    {
        $check = ProductConfigLinks::where('pid', $this->productID)->first();
        if (!is_null($check))
        {
            $this->optionsGroupID = $check->gid;
            return true;
        }
    }

    /*
     * Prepare Options Array
     * 
     * 
     * @return array $fields
     */

    protected function showOptions()
    {
        $fields = [];
        foreach ($this->options as $option)
        {
            $fields[$option->getKey()] = $option->getName();
        }
        return $fields;
    }

    /*
     * Add options group
     *  
     *
     * @throw \Exception
     */

    protected function buildOptions()
    {
        if (is_array($this->options))
        {
            foreach ($this->options as $option)
            {
                $optionID = $this->createOptions($option);

                if (!empty($option->getSubOptions()) && !empty($optionID))
                {
                    $this->buildSubOptions($optionID, $option->getSubOptions());
                }
            }
        }
    }

    /*
     * Add suboptions to options group
     * 
     * @params integer $optionsID
     * @params object \ModulesGarden\Servers\OpenXchange\Core\Models\Whmcs\ProductConfigOptionsSub $sobOptions
     * @throw \Exception
     */

    protected function buildSubOptions($optionID, $subOptions)
    {
        if (is_array($subOptions))
        {
            foreach ($subOptions as $option)
            {
                $this->createSubOptions($optionID, $option);
            }
        }
    }

    /*
     * Create configurable options exist
     * 
     * @params string $key
     * @return mixed 
     * @throw \Exception
     */

    public function checkExistOption($key)
    {
        return ProductConfigOptions::where([
                    ['gid', $this->optionsGroupID],
                    ['optionname', 'LIKE', $key . '|%']
                ])->first();
    }

    /*
     * Create configurable options group
     * 
     * $params object \ModulesGarden\Servers\OpenXchange\Core\Models\Whmcs\Product $product
     * @throw \Exception
     */

    private function createOptionsGroup()
    {
        $product                   = $this->getProduct();
        $optionsGroup              = new ProductConfigGroups();
        $optionsGroup->name        = "Configurable options for " . $product->name . " product";
        $optionsGroup->description = "Auto generated by module " . $product->servertype;
        $optionsGroup->save();
        $this->optionsGroupID      = $optionsGroup->id;
    }

    /*
     * Assign Configurable Options Group to Product
     * 
     * $params object \ModulesGarden\Servers\OpenXchange\Core\Models\Whmcs\ProductConfigGroups $optionsGroup
     * @throw \Exception
     */

    private function assignGroupToProduct()
    {
        $assignProduct      = new ProductConfigLinks();
        $assignProduct->gid = $this->optionsGroupID;
        $assignProduct->pid = $this->productID;
        $assignProduct->save();
    }

    public function createOptions(Option $option)
    {
        if ($this->checkExistOption($option->getKey()))
        {
            return;
        }
        $model = new ProductConfigOptions($option->setGid($this->optionsGroupID)->toArray());
        $model->save();

        return $model->id;
    }

    /*
     * Create sub-options to configurable options
     * Function automatically create pricing for configurable options
     * 
     * $params  integer $optionID
     * @params object \ModulesGarden\Servers\OpenXchange\Core\Models\Whmcs\ProductConfigOptionsSub $sobOption
     * @throw \Exception
     */

    public function createSubOptions($optionID, SubOption $subOption)
    {
        $model = new ProductConfigOptionsSub($subOption->setConfigid($optionID)->toArray());
        $model->save();
        $this->createPricingForOptions($model->id);
    }

    /*
     * Get available currencies in WHMCS
     */

    private function getCurrencies()
    {
        $currencies = Currency::get();

        $allCurrencies = [];
        foreach ($currencies as $currency)
        {
            $allCurrencies[] = $currency->id;
        }
        return $allCurrencies;
    }

    /*
     * Get all currencies and create pricing for each one
     * 
     * @params integer $subOptionID
     */

    private function createPricingForOptions($subOptionID)
    {
        foreach ($this->getCurrencies() as $currency)
        {
            $this->addPricing($subOptionID, $currency);
        }
    }

    /*
     * Add pricing for sub-options
     * 
     * @params integer $subOptionID, $currencyID string $type
     * @throw \Exception
     */

    private function addPricing($subOptionID, $currencyID, $type = 'configoptions')
    {
        $pricing               = new Pricing();
        $pricing->type         = $type;
        $pricing->currency     = $currencyID;
        $pricing->relid        = $subOptionID;
        $pricing->msetupfee    = 0;
        $pricing->qsetupfee    = 0;
        $pricing->ssetupfee    = 0;
        $pricing->asetupfee    = 0;
        $pricing->bsetupfee    = 0;
        $pricing->tsetupfee    = 0;
        $pricing->monthly      = 0;
        $pricing->quarterly    = 0;
        $pricing->semiannually = 0;
        $pricing->annually     = 0;
        $pricing->biennially   = 0;
        $pricing->triennially  = 0;
        $pricing->save();
    }

}
