<?php


namespace ModulesGarden\ProxmoxAddon\App\Jobs\Vps;


use Illuminate\Database\Capsule\Manager as DB;
use MGProvision\Proxmox\v2\Api;
use MGProvision\Proxmox\v2\models\HardDisk;
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\EmailService;
use ModulesGarden\ProxmoxAddon\App\Services\Utility;
use ModulesGarden\ProxmoxAddon\App\Services\Vps\AdditionalDiskService;
use ModulesGarden\ProxmoxAddon\App\Services\Vps\ContainerService;
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 CreateQemuJob extends BaseJob
{
    use ProductService;
    use UserService;

    private $networkService;

    protected function initServices()
    {
        $this->emailService     = new EmailService();
        $this->containerService = new ContainerService();
        $this->networkService   = new NetworkService();
        $this->additionalDiskService = new AdditionalDiskService();
    }

    public function handle()
    {
        $this->initParams();
        $this->initServices();
        $this->setHostingId($this->getWhmcsParamByKey("serviceid"));
        //create task validation
        if ($this->isDone())
        {
            if($this->configuration()->isAdditionalDisk()){
                $this->additionalDiskService->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);
            $container = [
                'vmid'   => $vmid,
                'name'   => $this->containerService->hostname(),
                "ostype" => $this->getWhmcsConfigOption(ConfigurableOption::OS_TYPE, $this->configuration()->getOsType())
            ];
            //vcpus
            if ($this->getWhmcsConfigOption(ConfigurableOption::VCPUS, $this->configuration()->getVcpus() ))
            {
                $container['vcpus'] = $this->getWhmcsConfigOption(ConfigurableOption::VCPUS, $this->configuration()->getVcpus() );
            }
            //cpulimit
            if ($this->getWhmcsConfigOption(ConfigurableOption::CPU_LIMIT, $this->configuration()->getCpulimit() ))
            {
                $container['cpulimit'] = $this->getWhmcsConfigOption(ConfigurableOption::CPU_LIMIT, $this->configuration()->getCpulimit() );
            }
            // Boot order device
            if ($this->configuration()->getBootOrder())
            {
                $container['boot'] = $this->configuration()->getBootOrder();
            }
            //numa
            if ($this->configuration()->isNuma())
            {
                $container['numa'] = 1;
            }
            //Memory
            if ($this->isWhmcsConfigOption(ConfigurableOption::MEMORY))
            {
                $container['memory'] = $this->getWhmcsConfigOption(ConfigurableOption::MEMORY);
                Utility::unitFormat($container['memory'], $this->configuration()->getMemoryUnit(), 'mb');
            }
            else if($this->configuration()->getMemory())
            {
                $container['memory'] = $this->configuration()->getMemory();
            }
            //cpuunits
            if ($this->getWhmcsConfigOption(ConfigurableOption::CPU_UNITS, $this->configuration()->getCpuunits() ))
            {
                $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);
            }
            //sockets
            if ($this->getWhmcsConfigOption(ConfigurableOption::SOCKETS, $this->configuration()->getSockets() ))
            {
                $container['sockets'] = $this->getWhmcsConfigOption(ConfigurableOption::SOCKETS, $this->configuration()->getSockets() );
            }
            //cores
            if ($this->getWhmcsConfigOption(ConfigurableOption::CORES_PER_SOCKET, $this->configuration()->getCores() ))
            {
                $container['cores'] = $this->getWhmcsConfigOption(ConfigurableOption::CORES_PER_SOCKET, $this->configuration()->getCores() );
            }
            //description
            if ($this->configuration()->getDescription())
            {
                $container['description'] = $this->containerService->description();
            }
            //onboot
            if ($this->configuration()->isOnboot())
            {
                $container['onboot'] = 1;
            }
            //pool
            if ($this->configuration()->getPool())
            {
                $container['pool'] = $this->configuration()->getPool();
            }
            //startup
            if ($this->configuration()->getStartup())
            {
                $container['startup'] = $this->configuration()->getStartup();
            }
            //busDevces
            $busDevices = [
                "ide"    => 0,
                "sata"   => 0,
                "virtio" => 0,
                "scsi"   => 0
            ];
            //CD-ROM
            if ($this->configuration()->getCdromType())
            {
                $iso  = $this->getWhmcsConfigOption(ConfigurableOption::ISO_IMAGE,  $this->configuration()->getIsoImage() );
                $type = $this->configuration()->getCdromType();
                $bus  = $busDevices[$type];
                $busDevices[$type]++;
                $container[$type . $bus] = "{$iso},media=cdrom";
            }
            //Disk
            $type = $this->configuration()->getDiskType();
            $bus  = $busDevices[$type];
            $busDevices[$type]++;
            $harDisk = new HardDisk($type . $bus);
            $dafaultStorage  = NodeSetting::ofServer($this->getWhmcsParamByKey('serverid'))
                ->ofNode($this->getNode()->getNode())
                ->ofSetting('defaultStorage')
                ->value("value");
            $harDisk->setStorage($dafaultStorage ? $dafaultStorage : $this->configuration()->getDiskStorage())
                ->setCache($this->configuration()->getDiskCache())
                ->setFormat($this->configuration()->getDiskFormat())
                ->setMbps_rd($this->configuration()->getMbpsRd())
                ->setMbps_wr($this->configuration()->getMbpsWr())
                ->setDiscard($this->configuration()->isDiscard() ? "on" : null)
                ->setIops_rd($this->configuration()->getIopsRd())
                ->setIops_rd_max($this->configuration()->getIopsRdMax())
                ->setIops_wr($this->configuration()->getIopsWr())
                ->setIops_wr_max($this->configuration()->getIopsWrMax())
                ->setReplicate($this->configuration()->isReplicate() ? 0 : null)
                ->setSsd($this->configuration()->isSsd() ? 1 : null);
            $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');
                $harDisk->setStorage($storage);
            }
            elseif ($this->isWhmcsConfigOption(ConfigurableOption::DISK_SIZE))
            {
                $diskSize = $this->getWhmcsConfigOption(ConfigurableOption::DISK_SIZE);
                Utility::unitFormat($diskSize, $this->configuration()->getDiskUnit(), 'gb');
            }
            if ($this->configuration()->isIoThread() && in_array($type, ['virtio', 'scsi']))
            {
                $harDisk->setIothread($this->configuration()->isIoThread());
            }
            $harDisk->setSize($diskSize);
            $container[$harDisk->getId()] = $harDisk->asConfig();
            //Network
            $container += $this->networkService->buildQemu();
            //acpi
            if ($this->configuration()->isAcpi())
            {
                $container['acpi'] = 1;
            }
            //agent
            if ($this->configuration()->isAgent())
            {
                $container['agent'] = 1;
            }
            //autostart
            if ($this->configuration()->isAutostart())
            {
                $container['autostart'] = 1;
            }
            //balloon
            if ($this->configuration()->getBalloon())
            {
                $container['balloon'] = $this->configuration()->getBalloon();
            }
            //shares
            if ($this->configuration()->getShares())
            {
                $container['shares'] = $this->configuration()->getShares();
            }
            //cdrom
            if ($this->configuration()->getCdrom())
            {
                $container['cdrom'] = $this->configuration()->getCdrom();
            }
            //cpu
            if ($this->configuration()->getCpu())
            {
                $container['cpu'] = $this->configuration()->getCpu();
            }
            //freeze
            if ($this->configuration()->isFreeze())
            {
                $container['freeze'] = 1;
            }
            //hotplug
            if ($this->configuration()->getHotplug())
            {
                $container['hotplug'] = $this->configuration()->getHotplug();
            }
            //keyboard
            if ($this->configuration()->getKeyboard())
            {
                $container['keyboard'] = $this->configuration()->getKeyboard();
            }
            //kvm
            if ($this->configuration()->isKvm())
            {
                $container['kvm'] = 1;
            }
            //localtime
            if ($this->configuration()->isLocaltime())
            {
                $container['localtime'] = 1;
            }
            //migrate_downtime
            if ($this->configuration()->getMigrateDowntime())
            {
                $container['migrate_downtime'] = $this->configuration()->getMigrateDowntime();
            }
            //migrate_speed
            if ($this->configuration()->getMigrateSpeed())
            {
                $container['migrate_speed'] = $this->configuration()->getMigrateSpeed();
            }
            //reboot
            if ($this->configuration()->isReboot())
            {
                $container['reboot'] = 1;
            }
            //startdate
            if ($this->configuration()->getStartdate())
            {
                $container['startdate'] = $this->configuration()->getStartdate();
            }
            //startup
            if ($this->configuration()->getStartup())
            {
                $container['startup'] = $this->configuration()->getStartup();
            }
            //tablet
            if ($this->configuration()->isTablet())
            {
                $container['tablet'] = 1;
            }
            //tdf
            if ($this->configuration()->isTdf())
            {
                $container['tdf'] = 1;
            }
            //watchdog
            if ($this->configuration()->getWatchdog())
            {
                $container['watchdog'] = $this->configuration()->getWatchdog();
            }
            //bootdisk
            if ($this->configuration()->getBootdisk())
            {
                $container['bootdisk'] = $this->configuration()->getBootdisk();
            }
            //scsihw
            if ($this->configuration()->getScsihw())
            {
                $container['scsihw'] = $this->configuration()->getScsihw();
            }
            //args
            if ($this->configuration()->getArgs())
            {
                $container['args'] = $this->configuration()->getArgs();
            }
            //vga
            $vga=[];
            if ($this->configuration()->getVga())
            {
                $vga[] = $this->configuration()->getVga();
            }
            if($container['vga']!="none" && $this->configuration()->getVgaMemory()){
                $vga[]="memory=".$this->configuration()->getVgaMemory();
            }
            if(!empty($vga)){
                $container['vga'] = implode(",",$vga);
            }
            //xterm.js Console
            if ($this->configuration()->isPermissionXtermjs())
            {
                $container['serial0'] = 'socket';
            }
            //cpu flags

            if ($this->configuration()->hasCpuFlags()  && version_compare($this->api()->getVersion(), "5.2", '>'))
            {
                $container['cpu'] .= ',flags=' .$this->configuration()->getCpuFlagsAsSource();
            }
            //start
            if ($this->configuration()->isStart())
            {
                $container['start'] = 1;
            }
            //bios
            if ($this->configuration()->getBios())
            {
                $container['bios'] = $this->configuration()->getBios();
            }
            //machine
            if ($this->configuration()->getMachine())
            {
                $container['machine'] = $this->configuration()->getMachine();
            }
            //Create
            $nodeService = $this->getWhmcsCustomField(CustomField::NODE)? new Node($this->getWhmcsCustomField(CustomField::NODE)) : $this->getNode();
            $vm          = $nodeService->kvm();
            $this->setVm($vm);
            $taskId = $vm->create($container);
            $this->customFieldUpdate("node", $nodeService->getNode());
            DB::commit();
        }
        catch (\Exception $ex)
        {
            echo $ex->getMessage();
            DB::rollBack();
            Api::commit();
            throw $ex;
        }
        //task history
        $this->createTaskHistory($taskId, "Create");
        //save task id
        $this->putModelDataAndSave(["taskId" => $taskId, "node" => $nodeService->getNode()]);
        //sleep
        $this->sleep();
        return false;
    }


}
