<?php


namespace ModulesGarden\ProxmoxAddon\App\Services\Cloud;


use MGProvision\Proxmox\v2\repository\FileRepository;
use ModulesGarden\ProxmoxAddon\App\Models\VirtualInterface;
use ModulesGarden\ProxmoxAddon\App\Models\VirtualNetwork;
use ModulesGarden\ProxmoxAddon\App\Models\VmIpAddress;
use ModulesGarden\ProxmoxAddon\App\Models\VmModel;
use ModulesGarden\ProxmoxAddon\App\Services\ApiService;
use ModulesGarden\ProxmoxAddon\App\Services\CloudService;
use ModulesGarden\ProxmoxAddon\App\Services\Utility;
use ModulesGarden\ProxmoxAddon\Core\UI\Traits\WhmcsParams;
use ModulesGarden\ProxmoxAddon\App\Enum\Cloud\ConfigurableOption;

class ResourceManager
{
    use WhmcsParams;
    use ProductService;
    use ApiService;

    protected $notVmIds = [];
    protected $vmIds=[];

    /**
     * @var Resource[]
     */
    protected $items = [];


    public function notVmIds(array $ids)
    {
        $this->notVmIds = $ids;
        return $this;
    }

    public function vmIds(array $ids)
    {
        $this->vmIds = $ids;
        return $this;
    }

    /**
     * @return Resource
     */
    public function sockets()
    {
        //cache
        if ($this->items[__FUNCTION__])
        {
            return $this->items[__FUNCTION__];
        }
        $resurce = new Resource(__FUNCTION__);
        $resurce->setUnit('int');
        if ($this->isWhmcsConfigOption(ConfigurableOption::SOCKETS))
        {
            $resurce->setTotal((int)$this->getWhmcsConfigOption(ConfigurableOption::SOCKETS));
        }
        else
        {
            $resurce->setTotal((int)$this->configuration()->getSockets());
        }
        $resurce->setMin($this->configuration()->serverSockets->min);
        $resurce->setMax($this->configuration()->serverSockets->max);
        $query = VmModel::ofHostingId($this->getWhmcsParamByKey('serviceid'));
        if ($this->notVmIds)
        {
            $query->notIdIn($this->notVmIds);
        }
        $resurce->setUsed($query->sum(__FUNCTION__));
        return $this->items[__FUNCTION__] = $resurce;
    }

    public function cores()
    {
        //cache
        if ($this->items[__FUNCTION__])
        {
            return $this->items[__FUNCTION__];
        }
        $resurce = new Resource(__FUNCTION__);
        $resurce->setUnit('int');
        if ($this->isWhmcsConfigOption(ConfigurableOption::CORES))
        {
            $resurce->setTotal((int)$this->getWhmcsConfigOption(ConfigurableOption::CORES));
        }
        else
        {
            $resurce->setTotal((int)$this->configuration()->getCores());
        }
        $resurce->setMin($this->configuration()->serverCores->min);
        $resurce->setMax($this->configuration()->serverCores->max);
        $query = VmModel::ofHostingId($this->getWhmcsParamByKey('serviceid'));
        if ($this->notVmIds)
        {
            $query->notIdIn($this->notVmIds);
        }
        $resurce->setUsed($query->sum(__FUNCTION__));
        return $this->items[__FUNCTION__] = $resurce;
    }

    public function vcpus()
    {
        //cache
        if ($this->items[__FUNCTION__])
        {
            return $this->items[__FUNCTION__];
        }
        $resurce = new Resource(__FUNCTION__);
        $resurce->setUnit('int');
        if ($this->isWhmcsConfigOption(ConfigurableOption::VCPUS))
        {
            $resurce->setTotal((int)$this->getWhmcsConfigOption(ConfigurableOption::VCPUS));
        }
        else
        {
            $resurce->setTotal((int)$this->configuration()->getVcpus());
        }
        $resurce->setMin($this->configuration()->serverVcpus->min);
        $resurce->setMax($this->configuration()->serverVcpus->max);
        $query = VmModel::ofHostingId($this->getWhmcsParamByKey('serviceid'));
        if ($this->notVmIds)
        {
            $query->notIdIn($this->notVmIds);
        }
        $resurce->setUsed($query->sum(__FUNCTION__));
        return $this->items[__FUNCTION__] = $resurce;
    }

    public function cpulimit()
    {
        //cache
        if ($this->items[__FUNCTION__])
        {
            return $this->items[__FUNCTION__];
        }
        $resurce = new Resource(__FUNCTION__);
        $resurce->setUnit('int');
        if ($this->isWhmcsConfigOption(ConfigurableOption::CPU_LIMIT))
        {
            $resurce->setTotal(round($this->getWhmcsConfigOption(ConfigurableOption::CPU_LIMIT),2));
        }
        else
        {
            $resurce->setTotal(round($this->configuration()->getCpulimit(),2));
        }
        $resurce->setMin($this->configuration()->serverCpulimit->min);
        $resurce->setMax($this->configuration()->serverCpulimit->max);
        $query = VmModel::ofHostingId($this->getWhmcsParamByKey('serviceid'));
        if ($this->notVmIds)
        {
            $query->notIdIn($this->notVmIds);
        }
        $resurce->setUsed($query->sum(__FUNCTION__));
        return $this->items[__FUNCTION__] = $resurce;
    }

    public function virtualNetworks()
    {
        //cache
        if ($this->items[__FUNCTION__])
        {
            return $this->items[__FUNCTION__];
        }
        $resurce = new Resource(__FUNCTION__);
        $resurce->setUnit('int');
        if ($this->isWhmcsConfigOption(ConfigurableOption::VIRTUAL_NETWORKS))
        {
            $resurce->setTotal((int)$this->getWhmcsConfigOption(ConfigurableOption::VIRTUAL_NETWORKS));
        }
        else
        {
            $resurce->setTotal((int)$this->configuration()->getVirtualNetworks());
        }
        $resurce->setMin(0);
        $resurce->setMax($resurce->getTotal());
        $query = VirtualNetwork::ofHostingId($this->getWhmcsParamByKey('serviceid'));
        $resurce->setUsed($query->count());


        return $this->items[__FUNCTION__] = $resurce;
    }


    /**
     * @return Resource|Resource
     * @todo  singel query
     */
    public function disk()
    {
        //cache
        if ($this->items[__FUNCTION__])
        {
            return $this->items[__FUNCTION__];
        }
        $resurce = new Resource(__FUNCTION__);
        $resurce->setUnit("gb");
        if ($this->isWhmcsConfigOption(ConfigurableOption::STORAGE_DISK) && $this->getWhmcsConfigOption(ConfigurableOption::STORAGE_DISK)!="0"){
            list($storage,$disk) = explode(":", $this->getWhmcsConfigOption(ConfigurableOption::STORAGE_DISK),2);
            Utility::unitFormat($disk,$this->configuration()->getStorageUnit(),"gb");
            $resurce->setTotal((int)$disk);

        }
        elseif ($this->isWhmcsConfigOption(ConfigurableOption::STORAGE))
        {
            $disk = (int)$this->getWhmcsConfigOption(ConfigurableOption::STORAGE);
            Utility::unitFormat($disk,$this->configuration()->getStorageUnit(),"gb");
            $resurce->setTotal($disk);
        }
        else
        {
            $resurce->setTotal((int)$this->configuration()->getStorageSize());
        }
        $resurce->setMin((int)$this->configuration()->serverDiskSize->min);
        $resurce->setMax((int)$this->configuration()->serverDiskSize->max);
        $query  = VmModel::ofHostingId($this->getWhmcsParamByKey('serviceid'));
        $query2 = VmModel::ofHostingId($this->getWhmcsParamByKey('serviceid'));
        if ($this->notVmIds)
        {
            $query->notIdIn($this->notVmIds);
            $query2->notIdIn($this->notVmIds);
        }
        $resurce->setUsed($query->sum('disk') + $query2->sum('disks'));
        return $this->items[__FUNCTION__] = $resurce;
    }

    /**
     * @return Resource|Resource
     */
    public function memory()
    {
        //cache
        if ($this->items[__FUNCTION__])
        {
            return $this->items[__FUNCTION__];
        }
        $resurce = new Resource(__FUNCTION__);
        $resurce->setUnit("mb");
        if ($this->isWhmcsConfigOption(ConfigurableOption::MEMORY))
        {
            $resurce->setUnit($this->configuration()->getMemoryUnit());
            $total = (int)$this->getWhmcsConfigOption(ConfigurableOption::MEMORY);
            Utility::unitFormat($total,$this->configuration()->getMemoryUnit(),"mb");
            $resurce->setTotal($total);
        }
        else
        {
            $resurce->setTotal((int)$this->configuration()->getMemory());
        }
        $resurce->setMin($this->configuration()->serverMemory->min);
        $resurce->setMax($this->configuration()->serverMemory->max);
        $query = VmModel::ofHostingId($this->getWhmcsParamByKey('serviceid'));
        if ($this->notVmIds)
        {
            $query->notIdIn($this->notVmIds);
        }
        $resurce->setUsed($query->sum(__FUNCTION__));
        return $this->items[__FUNCTION__] = $resurce;
    }

    /**
     * @return Resource|Resource
     */
    public function swap()
    {
        //cache
        if ($this->items[__FUNCTION__])
        {
            return $this->items[__FUNCTION__];
        }
        $resurce = new Resource(__FUNCTION__);
        $resurce->setUnit("mb");
        if ($this->isWhmcsConfigOption(ConfigurableOption::SWAP))
        {
            $resurce->setUnit($this->configuration()->getSwapUnit());
            $resurce->setTotal((int)$this->getWhmcsConfigOption(ConfigurableOption::SWAP));
        }
        else
        {
            $resurce->setTotal((int)$this->configuration()->getSwap());
        }
        $resurce->setMin($this->configuration()->serverSwap->min);
        $resurce->setMax($this->configuration()->serverSwap->max);
        $query = VmModel::ofHostingId($this->getWhmcsParamByKey('serviceid'));
        if ($this->notVmIds)
        {
            $query->notIdIn($this->notVmIds);
        }
        $resurce->setUsed($query->sum(__FUNCTION__));
        return $this->items[__FUNCTION__] = $resurce;
    }

    public function cpuunits()
    {
        //cache
        if ($this->items[__FUNCTION__])
        {
            return $this->items[__FUNCTION__];
        }
        $resurce = new Resource(__FUNCTION__);
        $resurce->setUnit("int");
        if ($this->isWhmcsConfigOption(ConfigurableOption::CPU_UNITS))
        {
            $resurce->setTotal((int)$this->getWhmcsConfigOption(ConfigurableOption::CPU_UNITS));
        }
        else
        {
            $resurce->setTotal((int)$this->configuration()->getCpuunits());
        }
        $resurce->setMin($this->configuration()->serverCpuunit->min);
        $resurce->setMax($this->configuration()->serverCpuunit->max);
        $query = VmModel::ofHostingId($this->getWhmcsParamByKey('serviceid'));
        if ($this->notVmIds)
        {
            $query->notIdIn($this->notVmIds);
        }
        $resurce->setUsed($query->sum(__FUNCTION__));
        return $this->items[__FUNCTION__] = $resurce;
    }

    public function ipv4()
    {
        //cache
        if ($this->items[__FUNCTION__])
        {
            return $this->items[__FUNCTION__];
        }
        $resurce = new Resource(__FUNCTION__);
        $resurce->setUnit("int");
        if ($this->isWhmcsConfigOption(ConfigurableOption::IPV4))
        {
            $resurce->setTotal((int)$this->getWhmcsConfigOption(ConfigurableOption::IPV4));
        }
        else
        {
            $resurce->setTotal((int)$this->configuration()->getIpv4());
        }
        $resurce->setMin($this->configuration()->serverIpv4->min);
        $resurce->setMax($this->configuration()->serverIpv4->max);
        $query = VmIpAddress::ofHostingId($this->getWhmcsParamByKey('serviceid'));
        $query->ofIp4();
        if ($this->notVmIds)
        {
            $query->notIdIn($this->notVmIds);
        }
        $resurce->setUsed($query->count());
        return $this->items[__FUNCTION__] = $resurce;
    }

    public function ipv6()
    {
        //cache
        if ($this->items[__FUNCTION__])
        {
            return $this->items[__FUNCTION__];
        }
        $resurce = new Resource(__FUNCTION__);
        $resurce->setUnit("int");
        if ($this->isWhmcsConfigOption(ConfigurableOption::IPV6))
        {
            $resurce->setTotal((int)$this->getWhmcsConfigOption(ConfigurableOption::IPV6));
        }
        else
        {
            $resurce->setTotal((int)$this->configuration()->getIpv6());
        }
        $resurce->setMin($this->configuration()->serverIpv6->min);
        $resurce->setMax($this->configuration()->serverIpv6->max);
        $query = VmIpAddress::ofHostingId($this->getWhmcsParamByKey('serviceid'));
        $query->ofIp6();
        if ($this->notVmIds)
        {
            $query->notIdIn($this->notVmIds);
        }
        $resurce->setUsed($query->count());
        return $this->items[__FUNCTION__] = $resurce;
    }

    public function cpuPriority(){
        //cache
        if ($this->items[__FUNCTION__])
        {
            return $this->items[__FUNCTION__];
        }
        $resurce = new Resource(__FUNCTION__);
        $resurce->setUnit("int");
        $resurce->setMin(1);
        $resurce->setMax(5);
        $resurce->setTotal(5);

        for($i=1; $i<=5; $i++){
            $cpuunits = $this->configuration()->get('cpuunitsPriority'.$i);
            $cpulimit = round( $this->configuration()->get('cpulimitPriority'.$i),2);
            if($this->cpulimit()->freeTotal() < $cpulimit){
                $resurce->setUsed($i);
            }
            if($this->cpuunits()->freeTotal() < $cpuunits){
                $resurce->setUsed($i);
            }
        }
        return $this->items[__FUNCTION__] = $resurce;
    }

    public function virtualInterfaces()
    {
        //cache
        if ($this->items[__FUNCTION__])
        {
            return $this->items[__FUNCTION__];
        }
        $resurce = new Resource(__FUNCTION__);
        $resurce->setUnit('int');
        $resurce->setTotal((int)$this->configuration()->serverVirtualInterfaces->max);
        $resurce->setMin($this->configuration()->serverVirtualInterfaces->min);
        $resurce->setMax($this->configuration()->serverVirtualInterfaces->max);
        $query = VirtualInterface::ofHostingId($this->getWhmcsParamByKey('serviceid'))
            ->notPublic();
        if ($this->vmIds)
        {
            $query->ofVmIds($this->vmIds);
        }
        $resurce->setUsed($query->count());
        return $this->items[__FUNCTION__] = $resurce;
    }

    protected function backupFileRepository(){
        if(!is_null($this->backupFileRepository)){
            return $this->backupFileRepository;
        }
        $cloudService = new CloudService();
        $this->backupFileRepository = new FileRepository();
        $this->backupFileRepository->setApi($this->api());
        $this->backupFileRepository->findBackupByVmModel($cloudService->getVmModels())
            ->findByStorages([$this->configuration()->getBackupStorage()]);
        return $this->backupFileRepository;
    }
    /**
     * @return Resource|Resource
     */
    public function backupSize()
    {
        //cache
        if ($this->items[__FUNCTION__]) {
            return $this->items[__FUNCTION__];
        }
        $resurce = new Resource(__FUNCTION__);
        $resurce->setUnit("bytes");
        if ($this->isWhmcsConfigOption(ConfigurableOption::BACKUPS_SIZE)) {
            $total = (int)$this->getWhmcsConfigOption(ConfigurableOption::BACKUPS_SIZE);
        } else {
            $total = (int)$this->configuration()->getBackupMaxFiles();
        }
        if($total != -1){
            Utility::unitFormat($total,"gb","bytes");
        }
        $resurce->setTotal($total);
        $resurce->setMin(0);
        $resurce->setMax($total);
        //Backup repository
        $resurce->setUsed($this->backupFileRepository()->size());
        return $this->items[__FUNCTION__] = $resurce;
    }

    /**
     * @return Resource|Resource
     */
    public function backupFiles()
    {
        //cache
        if ($this->items[__FUNCTION__]) {
            return $this->items[__FUNCTION__];
        }
        $resurce = new Resource(__FUNCTION__);
        $resurce->setUnit("int");
        if ($this->isWhmcsConfigOption(ConfigurableOption::BACKUPS_FILES)) {
            $total = (int)$this->getWhmcsConfigOption(ConfigurableOption::BACKUPS_FILES);
        } else {
            $total = (int)$this->configuration()->getBackupMaxFiles();
        }
        $resurce->setTotal($total);
        $resurce->setMin(0);
        $resurce->setMax($total);
        //Backup repository
        $resurce->setUsed($this->backupFileRepository()->count());
        return $this->items[__FUNCTION__] = $resurce;
    }
}