<?php


namespace ModulesGarden\ProxmoxAddon\App\Services\Cloud;


use MGProvision\Proxmox\v2\models\IpConfig;
use MGProvision\Proxmox\v2\models\Kvm;
use MGProvision\Proxmox\v2\models\Lxc;
use MGProvision\Proxmox\v2\models\NetworkDeviceKvm;
use MGProvision\Proxmox\v2\models\NetworkDeviceLxc;
use ModulesGarden\ProxmoxAddon\App\Enum\Cloud\ConfigurableOption;
use ModulesGarden\ProxmoxAddon\App\Models\VirtualInterface;
use ModulesGarden\ProxmoxAddon\App\Models\VmIpAddress;
use ModulesGarden\ProxmoxAddon\Core\UI\Traits\WhmcsParams;
use Illuminate\Database\Capsule\Manager as DB;

class VirtualInterfaceConverter
{
    use WhmcsParams;
    use ProductService;

    /**
     * @var Kvm|Lxc|null
     */
    protected $vm;


    /**
     * @var VirtualInterface[]
     */
    protected $virtualInterfaces;

    /**
     * @var NetworkDeviceKvm[]
     */
    protected $networkDevices;

    /**
     * @var IpConfig[]
     */
    protected $ipConfigs=[];

    /**
     * VirtualInterfaceConverter constructor.
     * @param Kvm|Lxc $vm
     * @param VirtualInterface[] $virtualInterfaces
     */
    public function __construct( $virtualInterfaces, $vm=null)
    {
        $this->vm = $vm;
        $this->virtualInterfaces = $virtualInterfaces;
    }

    public function convert(){
        $container=[];
        $rate      = $this->getRate();
        $networkId = $this->freeNetworDeviceId();
        foreach ($this->virtualInterfaces as $virtualInterface){
            //public network
            if($virtualInterface->vn_id == 0){
                /**
                 * @var $ip VmIpAddress
                 */
                $ip = VmIpAddress::ofHostingId($virtualInterface->hosting_id)->ofIp($virtualInterface->ip)->first();
            }
            $bridge = $this->getBridge($virtualInterface);
            if ($this->configuration()->isQemu())
            {
                $networkDevice = new NetworkDeviceKvm('net' . $networkId);
                $networkDevice->setBridge($bridge)
                    ->setRate($rate)
                    ->setFirewall($this->configuration()->isNetworkFirewall() ? 1 : 0);
                //ip config
                $ipConfig = new IpConfig('ipconfig' . $networkId);
                //Public
                if($ip){
                    $networkDevice->setModel($this->configuration()->getNetworkModel())
                        ->setTag($ip->tag)
                        ->setMacAddress($ip->mac_address)
                        ->setTrunks($ip->trunks)
                        ->setQueues(trim($this->configuration()->getQueues()));
                    //ipv4
                    if(!preg_match("/\:/",$virtualInterface->ip)){
                        $ipConfig->setIp(trim($virtualInterface->ip))
                            ->setCidr(trim($ip->cidr))
                            ->setGw(trim($ip->gateway));
                    }else{
                        //ipv6
                        $ipConfig->setIp6(trim($virtualInterface->ip))
                            ->setCidr6(trim($ip->cidr))
                            ->setGw6(trim($ip->gateway));
                    }
                }else{
                    $networkDevice->setModel($this->configuration()->getNetworkPrivateModel())
                        ->setTag($virtualInterface->virtualNetwork->tag);
                    $ipConfig->setIp(trim($virtualInterface->ip))
                        ->setCidr(trim($virtualInterface->virtualNetwork->cidr))
                        ->setGw(trim($virtualInterface->virtualNetwork->gateway));
                }
                if(!$this->configuration()->isOneNetworkDevice() || ( $this->configuration()->isOneNetworkDevice() && $networkDevice->getId() =="net0")){
                    $this->networkDevices[] = $networkDevice;
                    $this->ipConfigs[] = $ipConfig;
                }
            }
            //lxc
            if ($this->configuration()->isLxc())
            {
                $networkDevice = new NetworkDeviceLxc('net' . $networkId);
                $networkDevice->setName('eth' . $networkId)
                    ->setBridge($bridge)
                    ->setFirewall($this->configuration()->isNetworkFirewall() ? 1 : 0)
                    ->setIp($virtualInterface->ip)
                    ->setRate($rate);
                //Public
                if($ip){
                    $networkDevice->setCidr($ip->cidr)
                        ->setGw($ip->gateway)
                        ->setTag($ip->tag)
                        ->setHwaddr($ip->mac_address)
                        ->setTrunks($ip->trunks);
                }else{
                    $networkDevice->setCidr($virtualInterface->virtualNetwork->cidr)
                        ->setGw($virtualInterface->virtualNetwork->gateway)
                        ->setTag($virtualInterface->virtualNetwork->tag);
                }
                if(!$this->configuration()->isOneNetworkDevice() || ( $this->configuration()->isOneNetworkDevice() && $networkDevice->getId() =="net0")){
                    $this->networkDevices[] = $networkDevice;
                }

            }
            //one network device for public ip only
            if($this->configuration()->isOneNetworkDevice() && $networkDevice->getId() !="net0" && $ip instanceof VmIpAddress ){
                $virtualInterface->net = "net0";
                $virtualInterface->save();
                $ip->net = "net0";
                $ip->save();
            }else{
                $virtualInterface->net = $networkDevice->getId();
                $virtualInterface->save();
                //public ip
                if($ip instanceof VmIpAddress){
                    $ip->net = $networkDevice->getId();
                    $ip->save();
                }
            }
            $networkId++;
            unset($ip);
        }
    }

    public function asConfig(){
        $this->convert();
        return array_merge($this->getNetworkDevicesAsConfig(), $this->getIpConfigsAsConfig());
    }

    public function getNetworkDevicesAsConfig(){
        $container=[];
        foreach ($this->networkDevices as $networkDevice){
            $container[$networkDevice->getId()] = $networkDevice->asConfig();
        }
        return $container;
    }

    public function getIpConfigsAsConfig(){
        $container=[];
        foreach ($this->ipConfigs as $ipConfig){
            $container[$ipConfig->getId()] = $ipConfig->asConfig();
        }
        return $container;
    }

    private function getRate(){
        $rate      = null;
        if ($this->isWhmcsConfigOption(ConfigurableOption::NETWORK_RATE) && $this->getWhmcsConfigOption(ConfigurableOption::NETWORK_RATE) != "-1")
        {
            $rate = $this->getWhmcsConfigOption(ConfigurableOption::NETWORK_RATE);
        }
        else
        {
            if ($this->configuration()->getRate())
            {
                $rate = $this->configuration()->getRate();
            }
        }
        return $rate;
    }

    private function getBridge(VirtualInterface $virtualInterface){
        if($virtualInterface->vn_id == 0){
            return $this->configuration()->getBridge();
        }
        return $this->configuration()->getPrivateBridge() ? $this->configuration()->getPrivateBridge() :  $this->configuration()->getBridge();
    }

    private function freeNetworDeviceId(){
        if($this->vm){
            return $this->vm->findFreeNetworDeviceId();
        }
        return 0;
    }
}