<?php

namespace MGModule\DNSManager2\mgLibs\custom\task;

use \Exception;
use \MGModule\DNSManager2 as main;
use \MGModule\DNSManager2\mgLibs\custom\helpers\TimeDiffHelper;
use \MGModule\DNSManager2\mgLibs\custom\helpers\StatusHelper;
use \MGModule\DNSManager2\mgLibs\custom\manager\DefaultNotifications;
use \MGModule\DNSManager2\mgLibs\custom\manager\EmailNotificationHelper;
use \MGModule\DNSManager2\mgLibs\custom\manager\GlobalSettingHelper;
use \MGModule\DNSManager2\mgLibs\custom\manager\NotificationHelper;
use \MGModule\DNSManager2\models\custom\globalsetting\GlobalSettingEnum;
use \MGModule\DNSManager2\mgLibs\custom\manager\LogHelper;
use \MGModule\DNSManager2\mgLibs\custom\task\TaskTypeCodesCodes;
use \MGModule\DNSManager2\models\custom\task;

class Synchronization extends TaskAbstract
{
    protected $abort_after_repeats = array('main' => 0);
    protected $taskTypeCode = TaskTypeCodesCodes::SYNCHRONISATION;
    
    public function mainDescription()
    {
        return 'Synchronizator';
    }

    public function main($params)
    {
        $this->setStatus(task\TaskStatusEnum::IN_PROGRESS);
        $diff = TimeDiffHelper::diff(GlobalSettingHelper::getSetting(GlobalSettingEnum::CRON_SYNC_LAST_RUN)?:'1991-12-19');
        $cron_sync_run_each = GlobalSettingHelper::getSetting(GlobalSettingEnum::CRON_SYNC_RUN_EACH?:5);
        
        if(!$this->isReadyToRun( $cron_sync_run_each )) {
            return true;
        }
        
        LogHelper::addSuccessLog('Cron Sync', 'Sync Started');
        
        $last_id = GlobalSettingHelper::getSetting(GlobalSettingEnum::CRON_SYNC_LAST_ID)?:0;
        $zones_per_run = GlobalSettingHelper::getSetting(GlobalSettingEnum::CRON_SYNC_ZONES_PER_RUN);
        $zones_per_run<1?$zones_per_run=1:'';
        
        $rep = $this->getZonesRepoWithIDGreaterThan($last_id,$zones_per_run);
        $count_filtered = $rep->count();
        
        $count_synchronized = 0;
        $details = array();
        $notify_only = GlobalSettingHelper::getSetting(GlobalSettingEnum::CRON_SYNC_NOTIFY_ONLY);
        $notify_only = ($notify_only === 'on' || $notify_only === false);

        /** @var main\models\custom\zone\Zone $zone */
        foreach($rep->get() as $zone)
        {
            try
            {
                /** @var main\models\custom\server\Server $server */
                $server = $zone->getServer();
                $nameservers = $server->getModule()->getNameservers();
                $ns_records = $zone->getModule()->getRecords('NS');

                $domain_ns_records  = (new StatusHelper($zone->id))->getNameservers();

                foreach($nameservers as $nameserver)
                {
                    if(!empty($nameserver->name) || !empty($nameserver->ip))
                    {
                        $value = empty($nameserver->name) ? $nameserver->ip : $nameserver->name;
                        foreach($ns_records as $record)
                        {
                            if(trim($record->rdata->__toString(), '.') == trim($value, '.'))
                            {
                                continue 2;
                            }
                        }
                        
                        foreach($domain_ns_records as $record)
                        {
                            if(trim($record, '.') == trim($value, '.'))
                            {
                                continue 2;
                            }
                        }

                        if(!$this->checkIfZoneStillActive($zone->id))
                        {
                            continue;
                        }
                        
                        $count_synchronized++;
                        $details[] = $zone->name;
                        if(!$notify_only)
                        {
                            try
                            {
                                $zone->getModule()->terminateZone();
                                $this->updateZone($zone);
                            }
                            catch(Exception $exc)
                            {
                                LogHelper::addFailLogUsingZone('Cron Sync - Terminate Zone', $exc->getMessage(), $zone);
                            }
                            LogHelper::addSuccessLogUsingZone('Cron Sync - Terminate Zone', '', $zone);
                        }
                    }
                }
            }
            catch(Exception $exc)
            {
                
            }

            try{
                if($zone->getModule()->zoneExists())
                {
                    $zone->setThatExist();
                }
                else
                {
                    $zone->setThatNotExist();
                }
            }
            catch(Exception $exc)
            {
                LogHelper::addFailLogUsingZone('Cron Sync - Set Zone Status', $exc->getMessage(), $zone);
            }

        }
        
        if($count_filtered < $zones_per_run)
        {
            $last_id = 0;
        }
        
        GlobalSettingHelper::setSetting(GlobalSettingEnum::CRON_SYNC_LAST_ID, $last_id);
        
        if($count_synchronized > 0)
        {
            EmailNotificationHelper::sendAdminNotification(
                    DefaultNotifications::ADMIN_CRON_SYNCHRONIZATOR_NOTIFIACTION, 
                    array(
                        'notify_only' => $notify_only,
                        'zones_synchronized_count' => $count_synchronized,
                        'zones_synchronized' => $details,
                    )
            );
 
            $zonesCountWord = $count_synchronized == 1 ? 'zone' : 'zones';
            if($notify_only)
            {
                NotificationHelper::addInfoNotification("Cron Synchronization - ".$count_synchronized." ".$zonesCountWord." should be synchronized");
                LogHelper::addSuccessLog('Cron Sync', "End Of Sync Run - ".$count_synchronized." ".$zonesCountWord." should be synchronized");
            }
            else
            {
                NotificationHelper::addInfoNotification("Cron Synchronization - ".$count_synchronized." ".$zonesCountWord." synchronized");
                LogHelper::addSuccessLog('Cron Sync', "End Of Sync Run - ".$count_synchronized." ".$zonesCountWord." zones synchronized");
            }
        }
        else
        {
            LogHelper::addSuccessLog('Cron Sync', "End Of Sync Run");
        }
//        $this->setStatus(task\TaskStatusEnum::FINISHED);
    }
    
    private function getZonesRepoWithIDGreaterThan($id, $zones_per_run)
    {
        $rep = new main\models\custom\zone\Repository();
        $rep->setFilter(0, array(
            'customQuery' => 'id > :last_id ',
            'params' => array('last_id' => $id)
        ));
        $rep->limit($zones_per_run);
        
        return $rep;
    }
    
    private function checkIfZoneStillActive($zoneId)
    {
        $repo = new main\models\custom\zone\Repository();
        $repo->byId($zoneId);
        
        $zone = $repo->one();
        if(!$zone)
        {
            return false;
        }

        return $zone->status === '1';
    }
    
    private function updateZone($zone)
    {
        if($zone->getModule()->zoneExists())
        {
            $zone->setThatExist();
        }
        else
        {
            $zone->setThatNotExist();
        }        
    }
}