<?php


namespace ModulesGarden\ProxmoxAddon\App\Services\Vps;

use Illuminate\Database\Capsule\Manager as DB;
use MGProvision\Proxmox\v2\Api;
use MGProvision\Proxmox\v2\models\Config;
use MGProvision\Proxmox\v2\models\IpConfig;
use MGProvision\Proxmox\v2\models\Kvm;
use MGProvision\Proxmox\v2\models\NetworkDeviceKvm;
use MGProvision\Proxmox\v2\models\NetworkDeviceLxc;
use ModulesGarden\ProxmoxAddon\App\Models\IpAddress;
use ModulesGarden\ProxmoxAddon\App\Models\VmIpAddress;
use ModulesGarden\ProxmoxAddon\App\Services\ApiService;
use ModulesGarden\ProxmoxAddon\App\Services\IpLogService;
use ModulesGarden\ProxmoxAddon\App\Services\Utility;
use ModulesGarden\ProxmoxAddon\App\Enum\Vps\ConfigurableOption;
use ModulesGarden\ProxmoxAddon\App\Enum\Vps\CustomField;
use ModulesGarden\ProxmoxAddon\Core\UI\Traits\WhmcsParams;

class NetworkService
{
    use WhmcsParams;
    use HostingService;
    use ApiService;
    use ProductService;
    protected $deletePrivateNetwork = false;

    /**
     * @param VmIpAddress[] $enteries
     */
    public function create(array $enteries)
    {
        //to do acl
        $this->setHostingId($this->getWhmcsParamByKey("serviceid"));
        DB::beginTransaction();

        try
        {
            foreach ($enteries as &$ip)
            {
                //insert to data base
                $ip->save();
                $this->hosting()->ipAdd($ip->ip);
                //lock ip in proxmox addon
                if (!Utility::isIpManagerProxmoxVPSIntegration())
                {
                    IpAddress::where('ip', $ip->ip)
                        ->update(["hosting_id" => $ip->hosting_id]);
                }
            }
            //update hosting
            $this->hosting()->save();
            DB::commit();
        }
        catch (\Exception $ex)
        {
            DB::rollBack();
            throw $ex;
        }
    }

    /**
     * @param VmIpAddress[] $enteries
     */
    public function addPrivate(array $enteries)
    {
        $this->setHostingId($this->getWhmcsParamByKey("serviceid"));
        $container = [];
        $rate      = null;
        $tag       = $this->makeTag();
        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();
            }
        }
        //cloud init
        $isCloudInit = $this->configuration()->isQemu() && $this->configuration()->isCloudInit();
        try
        {
            DB::beginTransaction();
            Api::beginTransaction();
            foreach ($enteries as &$ip)
            {
                //insert to data base
                $ip->save();
                $this->hosting()->ipAdd($ip->ip);
                //lock ip in proxmox addon
                IpAddress::where('ip', $ip->ip)
                    ->update(["hosting_id" => $ip->hosting_id]);
                $networkId = $this->vm()->findFreeNetworDeviceId();
                if ($this->configuration()->isLxc())
                {
                    $networkDevice = new NetworkDeviceLxc('net' . $networkId);
                    $networkDevice->setName('eth' . $networkId)
                        ->setBridge($this->configuration()->getPrivateBridge())
                        ->setFirewall($this->configuration()->isNetworkFirewall() ? 1 : 0);
                    if ($ip->mac_address && $ip->mac_address != "auto")
                    {
                        $networkDevice->setHwaddr($ip->mac_address);
                    }
                    $networkDevice->setIp($ip->ip)
                        ->setCidr($ip->cidr)
                        ->setGw($ip->gateway)
                        ->setTag($tag)
                        ->setRate($rate)
                        ->setTrunks($ip->trunks);
                    $container[$networkDevice->getId()] = $networkDevice->asConfig();
                }
                else
                {
                    if ($this->configuration()->isQemu())
                    {
                        $networkDevice = new NetworkDeviceKvm('net' . $networkId);
                        $networkDevice->setBridge($this->configuration()->getPrivateBridge())
                            ->setModel($this->configuration()->getNetworkPrivateModel())
                            ->setRate($rate)
                            ->setTag($tag)
                            ->setTrunks($ip->trunks)
                            ->setFirewall($this->configuration()->isNetworkFirewall() ? 1 : 0);

                        if ($ip->mac_address && $ip->mac_address != "auto")
                        {
                            $networkDevice->setMacAddress($ip->mac_address);
                        }
                        $container[$networkDevice->getId()] = $networkDevice->asConfig();
                        if ($isCloudInit)
                        {
                            $ipConfig = new IpConfig('ipconfig' . $networkId);
                            $ipConfig->setIp(trim($ip->ip))
                                ->setCidr(trim($ip->cidr))
                                ->setGw(trim($ip->gateway));
                            $container[$ipConfig->getId()] = $ipConfig->asConfig();
                        }
                    }
                }
                $ip->net = $networkDevice->getId();
                $ip->tag = $tag;
                $ip->save();
            }
            //update hosting
            $this->hosting()->save();
            $this->vm()->updateConfig($container);
            DB::commit();
        }
        catch (\Exception $ex)
        {
            DB::rollBack();
            Api::commit();
            throw $ex;
        }
    }

    protected function makeTag()
    {
        if (is_numeric($this->getWhmcsCustomField(CustomField::TAG)))
        {
            return $this->getWhmcsCustomField(CustomField::TAG);
        }
        if (!$this->configuration()->getTagFrom() && !$this->configuration()->getTagTo())
        {
            return null;
        }
        $tag = $this->nextTag();
        if (!$tag)
        {
            throw new \Exception("Max VLAN tag have been reached, Please Configure product  (Max VLAN tag)");
        }
        $this->customFieldUpdate("VLAN Tag", $tag);
        return $tag;
    }

    public function nextTag()
    {
        $cf = "tblcustomfields";
        $cv = "tblcustomfieldsvalues";
        for ($i = $this->configuration()->getTagFrom(); $i <= $this->configuration()->getTagTo(); $i++)
        {
            $query = DB::table($cf)
                ->select("{$cv}.value")
                ->leftJoin($cv, "{$cv}.fieldid", "=", "{$cf}.id")
                ->where("{$cf}.type", "product")
                ->where("{$cf}.relid", $this->getWhmcsParamByKey("packageid"))
                ->where("{$cf}.fieldname", 'like', "VLAN Tag%")
                ->where("{$cv}.relid", '!=', $this->getWhmcsParamByKey("serviceid"))
                ->where("{$cv}.value", $i);
            if ($query->count())
            {
                continue;
            }
            return $i;
        }
        return false;
    }

    /**
     * @return VmIpAddress
     */
    public function getPrivateIpAddress()
    {
        $ip    = IpAddress::where('private', 1)
            ->where('type', 'IPv4')
            ->whereIn("sid", [$this->getWhmcsParamByKey('serverid'), "0"])
            ->where('hosting_id', '0')
            ->firstOrFail();
        $newIp = new VmIpAddress();
        $newIp->fill($ip->toArray());
        $newIp->hosting_id = $this->getWhmcsParamByKey("serviceid");
        $newIp->server_id  = $this->getWhmcsParamByKey("serverid");
        return $newIp;
    }

    public function hasPrivateIpAddress()
    {
        $query = IpAddress::where('private', 1)
            ->where('type', 'IPv4')
            ->whereIn("sid", [$this->getWhmcsParamByKey('serverid'), "0"])
            ->where('hosting_id', '0');
        return $query->count();
    }

    public function deleteByNetworkId(array $networkIds)
    {
        if (is_null($networkIds))
        {
            throw new \InvalidArgumentException('The network ids cannot be empty');
        }
        $ipAddresses = VmIpAddress::ofHostingId($this->getWhmcsParamByKey("serviceid"))
            ->whereIn("net", $networkIds)->get()->all();
        return $this->deleteByIpAddresses($ipAddresses);
    }

    public function deleteByIpAddresses(array $ipAddresses)
    {
        if (is_null($ipAddresses))
        {
            throw new \InvalidArgumentException('The IP Addresses cannot be empty');
        }
        $devices      = $this->vm()->getNetworkDevices();
        if($this->configuration()->getPrivateBridge()){
            $privateDevices = $this->vm()->getNetworkDevices($this->configuration()->getPrivateBridge());
        }
        $configDelete = [];
        $ipunassigned = [];
        $this->setHostingId($this->getWhmcsParamByKey("serviceid"));
        DB::beginTransaction();
        Api::beginTransaction();
        try
        {
            foreach ($ipAddresses as &$ip)
            {
                if (is_numeric($ip))
                {
                    $ip = VmIpAddress::where("id", $ip)->firstOrFail();
                }
                if (!$ip instanceof VmIpAddress)
                {
                    throw new \InvalidArgumentException(sprintf('The following class are not supported "%s"', get_class($ip)));
                };
                //private ip
                if(!$this->deletePrivateNetwork && isset($privateDevices[0]) && $privateDevices[0] && $privateDevices[0]->getId() == $ip->net){
                    continue;
                }
                $ip->delete();

                $this->hosting()->ipDelete($ip->ip);
                $ipunassigned[] = $ip->ip;
                //Unlock ip in Proxmox Addon
                IpAddress::where('ip', $ip->ip)
                    ->where('hosting_id', $ip->hosting_id)
                    ->update(["hosting_id" => "0", 'last_check' => Utility::timeStamp()]);

                foreach ($devices as $deviceIndex => $device)
                {
                    if ($this->configuration()->isOneNetworkDevice() && $device->getId() == "net0")
                    {
                        continue;
                    }
                    if($device instanceof NetworkDeviceLxc)
                    {
                        if ($ip->ip == $device->getIp())
                        {
                            $device->setIp(null);
                        }

                        if ($ip->ip == $device->getIp6())
                        {
                            $device->setIp6(null);
                        }

                        if(empty($device->getIp6()) && empty($device->getIp()))
                        {
                            unset($devices[$deviceIndex]);
                            $configDelete[] = $device->getId();
                        }
                    }
                    elseif($device instanceof  NetworkDeviceKvm && $ip->net && $ip->net == $device->getId())
                    {
                        $configDelete[] = $device->getId();
                        unset($devices[$deviceIndex]);
                    }
                }
                
                //cloud init
                if ($this->vm() instanceof Kvm)
                {
                    foreach ($this->vm()->getIpConfig()->fetch() as $ipConfig)
                    {
                        if ($ipConfig->getIp() == $ip->ip || $ipConfig->getIp6() == $ip->ip)
                        {
                            $configDelete[] = $ipConfig->getId();
                        }
                    }
                }
            }

            $this->hosting()->save();
            /**
             * Update current config. We need that only if we remove only one IP and other IP is still on the same interface
             */
            $config = new Config();
            $config->setNet($devices);
            $config = $config->toArray();
            if($config)
            {
                $this->vm()->updateConfig($config);
            }

            /**
             * Delete config. We need that when there is no more network interface
             */
            if (!empty($configDelete))
            {
                $this->vm()->deleteConfig(implode(",", $configDelete));
            }
            if(!empty( $ipunassigned)){
                (new IpLogService())->unassigned($ipunassigned);
            }
            DB::commit();
        }
        catch (\Exception $ex)
        {
            DB::rollBack();
            Api::commit();
            throw $ex;
        }
    }

    public function hasIp($totalIpv4, $totalIpv6, $nodeName, $bridge="")
    {
        $virtualization = $this->configuration()->isQemu() ? "KVM" : "LXC";
        $tags = $this->configuration()->getTags();
        if($this->getWhmcsConfigOption(ConfigurableOption::TAG) > 0){
            $tags = [$this->getWhmcsConfigOption(ConfigurableOption::TAG)];
        }
        if ((int)$totalIpv4 > 0)
        {
            /**
             * @var $ipCollections IpAddress
             */
            $ipCollections = IpAddress::where('hosting_id', '0')
                ->where('private', '0')
                ->where('type', 'IPv4')
                ->whereIn('sid', [$this->getWhmcsParamByKey('serverid'), '0'])
                ->whereIn('visualization', [$virtualization, 'Auto'])
                ->whereIn('node', [$nodeName, '0', ""])
               ->whereIn('bridge', [$bridge, ""]);
            //tag
            if ($tags)
            {
                $ipCollections->ofTags($tags);
            }
            $count = $ipCollections->count();
            if ((int)$count < $totalIpv4)
            {
                $errorMessage =  sprintf("Unable to get %s of IPv4. IP Addresses available: %s", $totalIpv4, $count);
                if($nodeName){
                    $errorMessage =  sprintf("Unable to get %s of IPv4, on node: %s. IP Addresses available: %s", $totalIpv4, $nodeName, $count);
                }
                throw new \Exception($errorMessage);
            }
        }
        if ((int)$totalIpv6 > 0)
        {
            $ipCollections = IpAddress::where('hosting_id', '0')
                ->where('private', '0')
                ->where('type', 'IPv6')
                ->whereIn('sid', [$this->getWhmcsParamByKey('serverid'), '0'])
                ->whereIn('visualization', [$virtualization, 'Auto'])
                ->whereIn('node', [$nodeName, '0', ""])
                ->whereIn('bridge', [$bridge, ""]);
            //tag
            if ($tags)
            {
                $ipCollections->ofTags($tags);
            }
            $count = $ipCollections->count();
            if ((int)$count < $totalIpv6)
            {
                $errorMessage =  sprintf("Unable to get %s of IPv6. IP Addresses available: %s", $totalIpv6, $count);
                if($nodeName){
                    $errorMessage =  sprintf("Unable to get %s of IPv6, on node: %s. IP Addresses available: %s", $totalIpv6, $nodeName, $count);
                }
                throw new \Exception($errorMessage);
            }
        }
        return $this;
    }

    public function addIp($totalIpv4, $totalIpv6, $nodeName, $bridge="")
    {
        try {
            DB::beginTransaction();
            $virtualization = $this->configuration()->isQemu() ? "KVM" : "LXC";
            $this->setHostingId($this->getWhmcsParamByKey('serviceid'));
            $tags = $this->configuration()->getTags();
            if($this->getWhmcsConfigOption(ConfigurableOption::TAG) > 0){
                $tags = [$this->getWhmcsConfigOption(ConfigurableOption::TAG)];
            }
            if ((int)$totalIpv4 > 0) {
                $query = IpAddress::where('hosting_id', '0')
                    ->where('private', '0')
                    ->where('type', 'IPv4')
                    ->whereIn('sid', [$this->getWhmcsParamByKey('serverid'), '0'])
                    ->whereIn('visualization', [$virtualization, 'Auto'])
                    ->whereIn('node', [$nodeName, '0', ""])
                    ->whereIn('bridge', [$bridge, ""]);
                if ($tags) {
                    $query->ofTags($tags);
                }
                $count = $query->limit($totalIpv4)
                    ->orderBy('last_check', 'asc')
                    ->update(["hosting_id" => $this->getWhmcsParamByKey('serviceid'), 'last_check' => Utility::timeStamp()]);
                if ((int)$count < $totalIpv4) {
                    throw new \Exception(sprintf("Unable to get %s of IPv4. IP Addresses available: %s", $totalIpv4, $count));
                }

            }
            if ((int)$totalIpv6 > 0) {
                $query = IpAddress::where('hosting_id', '0')
                    ->where('private', '0')
                    ->where('type', 'IPv6')
                    ->whereIn('sid', [$this->getWhmcsParamByKey('serverid'), '0'])
                    ->whereIn('visualization', [$virtualization, 'Auto'])
                    ->whereIn('node', [$nodeName, '0', ""])
                    ->whereIn('bridge', [$bridge, ""]);
                if ($tags) {
                    $query->ofTags($tags);
                }
                $count = $query->limit($totalIpv6)
                    ->orderBy('last_check', 'asc')
                    ->update(["hosting_id" => $this->getWhmcsParamByKey('serviceid'), 'last_check' => Utility::timeStamp()]);

                if ((int)$count < $totalIpv6) {
                    throw new \Exception(sprintf("Unable to get %s of IPv6. IP Addresses available: %s", $totalIpv6, $count));
                }
            }
            $vmIp = (new VmIpAddress())->getTable();
            $collection = IpAddress::where('hosting_id', $this->getWhmcsParamByKey('serviceid'))
                ->orderBy("ip", "desc")
                ->whereNotIn('ip', function ($query) use ($vmIp) {
                    $query->select('ip')->from($vmIp);
                });
            $newIps = [];
            foreach ($collection->get()->sortBy("type")->all() as $ip) {
                /*@var $ip IpAddress */
                $newIp = new VmIpAddress();
                $ipData = $ip->toArray();
                unset($ipData['id']);
                $ipData['hosting_id'] = $this->getWhmcsParamByKey('serviceid');
                $ipData['server_id'] = $this->getWhmcsParamByKey('serverid');
                $newIp->fill($ipData)->save();
                $this->hosting()->ipAdd($ip->ip);
                $newIps[] = $ip->ip;
            }
            if(!empty($newIps)){
                (new IpLogService())->assigned($newIps);
            }
            $this->hosting()->save();
            DB::commit();
        } catch (\Exception $ex) {
            DB::rollBack();
            throw $ex;
        }
    }

    public function deleteIpAddresses()
    {
        $ipunassigned =  VmIpAddress::ofHostingId($this->getWhmcsParamByKey('serviceid'))->pluck('ip')->toArray();
        if(!empty( $ipunassigned)){
            (new IpLogService())->unassigned($ipunassigned);
        }
        VmIpAddress::ofHostingId($this->getWhmcsParamByKey('serviceid'))->delete();
        //Unlock ip in Proxmox Addon
        IpAddress::where('hosting_id', $this->getWhmcsParamByKey('serviceid'))
            ->update(["hosting_id" => "0", 'last_check' => Utility::timeStamp()]);
        $this->setHostingId($this->getWhmcsParamByKey('serviceid'));
        $this->hosting()->dedicatedip = "";
        $this->hosting()->assignedips = "";
        $this->hosting()->save();
        return $this;
    }

    public function buildLxc()
    {
        $container = [];
        /**
         * @var VmIpAddress[] $ipv4
         */
        $ipv4 = VmIpAddress::ofHostingId($this->getWhmcsParamByKey("serviceid"))
            ->ofIp4()
            ->ofNetNull()
            ->get();
        //ip6
        $ipv6 = VmIpAddress::ofHostingId($this->getWhmcsParamByKey("serviceid"))
            ->ofIp6()
            ->ofNetNull()
            ->get();

        //Network
        $bridge   = $this->configuration()->getBridge();
        $firewall = $this->configuration()->isNetworkFirewall() ? 1 : 0;
        $ip4Mode  = $this->configuration()->getIpv4NetworkMode();
        $ip6Mode  = $this->configuration()->getIpv6NetworkMode();
        $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());
        }
        $networkId = 0;
        if ($this->hasVm())
        {
            $networkId = $this->vm()->findFreeNetworDeviceId();
        }
        for ($i = 0; $i <= 9; $i++)
        {
            //Empty IP Addresses
            if (!$ipv4->get($i) && !$ipv6->get($i))
            {
                break;
            }
            if ($networkId > 9)
            {
                break;
            }
            $mac = null;
            //Name
            $interface = new NetworkDeviceLxc('net' . $networkId);
            $interface->setName('eth' . $networkId)
                ->setBridge($bridge)
                ->setFirewall($firewall);
            //IP 4
            if ($ipv4->get($i))
            {
                if ($ipv4->get($i)->mac_address)
                {
                    $mac = $ipv4->get($i)->mac_address;
                }
                if ($ipv4->get($i)->tag)
                {
                    $interface->setTag($ipv4->get($i)->tag);
                }
                $interface->setTrunks($ipv4->get($i)->trunks);
                if ($ip4Mode == 'static')
                { //IP & CIRD
                    $interface->setIp($ipv4->get($i)->ip);
                    $interface->setCidr($ipv4->get($i)->cidr);
                    //Gateway
                    $interface->setGw($ipv4->get($i)->gateway);
                }
                $ipv4->get($i)->net = $interface->getId();
                $ipv4->get($i)->save();
            }
            if ($ip4Mode == "dhcp")
            {
                $interface->setIp("dhcp");
            }
            //IP 6
            if ($ip6Mode == "dhcp")
            {
                $interface->setIp6("dhcp");
            }
            else
            {
                if ($ip6Mode == "slaac")
                {
                    $interface->setIp6("auto");
                }
            }
            if ($ipv6->get($i))
            {  //IP & CIRD
                if ($ip6Mode == "static")
                {
                    $interface->setIp6($ipv6->get($i)->ip);
                    $interface->setCidr6($ipv6->get($i)->cidr);
                    //Gateway
                    $interface->setGw6($ipv6->get($i)->gateway);
                }
                if ($ipv6->get($i)->tag)
                {
                    $interface->setTag($ipv6->get($i)->tag);
                }
                if ($ipv6->get($i)->trunks)
                {
                    $interface->setTrunks($ipv6->get($i)->trunks);
                }
                if ($mac == null && $ipv6->get($i)->mac_address)
                {
                    $mac = $ipv6->get($i)->mac_address;
                }
                $ipv6->get($i)->net = $interface->getId();
                $ipv6->get($i)->save();
            }
            if ($rate)
            {
                $interface->setRate($rate);
            }
            $interface->setHwaddr($mac);
            $container['net' . $networkId] = $interface->asConfig();
            $networkId++;
        }
        return $container;

    }

    public function buildQemu()
    {
        $container = [];
        /**
         * @var VmIpAddress[] $ipv4
         */
        $ipv4 = VmIpAddress::ofHostingId($this->getWhmcsParamByKey("serviceid"))
            ->ofIp4()
            ->ofNetNull()
            ->get();
        //ip6
        $ipv6 = VmIpAddress::ofHostingId($this->getWhmcsParamByKey("serviceid"))
            ->ofIp6()
            ->ofNetNull()
            ->get();
        //Network
        $model    = $this->configuration()->getNetworkModel();
        $bridge   = $this->configuration()->getBridge();
        $firewall = $this->configuration()->isNetworkFirewall() ? 1 : 0;
        $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());
        }
        $networkId          = 0;
        $vmNetworkDevices   = [];

        if ($this->hasVm())
        {
            $networkId = $this->vm()->findFreeNetworDeviceId();
            $vmNetworkDevices   = $this->vm()->getNetworkDevices();
        }

        $i4      = 0;
        $i6      = 0;
        $isApi52 = version_compare($this->api()->getVersion(), "5.2", '>=');
        for ($i = 0; $i <= 31; $i++)
        {
            //Empty IP Addresses
            if (!$ipv4->get($i4) && !$ipv6->get($i6))
            {
                break;
            }
            if ($networkId > 31)
            {
                break;
            }
            if ($this->configuration()->isOneNetworkDevice() && ($i > 0 || count($vmNetworkDevices)))
            {
                VmIpAddress::ofHostingId($this->getWhmcsParamByKey("serviceid"))
                    ->ofNetNull()
                    ->update(["net" => 'net0']);
                break;
            }

            $mac   = null;
            $isIp4 = false;
            //Name
            $interface = new NetworkDeviceKvm('net' . $networkId);
            $interface->setModel($model)
                ->setBridge($bridge)
                ->setFirewall($firewall);
            $ipConfig = new IpConfig('ipconfig' . $networkId);
            //IP 4
            if ($ipv4->get($i4))
            {
                $isIp4 = true;
                if (trim($ipv4->get($i4)->mac_address))
                {
                    $mac = $ipv4->get($i4)->mac_address;
                }
                if ($ipv4->get($i4)->tag)
                {
                    $interface->setTag(trim($ipv4->get($i4)->tag));
                }
                $interface->setTrunks(trim($ipv4->get($i4)->trunks));
                //private ip
                if($this->configuration()->getPrivateBridge() && IpAddress::ofHostingId($this->getWhmcsParamByKey("serviceid"))->ofIp($ipv4->get($i4)->ip)->private()->count()){
                    $interface->setBridge($this->configuration()->getPrivateBridge());
                }
                $ipConfig->setIp(trim($ipv4->get($i4)->ip));
                $ipConfig->setCidr(trim($ipv4->get($i4)->cidr));
                //Gateway
                $ipConfig->setGw(trim($ipv4->get($i4)->gateway));
                $ipv4->get($i4)->net = $interface->getId();
                $ipv4->get($i4)->save();
                $i4++;
            }
            //ipv6
            if ($ipv6->get($i6) && (!$isIp4 || $interface->getTag() == $ipv6->get($i6)->tag))
            {  //IP & CIRD
                $ipConfig->setIp6(trim($ipv6->get($i6)->ip));
                $ipConfig->setCidr6(trim($ipv6->get($i6)->cidr));
                //Gateway
                $ipConfig->setGw6(trim($ipv6->get($i6)->gateway));
                if ($ipv6->get($i6)->tag)
                {
                    $tag = $ipv6->get($i6)->tag;
                    $interface->setTag(trim($ipv6->get($i6)->tag));
                }
                if ($ipv6->get($i6)->trunks)
                {
                    $interface->setTrunks(trim($ipv6->get($i6)->trunks));
                }
                if ($mac == null && $ipv6->get($i6)->mac_address)
                {
                    $mac = $ipv6->get($i6)->mac_address;
                }
                $ipv6->get($i6)->net = $interface->getId();
                $ipv6->get($i6)->save();
                $i6++;
            }
            $interface->setRate(trim($rate));
            $interface->setMacAddress(trim($mac));
            $interface->setQueues(trim($this->configuration()->getQueues()));
            $container[$interface->getId()] = $interface->asConfig();
            if ($isApi52 && ($ipConfig->getIp() || $ipConfig->getIp6()))
            {
                $container[$ipConfig->getId()] = $ipConfig->asConfig();
            }
            $networkId++;
        }

        return $container;
    }

    public function unassignIpAddressesAndDeleteNetwork()
    {
        list($requestIPv4, $requestIPv6) = $this->getIpAddressesRequest();
        $ip4 = [];
        $ip6 = [];
        if ($requestIPv4 < 0)
        {
            $ip4 = VmIpAddress::ofHostingId($this->getWhmcsParamByKey('serviceid'))
                ->ofIp4()
                ->ofNetNotNull()
                ->limit(abs($requestIPv4))
                ->orderByIdDesc()
                ->get()
                ->all();
        }
        if ($requestIPv6 < 0)
        {
            $ip6 = VmIpAddress::ofHostingId($this->getWhmcsParamByKey('serviceid'))
                ->ofIp6()
                ->ofNetNotNull()
                ->limit(abs($requestIPv6))
                ->orderByIdDesc()
                ->get()
                ->all();
        }
        $ipAddresses = array_merge($ip4, $ip6);
        if (!empty($ipAddresses))
        {
            $this->deleteByIpAddresses($ipAddresses);
        }
    }

    public function getIpAddressesRequest()
    {
        $ipv4Used    = (int)VmIpAddress::ofHostingId($this->getWhmcsParamByKey('serviceid'))
            ->ofIp4()
            ->count();
        $ipv6Used    = (int)VmIpAddress::ofHostingId($this->getWhmcsParamByKey('serviceid'))
            ->ofIp6()
            ->count();
        $requestIPv4 = (int)$this->configuration()->getIpv4();
        $requestIPv6 = (int)$this->configuration()->getIpv6();
        if ($this->isWhmcsConfigOption(ConfigurableOption::IPV4))
        {
            $requestIPv4 = (int)$this->getWhmcsConfigOption(ConfigurableOption::IPV4);
        }
        if ($this->isWhmcsConfigOption(ConfigurableOption::IPV6))
        {
            $requestIPv6 = (int)$this->getWhmcsConfigOption(ConfigurableOption::IPV6);
        }
        return [(int)$requestIPv4 -= $ipv4Used, (int)$requestIPv6 -= $ipv6Used];
    }

    /**
     * @param bool $deletePrivateNetwork
     * @return NetworkService
     */
    public function setDeletePrivateNetwork(bool $deletePrivateNetwork): NetworkService
    {
        $this->deletePrivateNetwork = $deletePrivateNetwork;
        return $this;
    }


}