<?php


namespace ModulesGarden\ProxmoxAddon\App\Jobs\Vps;


use Illuminate\Database\Capsule\Manager as DB;
use MGProvision\Proxmox\v2\Api;
use MGProvision\Proxmox\v2\models\Features;
use MGProvision\Proxmox\v2\models\Node;
use ModulesGarden\ProxmoxAddon\App\Enum\Vps\CustomField;
use ModulesGarden\ProxmoxAddon\App\Events\Vps\VmCreatedEvent;
use ModulesGarden\ProxmoxAddon\App\Models\NodeSetting;
use ModulesGarden\ProxmoxAddon\App\Services\Utility;
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 function ModulesGarden\ProxmoxAddon\Core\Helper\fire;

class CreateLxcJob extends BaseJob
{

    use ProductService;
    use UserService;

    public function handle()
    {
        $this->initParams();
        $this->initServices();
        $this->setHostingId($this->getWhmcsParamByKey("serviceid"));
        //create task validation
        if ($this->isDone())
        {
            if($this->configuration()->isMountPoint()){
                $this->additionalMountPointService->create();
            }
            fire(new VmCreatedEvent($this->vm()));
            return true;
        }
        elseif ($this->isTaskRunning())
        {
            //sleep
            $this->sleep(5);
            return false;
        }
        try
        {
            Api::beginTransaction();
            DB::beginTransaction();
            //vmid
            $vmid = $this->nextVmid();
            $this->customFieldUpdate("vmid", $vmid);
            //os
            if($this->isWhmcsConfigOption(\ModulesGarden\ProxmoxAddon\App\Enum\Vps\ConfigurableOption::OS_TEMPLATE) && $this->getWhmcsConfigOption(ConfigurableOption::OS_TEMPLATE) !="0"){
                $osTemplate = $this->getWhmcsConfigOption(ConfigurableOption::OS_TEMPLATE);
            }else if( $this->isWhmcsConfigOption(ConfigurableOption::ARCHIVE) && $this->getWhmcsConfigOption(ConfigurableOption::ARCHIVE) !="0" ){
                $archive = $this->getWhmcsConfigOption(ConfigurableOption::ARCHIVE);
            } else if($this->configuration()->getOsTemplate() && $this->configuration()->getOsTemplate()!="0"){
                $osTemplate = $this->configuration()->getOsTemplate();
            } else if($this->configuration()->archive && $this->configuration()->archive!="0"){
                $archive = $this->configuration()->archive;
            }
            $container = [
                'vmid'       => $vmid,
                'ostemplate' => $this->getWhmcsConfigOption(ConfigurableOption::OS_TEMPLATE, $this->configuration()->getOsTemplate()),
                'hostname'   => $this->containerService->hostname(),
                'password'   => $this->getWhmcsParamByKey('password'),
            ];
            if(isset($osTemplate) && $osTemplate){
                $container['ostemplate'] = $osTemplate;
            }elseif (isset($archive) && $archive){
                list($backupNode, $volid) = explode(":", $archive, 2);
                $container['ostemplate'] = $volid;
            }
            //default node
            if(isset($backupNode) && $backupNode){
                $nodeService = new Node($backupNode);
            }else{
                $nodeService = $this->getWhmcsCustomField(CustomField::NODE)? new Node($this->getWhmcsCustomField(CustomField::NODE)) : $this->getNode();
            }
            //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);
            }
            //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())
            {
                $container['cmode'] = $this->configuration()->getCmode();
            }
            //console
            if ($this->configuration()->isConsole())
            {
                $container['console'] = 1;
            }
            //description
            if ($this->configuration()->getDescription())
            {
                $container['description'] = $this->containerService->description();
            }
            //onboot
            if ($this->configuration()->isOnboot())
            {
                $container['onboot'] = 1;
            }
            //ostype
            if ($this->configuration()->getOsType())
            {
                $container['ostype'] = $this->configuration()->getOsType();
            }
            //pool
            if ($this->configuration()->getPool())
            {
                $container['pool'] = $this->configuration()->getPool();
            }
            //protection
            if ($this->configuration()->isProtection())
            {
                $container['protection'] = 1;
            }
            //startup
            if ($this->configuration()->getStartup())
            {
                $container['startup'] = $this->configuration()->getStartup();
            }
            //storage
            $dafaultStorage  = NodeSetting::ofServer($this->getWhmcsParamByKey('serverid'))
                                           ->ofNode($nodeService->getNode())
                                           ->ofSetting('defaultStorage')
                                           ->value("value");
            $container['storage'] = $dafaultStorage ? $dafaultStorage: $this->configuration()->getStorage();
            //tty
            if ($this->configuration()->getTty())
            {
                $container['tty'] = $this->configuration()->getTty();
            }
            //unprivileged
            $container['unprivileged'] = $this->configuration()->isUnprivileged() ? 1 : 0;
            //Disk
            $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');
                $container['storage'] = $storage;
            }
            elseif ($this->isWhmcsConfigOption(ConfigurableOption::DISK_SIZE))
            {
                $diskSize = $this->getWhmcsConfigOption(ConfigurableOption::DISK_SIZE);
                Utility::unitFormat($diskSize, $this->configuration()->getDiskUnit(), 'gb');
            }
            //Rootfs
            $container['rootfs'] = "{$container['storage']}:{$diskSize}";
            //SSH Public key.
            if ($this->configuration()->isSshKeyPairs())
            {
                $container['ssh-public-keys'] = $this->containerService->makeKeyPairs()->getPublic();
            }
            //Network
            $networkService = new NetworkService();
            $container      += $networkService->buildLxc();
            //start
            if ($this->configuration()->isStart()  && version_compare($this->api()->getVersion(), "4.4", '>'))
            {
                $container['start'] = 1;
            }
            //features
            $features = new Features();
            //Keyctl
            if($this->configuration()->isFeatureKeyctl() && $this->configuration()->isUnprivileged()){
                $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);
            }
            if(!$features->isEmpty()){
                $container[Features::ID] = $features->asConfig();
            }
            //Create
            $vm          = $nodeService->lxc();
            $this->setVm($vm);
            $taskId = $vm->create($container);
            $this->customFieldUpdate("node", $nodeService->getNode());
            DB::commit();
        }
        catch (\Exception $ex)
        {
            DB::rollBack();
            Api::commit();
            $this->failed($ex->getMessage());
            throw $ex;
        }
        //task history
        $this->createTaskHistory($taskId, "Create");
        //save task id
        $this->putModelDataAndSave(["taskId" => $taskId, "node" => $nodeService->getNode()]);
        //sleep
        $this->sleep();
        return false;

    }


}
