<?php

namespace ModulesGarden\ProxmoxAddon\App\Listeners\Vps;

use Illuminate\Database\Capsule\Manager as DB;
use MGProvision\Proxmox\v2\Api;
use MGProvision\Proxmox\v2\models\Features;
use ModulesGarden\ProxmoxAddon\App\Events\Vps\LxcUpdateEvent;
use ModulesGarden\ProxmoxAddon\App\Events\Vps\QemuUpdateEvent;
use ModulesGarden\ProxmoxAddon\App\Services\ApiService;
use ModulesGarden\ProxmoxAddon\App\Services\Utility;
use ModulesGarden\ProxmoxAddon\App\Services\Vps\AdditionalMountPointService;
use ModulesGarden\ProxmoxAddon\App\Services\Vps\ContainerService;
use ModulesGarden\ProxmoxAddon\App\Services\Vps\HostingService;
use ModulesGarden\ProxmoxAddon\App\Services\Vps\NetworkService;
use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
use ModulesGarden\ProxmoxAddon\App\Services\Vps\UserService;
use ModulesGarden\ProxmoxAddon\App\Enum\Vps\ConfigurableOption;
use ModulesGarden\ProxmoxAddon\Core\UI\Traits\WhmcsParams;

class LxcUpdateListener
{
    use WhmcsParams;
    use ApiService;
    use UserService;
    use ProductService;
    use HostingService;

    private $containerService;
    private $networkService;
    /**
     * @var AdditionalMountPointService
     */
    private $additionalMountPointService;
    /**
     * @var QemuUpdateEvent
     */
    private $event;

    /**
     * VmCreatedListener constructor.
     */
    public function __construct()
    {
        $this->containerService = new ContainerService();
        $this->networkService   = new NetworkService();
        $this->additionalMountPointService = new AdditionalMountPointService();
    }

    public function handle(LxcUpdateEvent $event)
    {
        $this->event   = $event;
        try
        {
            Api::beginTransaction();
            DB::beginTransaction();
            //Disk size
            $diskSize = $this->configuration()->getDiskSize();
            if($this->getWhmcsConfigOption(ConfigurableOption::STORAGE)){
                list($storage,$diskSize) = explode(":", $this->getWhmcsConfigOption(ConfigurableOption::STORAGE),2);
                Utility::unitFormat($diskSize, $this->configuration()->getDiskUnit(), 'gb');

            }
            elseif ($this->isWhmcsConfigOption(ConfigurableOption::DISK_SIZE))
            {
                $diskSize = $this->getWhmcsConfigOption(ConfigurableOption::DISK_SIZE);
                Utility::unitFormat($diskSize, $this->configuration()->getDiskUnit(), 'gb');
            }
            $masterHardDiskSize = $this->vm()->getMasterHddSize();
            if ($diskSize && $diskSize - $masterHardDiskSize > 0)
            {
                $disk = ['disk' => "rootfs", 'size' => sprintf('+%sG', $diskSize - $masterHardDiskSize)];
                $this->vm()->resize($disk);
            }
            //Move disk

            //init container
            $container = [];
            //hostname
            if ($hostname = $this->containerService->hostname())
            {
                $container['hostname'] = $hostname;
            }
            //description
            if ($this->configuration()->getDescription())
            {
                $container['description'] = $this->containerService->description();
            }
            //Configurable Options
            if ($this->getWhmcsConfigOption(ConfigurableOption::CPU_LIMIT, $this->configuration()->getCpulimit() ) )
            {
                $container['cpulimit'] = $this->getWhmcsConfigOption(ConfigurableOption::CPU_LIMIT, $this->configuration()->getCpulimit() );
            }
            //Memory
            $container['memory'] = $this->configuration()->getMemory();
            if ($this->isWhmcsConfigOption(ConfigurableOption::MEMORY))
            {
                $container['memory'] = $this->getWhmcsConfigOption(ConfigurableOption::MEMORY);
                Utility::unitFormat($container['memory'], $this->configuration()->getMemoryUnit(), 'mb');
            }
            //SWAP
            $container['swap'] = $this->configuration()->getSwap();
            if ($this->isWhmcsConfigOption(ConfigurableOption::SWAP))
            {
                $container['swap'] = $this->getWhmcsConfigOption(ConfigurableOption::SWAP);
                Utility::unitFormat($container['swap'], $this->configuration()->getSwapUnit(), 'mb');
            }
            //cpuunits
            $container['cpuunits'] = $this->getWhmcsConfigOption(ConfigurableOption::CPU_UNITS, $this->configuration()->getCpuunits()) ;
            //Name servers
            $ns = [];
            for ($i = 1; $i <= 2; $i++)
            {
                $n = trim($this->hosting()->{"ns{$i}"});
                if (!empty($n) && !filter_var($n, FILTER_VALIDATE_IP))
                {
                    $n = gethostbyname($n);
                }
                if (!empty($n) && filter_var($n, FILTER_VALIDATE_IP))
                {
                    $ns[] = $n;
                }
            }
            if ($ns)
            {
                $container['nameserver'] = implode(" ", $ns);
            }
            if ($this->vm()->isRunning() && $this->vm()->config()['nameserver'] == $container['nameserver'])
            {
                unset($container['nameserver']);
            }
            //cores
            if ($this->getWhmcsConfigOption(ConfigurableOption::CORES,$this->configuration()->getCores() ))
            {
                $container['cores'] = $this->getWhmcsConfigOption(ConfigurableOption::CORES,$this->configuration()->getCores() );
            }
            //arch
            if ($this->configuration()->getArch())
            {
                $container['arch'] = $this->configuration()->getArch();
            }
            //cmode
            if ($this->configuration()->getCmode() && !$this->vm()->isRunning())
            {
                $container['cmode'] = $this->configuration()->getCmode();
            }
            //console
            if ($this->configuration()->isConsole() && !$this->vm()->isRunning())
            {
                $container['console'] = 1;
            }
            //description
            if ($this->configuration()->getDescription())
            {
                $container['description'] = $this->containerService->description();
            }
            //onboot
            if ($this->configuration()->isOnboot())
            {
                $container['onboot'] = 1;
            }
            //protection
            if ($this->configuration()->isProtection())
            {
                $container['protection'] = 1;
            }
            //startup
            if ($this->configuration()->getStartup())
            {
                $container['startup'] = $this->configuration()->getStartup();
            }
            //tty
            if ($this->configuration()->getTty() && !$this->vm()->isRunning())
            {
                $container['tty'] = $this->configuration()->getTty();
            }
            //Features
            $features = new Features();
            //Keyctl
            if($this->configuration()->isFeatureKeyctl() && $this->vm()->config()['unprivileged']){
                $features->setKeyctl(1);
            }
            //Nesting
            if($this->configuration()->isFeatureNesting() ){
                $features->setNesting(1);
            }
            //NFS
            if($this->configuration()->isFeatureNfs() ){
                $features->addNfs();
            }
            //CIFS
            if($this->configuration()->isFeatureCifs() ){
                $features->addCifs();
            }
            //Fuse
            if($this->configuration()->isFeatureFuse() ){
                $features->setFuse(1);
            }
            //Mknod
            if($this->configuration()->isFeatureMknod() ){
                $features->setMknod(1);
            }
            $container[Features::ID] = $features->asConfig();
            //Network create & update
            $container += $this->networkService->buildLxc();
            $container += $this->updateNetwork();
            //Update container
            $this->vm()->updateConfig($container);
            DB::commit();
            if($this->configuration()->isMountPoint() && $this->additionalMountPointService->hasMountPoint()){
                $this->additionalMountPointService->resize();
            }elseif ($this->configuration()->isMountPoint() && !$this->additionalMountPointService->hasMountPoint() ){
                $this->additionalMountPointService->create();
            }
        }
        catch (\Exception $ex)
        {
            echo $ex->getMessage();
            DB::rollBack();
            Api::commit();
            throw $ex;
        }

    }

    private function updateNetwork()
    {
        $container         = [];
        $updateNetworkRate = !$this->configuration()->getMinimumRate() || !$this->hosting()->isBandwidthOverageUsage();
        $rate      = null;
        if ($this->getWhmcsConfigOption(ConfigurableOption::NETWORK_RATE,$this->configuration()->getRate()) &&
            $this->getWhmcsConfigOption(ConfigurableOption::NETWORK_RATE,$this->configuration()->getRate())  != "-1")
        {
            $rate = $this->getWhmcsConfigOption(ConfigurableOption::NETWORK_RATE,$this->configuration()->getRate()) ;
        }
        foreach ($this->vm()->getNetworkDevices($this->configuration()->getBridge()) as $entity)
        {
            $hash = $entity->getHashCode();
            if ($updateNetworkRate && $entity->getRate() != $rate)
            {
                $entity->setRate($rate);
            }
            if ($hash != $entity->getHashCode())
            {
                $container[$entity->getId()] = $entity->asConfig();
            }
        }
        return $container;
    }


}