<?php

namespace ModulesGarden\ProxmoxAddon\App\Jobs\Cloud;

use Illuminate\Database\Capsule\Manager as DB;
use MGProvision\Proxmox\v2\Api;
use MGProvision\Proxmox\v2\models\Kvm;
use MGProvision\Proxmox\v2\models\Lxc;
use MGProvision\Proxmox\v2\ProxmoxApiException;
use ModulesGarden\ProxmoxAddon\App\Enum\Cloud\ConfigurableOption;
use ModulesGarden\ProxmoxAddon\App\Events\Cloud\QemuUpdateEvent;
use ModulesGarden\ProxmoxAddon\App\Events\Cloud\VmCreatedEvent;
use ModulesGarden\ProxmoxAddon\App\Jobs\BaseJob;
use ModulesGarden\ProxmoxAddon\App\Models\TaskHistory;
use ModulesGarden\ProxmoxAddon\App\Models\VmIpAddress;
use ModulesGarden\ProxmoxAddon\App\Services\Cloud\AdditionalDiskService;
use ModulesGarden\ProxmoxAddon\App\Services\Cloud\AgentService;
use ModulesGarden\ProxmoxAddon\App\Services\Cloud\ContainerService;
use ModulesGarden\ProxmoxAddon\App\Services\Cloud\ProductService;
use ModulesGarden\ProxmoxAddon\App\Services\Cloud\UserService;
use ModulesGarden\ProxmoxAddon\App\Services\EmailService;
use function ModulesGarden\ProxmoxAddon\Core\Helper\fire;
use function ModulesGarden\ProxmoxAddon\Core\Helper\sl;

class CloneQemuJob extends BaseJob
{

    use ProductService;
    use UserService;
    /**
     * @var \ModulesGarden\ProxmoxAddon\App\Services\Cloud\ContainerService
     */
    protected $containerService;

    /**
     * @var Kvm|Lxc
     */
    protected $vm;
    /**
     * @var AdditionalDiskService
     */
    protected $additionalDiskService;
    protected function initServices()
    {
        $this->emailService     = new EmailService();
        $this->containerService = new ContainerService();
        $this->agentService = new AgentService();
        $this->additionalDiskService = new AdditionalDiskService();

    }
    public function handle()
    {
        $this->initParams();
        $this->initServices();
        //create task validation
        if ($this->isDone())
        {
            $this->initVm();
            $this->qemuUpdate();
            if ($this->agentUpdate()) {
                fire(new VmCreatedEvent($this->getVmModel()));
                return true;
            }
            return false;
        }
        elseif ($this->isTaskRunning())
        {
            //sleep
            $this->sleep(5);
            return false;
        }
        try
        {
            Api::beginTransaction();
            DB::beginTransaction();
            $osTemplate = $this->getModelData()['osTemplate'];
            //Support for configurable options i.e vmname|OS Name
            if (preg_match('/\//', $osTemplate))
            {
                list($templateNode, $templateVmid) = explode("/", $osTemplate);
            }
            //vmid
            $vmid = $this->nextVmid();
            $this->getVmModel();
            $this->vmModel->vmid = $vmid;
            $this->vmModel->save();
            //init container
            $container = [
                "newid"  => $vmid,
                "full"   => $this->configuration()->getCloneMode(),
                "target" => $this->vmModel->node
            ];
            //description
            $container['description'] = $this->getModelData()['description'];
            //hostname
            $container['name'] = $this->getModelData()['name'];
            //Storage
            if (!$this->configuration()->isCloneOnTheSameStorage() && $this->configuration()->getDiskStorage() && $this->configuration()->getCloneMode() == "1")
            {
                $container['storage'] = $this->configuration()->getDiskStorage();
            }
            if($this->getWhmcsConfigOption(ConfigurableOption::STORAGE_DISK)){
                list($storage,$diskSize) = explode(":", $this->getWhmcsConfigOption(ConfigurableOption::STORAGE_DISK),2);
                $container['storage'] = $storage;
            }
            //pool
            if ($this->configuration()->getPool())
            {
                $container['pool'] = $this->configuration()->getPool();
            }
            //bwlimit
            if($this->configuration()->getBwLimit()){
                $container['bwlimit'] = $this->configuration()->getBwLimit();
            }
            //Create
            $template = new Kvm($templateNode, $templateVmid);
            $template->setApi($this->api());
            $taskId = $template->cloneVm($container);
            DB::commit();
        }
        catch (\Exception $ex)
        {
            DB::rollBack();
            Api::commit();
            $this->failed($ex->getMessage());
            throw $ex;
        }
        //task history
        $task = new TaskHistory();
        $task->fill([
            'hosting_id' => $this->getWhmcsParamByKey("serviceid"),
            'upid'       => $taskId,
            'name'       => sprintf("VM %s - %s", $vmid, "Clone"),
            'vmid'       => $template->getVmid(),
            'node'       => $template->getNode(),
            'status'     => 0
        ])->save();
        //save task id
        $this->putModelDataAndSave(["taskId" => $taskId, "node" => $template->getNode(), "templateNode" => $templateNode]);
        //sleep
        $this->sleep();
        return false;
    }

    private function  deleteNetwork(){

        $deleteNetwork = [];
        foreach (sl('Vm')->getVm()->getNetworkDevices() as $networkDevice){
            if(VmIpAddress::ofHostingId($this->getWhmcsParamByKey('serviceid'))
                           ->ofNet($networkDevice->getId())
                          ->ofVmId(sl('Vm')->getVmModel()->id)
                          ->count()){
                continue;
            }
            $deleteNetwork[]=$networkDevice->getId();
        }
        if(!empty($deleteNetwork)){
            sl('Vm')->getVm()->deleteConfig(implode(",",$deleteNetwork));
        }
    }

    protected function qemuUpdate(){
        if(!sl('Vm')->getVm()->isRunning()){
            $this->deleteNetwork();
        }
        if($this->getModelData()['additionalDiskSize1'] && !$this->additionalDiskService->hasDisk()){
            $this->additionalDiskService->create($this->getModelData());
        }
        fire(new QemuUpdateEvent($this->getVmModel(), $this->getModelData()));
    }

    protected function agentUpdate(){
        try{

            if($this->agentService->isEnabled()){
                if(!sl('Vm')->getVm()->isRunning()){
                    $this->log->info(sprintf("VM %s - Start", sl('Vm')->getVm()->getVmid()));
                    sl('Vm')->getVm()->start();
                    $this->sleep(5);
                    return false;
                }
                sl('Vm')->getVm()->agent()->ping();
                $this->agentService ->passwordUpdate();
                $this->agentService ->configureNetwork();
            }
            return true;
        }catch (ProxmoxApiException $ex){
            if(preg_match("/not running/", $ex->getMessage())){
                $this->log->info($ex->getMessage());
            }else{
                $this->log->error($ex->getMessage());
            }
            //sleep
            $this->sleep(5);
            return false;
        }
    }

}
