<?php


namespace ModulesGarden\ProxmoxAddon\App\Services;


use MGProvision\Proxmox\v2\ProxmoxApiException;
use MGProvision\Proxmox\v2\repository\BackupScheduleRepository;
use MGProvision\Proxmox\v2\repository\FileRepository;
use MGProvision\Proxmox\v2\repository\FirewallRulesRepository;
use MGProvision\Proxmox\v2\VmFactory;
use ModulesGarden\ProxmoxAddon\App\Models\IpAddress;
use ModulesGarden\ProxmoxAddon\App\Models\KeyPair;
use ModulesGarden\ProxmoxAddon\App\Models\TaskHistory;
use ModulesGarden\ProxmoxAddon\App\Models\VirtualInterface;
use ModulesGarden\ProxmoxAddon\App\Models\VmIpAddress;
use ModulesGarden\ProxmoxAddon\App\Models\VmModel;
use ModulesGarden\ProxmoxAddon\App\Services\Cloud\HighAvailabilityClusterService;
use ModulesGarden\ProxmoxAddon\App\Services\Cloud\NetworkService;
use ModulesGarden\ProxmoxAddon\App\Services\Cloud\ProductService;
use ModulesGarden\ProxmoxAddon\App\Services\Cloud\ResourceManager;
use ModulesGarden\ProxmoxAddon\App\Traits\Cloud\SnippetTrait;
use ModulesGarden\ProxmoxAddon\Core\Queue\Models\Job;
use ModulesGarden\ProxmoxAddon\Core\UI\Traits\WhmcsParams;
use function ModulesGarden\ProxmoxAddon\Core\Helper\sl;

class CloudService
{
    use ProductService;
    use WhmcsParams;
    use ApiService;
    use SnippetTrait;

    protected $networkService;
    protected $highAvailabilityClusterService;
    /**
     * @var ResourceManager
     */
    protected $resourceManager;

    /**
     * CloudService constructor.
     */
    public function __construct()
    {
        $this->networkService = new NetworkService();
        $this->highAvailabilityClusterService = new HighAvailabilityClusterService();
    }



    /**
     * @return VmModel[]
     */
    public function getVmModels(){
        return VmModel::ofHostingId($this->getWhmcsParamByKey('serviceid'))->get();
    }

    public function getVmModelWithVmid(){
        return VmModel::ofHostingId($this->getWhmcsParamByKey('serviceid'))->notVmid(0)->get();
    }
    /**
     * @return array
     */
    public function getVmids(){
        return VmModel::ofHostingId($this->getWhmcsParamByKey('serviceid'))
            ->notVmid('0')
            ->pluck('vmid')
            ->toArray();
    }

    public function destroy(){
        foreach ($this->getVmModels() as $vmModel){
            $this->delete($vmModel);
        }
        $ipunassigned = VmIpAddress::ofHostingId($this->getWhmcsParamByKey('serviceid'))->pluck('ip')->toArray();
        if(!empty( $ipunassigned)){
            (new IpLogService())->unassigned($ipunassigned);
        }
        VmIpAddress::ofHostingId($this->getWhmcsParamByKey('serviceid'))->delete();
        IpAddress::ofHostingId($this->getWhmcsParamByKey('serviceid'))
            ->update(["hosting_id" => 0]);
    }

    public function delete(VmModel $vmModel){
        //Cron delete active jobs
        $this->cancellJobs($vmModel->id);
        sl('Vm')->setVmModel($vmModel);
        //Unassing IP
        $this->networkService->deleteIpAddresses();
        if($vmModel->vmid == 0){
            $vmModel->delete();
            return;
        }
        //init api
        $this->api();
        //init vm
        sl('Vm')->setVm((new VmFactory())->fromVmModel($vmModel));
        //Delete HA
        if ($this->highAvailabilityClusterService->exist())
        {
                $this->highAvailabilityClusterService->delete();
        }
        try{
            //Stop VM
            if (sl('Vm')->getVm()->isRunning())
            {
                sl('Vm')->getVm()->stop();
                sleep(4);
            }
            //VM Protection LXC
            if (sl('Vm')->getVm() instanceof Lxc && sl('Vm')->getVm()->config()['protection'] == "1")
            {
                sl('Vm')->getVm()->protectionOff();

            }
        } catch (ProxmoxApiException $ex) {
            //Configuration file 'nodes/proxmox4/qemu-server/105.conf' does not exist
            if (!preg_match("/Configuration file/", $ex->getMessage()) && !preg_match("/does not exist/", $ex->getMessage())) {
                throw $ex;
            }
        }
        //virtual interfaces delete
        VirtualInterface::ofHostingId($this->getWhmcsParamByKey("serviceid"))->ofVmId($vmModel->id)->delete();
        //key pair delete
        KeyPair::ofHostingId($this->getWhmcsParamByKey("serviceid"))->ofVmId($vmModel->id)->delete();

        //Destroy firewall rules
        if (version_compare($this->api()->getVersion(), "3.2", '>'))
        {
            $rules = new FirewallRulesRepository();
            $rules->findByVm(sl('Vm')->getVm())
                ->delete();
        }
        //Destroy Backups
        $storage        = $this->configuration()->getBackupStorage() ? $this->configuration()->getBackupStorage() : 'local';
        $fileRepository = new FileRepository();
        $fileRepository->findBackup(sl('Vm')->getVm())
            ->findByStorages([$storage])
            ->delete();
        //Destroy Backup Jobs
        $schedule = new BackupScheduleRepository();
        $schedule->findByVm(sl('Vm')->getVm());
        $schedule->delete();

        //Destroy VM
        try {
            $upid = sl('Vm')->getVm()->delete();
            //Create Task History
            $type = str_replace(["qemu", "lxc"], ["VM", "CT"], sl('Vm')->getVm()->getVirtualization());
            $task = new TaskHistory();
            $task->fill([
                'hosting_id' => $this->getWhmcsParamByKey("serviceid"),
                'upid'       => $upid,
                'name'       => sprintf("%s %s - %s", $type, sl('Vm')->getVm()->getVmid(), "Delete"),
                'vmid'       => sl('Vm')->getVm()->getVmid(),
                'node'       => sl('Vm')->getVm()->getNode(),
                'status'     => 0
            ])->save();
        } catch (ProxmoxApiException $ex) {
            //Configuration file 'nodes/proxmox4/qemu-server/105.conf' does not exist
            if (!preg_match("/Configuration file/", $ex->getMessage()) && !preg_match("/does not exist/", $ex->getMessage())) {
                throw $ex;
            }
        }
        //delete vmModel
        $vmModel->delete();
        if($this->hasSnippet() &&  $files = $this->getSnippetFiles($vmModel)){
            foreach ($files as $file){
                $file->delete();
            }
        }
    }

    public function cancellJobs($customId){
        Job::whereIn("status", ['waiting', "running", "", "error"])
            ->where("rel_id", $this->getWhmcsParamByKey("serviceid"))
            ->where("rel_type", "hosting")
            ->where("custom_id", $customId)
            ->update(["status" => 'cancelled']);
    }
}