<?php

namespace MGModule\DNSManager2\mgLibs\custom\task;

use \Exception;
use MGModule\DNSManager2\mgLibs\custom\helpers\IdnaHelper;
use \MGModule\DNSManager2\mgLibs\custom\manager;
use \MGModule\DNSManager2\mgLibs\custom\TaskManager;
use \MGModule\DNSManager2\models\custom\globalsetting\GlobalSettingEnum;
use \MGModule\DNSManager2\models\custom\server;
use \MGModule\DNSManager2\models\custom\task;
use \MGModule\DNSManager2\models\custom\zone\Zone;
use \MGModule\DNSManager2\models\custom\zone\Repository as ZoneRepo;
use \MGModule\DNSManager2\mgLibs\custom\manager\LogHelper;
use \MGModule\DNSManager2\mgLibs\custom\task\TaskTypeCodesCodes;
use \MGModule\DNSManager2\mgLibs\custom\dns\utils\ReverseDNSHelper;
use \MGModule\DNSManager2\models\custom\reverse\Reverse;
use \MGModule\DNSManager2\models\custom\reverse\Repository as ReverseRepo;
use MGModule\DNSManager2\mgLibs\custom\manager\GlobalSettingHelper;
use MGModule\DNSManager2\mgLibs\custom\helpers\datatable\Import as Importer;

class Import extends TaskAbstract
{
    protected $abort_after_repeats = array('main' => 0);
    protected $taskTypeCode = TaskTypeCodesCodes::IMPORT;
    
    public function mainDescription()
    {
         $server_from = new server\Server($this->getParams('from'));
         return 'Import from: ' . $server_from->name;
    }
    
    public function main($params)
    {
        $cron_import_run_each = manager\GlobalSettingHelper::getSetting(GlobalSettingEnum::CRON_IMPORT_RUN_EACH?:5);

        if(!$this->isReadyToRun( $cron_import_run_each ))
        {
            return true;
        }
        
        LogHelper::addSuccessLog('Cron Importer', 'Cron Importer Started');
        
        if($this->getStatus() == task\TaskStatusEnum::START)
        {
            $this->addChild('fetchZonesList')->run();
            $this->setStatus(task\TaskStatusEnum::IN_PROGRESS);
        }
        elseif($this->getStatus() == task\TaskStatusEnum::IN_PROGRESS)
        {
            $zones_per_run = manager\GlobalSettingHelper::getSetting(GlobalSettingEnum::CRON_IMPORT_ZONES_PER_RUN);
            
            $childs = $this->getXChilds($zones_per_run, 'import', task\TaskStatusEnum::START);

            if(count($childs) < $zones_per_run)
            {
                $childs += $this->getXChilds($zones_per_run - count($childs), 'import');
            }
            
            foreach($childs as $child) 
            {
                LogHelper::addSuccessLog('Cron Importer', 'Child task ran ' . get_class($child));
                $child->run();
            }
            
            $this->setFinishedStatusOnCronRun('import', $zones_per_run);
        }
        
        LogHelper::addSuccessLog('Cron Importer', 'End Of Cron Importer Run');
    }
    
    public function fetchZonesList($params)
    {
        if($this->isInCliMode())
        {
            LogHelper::addSuccessLog('Cron Importer', 'Fetching Zones List For Server Id: '.$this->parent->getParams('from').' Started.');            
        }          
        
        $server_from = new server\Server($this->parent->getParams('from'));

        $importHelper = new Importer();
        $rep = $importHelper->getNeeded($server_from->getModule()->getZones());

        foreach($rep as $domain => $ip)
        {
            if(ZoneRepo::factory()->byServerID($server_from->id)->byName(IdnaHelper::idnaDecode($domain))->one() === FALSE)
            {
                $this->addResult(array(
                    'domain' => IdnaHelper::idnaDecode($domain),
                    'ip' => $ip,
                ));
            }
        }

        $this->setStatus(task\TaskStatusEnum::FINISHED);
        if($this->isInCliMode())
        {
            LogHelper::addSuccessLog('Cron Importer', 'Fetching Zones List For Server Id: '.$this->parent->getParams('from').' Completed.');            
        }
    }
    
    public function import($params)
    {
        if(strpos($params['domain'], '.arpa') !== FALSE)
        {
            $this->importRDNS($params);
            return;
        }
        
        try
        {
            $server_from = new server\Server($this->parent->getParams('from'));

            $module_from = $server_from->getModule();
            $module_from->setDomain(IdnaHelper::idnaDecode($params['domain']));
            if($module_from->isIPRequired())
            {
                $module_from->setIP($params['ip']);
            }

            $zone = new Zone();
            $zone->clientid = $this->getParams('clientid');
            $zone->type = $this->getParams('type');
            $zone->relid = $this->getParams('relid');
            $zone->name = IdnaHelper::idnaDecode($this->getParams('domain'));
            $zone->ip = $this->getParams('ip');
            $zone->serverid = $server_from->id;
            $zone->status = 1;

            if(!$module_from->zoneExists())
            {
                $zone->status = 0;
            }

            $zone->save();

            $this->setStatus(task\TaskStatusEnum::FINISHED);

            $result = TaskManager::getTaskResultByID($this->getParams('resultid'));
            $result->data['status'] = 'imported';
            $result->save();
            
            LogHelper::addSuccessLogUsingZone('Cron Importer - Import Zone', 'Zone Imported', $zone);            
        }
        catch(Exception $exc)
        {
            $result = TaskManager::getTaskResultByID($this->getParams('resultid'));
            $result->data['status'] = 'error';
            $result->save();
            
            LogHelper::addFailLog('Cron Importer - Import Failed', $exc->getMessage());
        }
    }
    
    public function importRDNS($params)
    { 
        try
        {
            $server = new server\Server($this->parent->getParams('from'));
            $module = $server->getModule();
            $module->setDomain($params['domain']);
            $ptrs = [];
            foreach($module->getRecords() as $record)
            {
                if($record->type == 'PTR')
                {
                    $ptrs[] = $record;
                }
            }
            
            if(!$ptrs)
            {
                throw new \MGModule\DNSManager2\mgLibs\custom\dns\exceptions\DNSException(sprintf('%s : Cannot find any ptr record.', $params['domain']));
            }
            
            if(strpos($params['domain'], 'ip6') !== false)
            {
                $this->importRDNSv6($params,$ptrs);
                return;
            }
            
            foreach($ptrs as $ptr)
            {
                $reverseHelper  = ReverseDNSHelper::buildReverseFromARPA($ptr,$params['domain']);
                $zone           = ZoneRepo::factory()->setFilter('name', $reverseHelper['from'])->setFilter('clientid', $params['clientid'])->get();
                if(!$zone && ((int)$params['type'] != 0 && (int)$params['relid'] != 0))
                {
                    throw new \MGModule\DNSManager2\mgLibs\custom\dns\exceptions\DNSException($reverseHelper['from'] . ' : Cannot be imported');
                }
                
               	if(ReverseRepo::factory()->byServerID($server->id)->byIP($reverseHelper['ip'])->get())
               	{
                    LogHelper::addFailLog('Cron Importer - Import Failed', $params['domain'] . ' - ' . $reverseHelper['ip'] . ' already exists.');
                    continue;
               	}

                $reverse            = new Reverse;
                $reverse->serverid  = $server->id;
                $reverse->clientid  = $params['clientid'];
                $reverse->from      = $reverseHelper['from'];
                $reverse->sub       = '';
                //$reverse->name      = $params['domain'];
                $reverse->name      = ReverseDNSHelper::reverseZoneName($reverseHelper['ip']);
                $reverse->ip        = $reverseHelper['ip'];
                $reverse->ttl       = $reverseHelper['ttl'];
                $reverse->created_at= date('Y-m-d H:i:s');
                $reverse->save();   
            }                
            
            $this->setStatus(task\TaskStatusEnum::FINISHED);
            $result = TaskManager::getTaskResultByID($this->getParams('resultid'));
            $result->data['status'] = 'imported';
            $result->save();
            
            LogHelper::addSuccessLogUsingZone('Cron Importer - Import Zone', 'Zone Imported', $zone);   
                
        } 
        catch (Exception $ex) 
        {
            $result = TaskManager::getTaskResultByID($this->getParams('resultid'));
            $result->data['status'] = 'error';
            $result->save();
            
            LogHelper::addFailLog('Cron Importer - Import Failed', $ex->getMessage());
        }
    }
    
    public function importRDNSv6($params,$ptrs)
    {
        try
        {
            $server = new server\Server($this->parent->getParams('from'));
            
            foreach($ptrs as $ptr)
            {
                $zone = ZoneRepo::factory()->setFilter('name', $ptr->rdata->ptrdname)->setFilter('clientid', $params['clientid'])->get();
                if(!$zone && ((int)$params['type'] != 0 && (int)$params['relid'] != 0))
                {
                    throw new \MGModule\DNSManager2\mgLibs\custom\dns\exceptions\DNSException($ptr->rdata->ptrdname . ' : Cannot be imported');
                }
                
                $ipv6 = ReverseDNSHelper::fromIP6Arpa($params['domain'],$ptr->name);
               	if(ReverseRepo::factory()->byServerID($server->id)->byIP($ipv6)->get())
               	{
                    LogHelper::addFailLog('Cron Importer - Import Failed', $params['domain'] . ' - ' . $ipv6 . ' already exists.');
                    continue;
               	}
                
                $reverse            = new Reverse;
                $reverse->serverid  = $server->id;
                $reverse->clientid  = $params['clientid'];
                $reverse->from      = $ptr->rdata->ptrdname;
                $reverse->sub       = '';
                $reverse->name      = IdnaHelper::idnaDecode($params['domain']);
                $reverse->ip        = $ipv6;
                $reverse->ttl       = $ptr->ttl;
                $reverse->created_at= date('Y-m-d H:i:s');
                $reverse->save();    
            }
            
            $this->setStatus(task\TaskStatusEnum::FINISHED);
            $result = TaskManager::getTaskResultByID($this->getParams('resultid'));
            $result->data['status'] = 'imported';
            $result->save();      
        } 
        catch (Exception $ex) 
        {
            $result = TaskManager::getTaskResultByID($this->getParams('resultid'));
            $result->data['status'] = 'error';
            $result->save();
            
            LogHelper::addFailLog('Cron Importer - Import Failed', $ex->getMessage());            
        }
        
    }
}
