<?php

namespace MGModule\DNSManager2\mgLibs\custom\task;

use \Exception;
use MGModule\DNSManager2\mgLibs\custom\dns\record\Record;
use \MGModule\DNSManager2\mgLibs\custom\manager;
use \MGModule\DNSManager2\mgLibs\custom\manager\DefaultNotifications;
use \MGModule\DNSManager2\mgLibs\custom\manager\EmailNotificationHelper;
use \MGModule\DNSManager2\mgLibs\custom\manager\NotificationHelper;
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\mgLibs\custom\manager\LogHelper;
use MGModule\DNSManager2\models\custom\zone\Repository;
use MGModule\DNSManager2\models\custom\zone\Zone;

class Migration extends TaskAbstract
{
    protected $taskTypeCode = TaskTypeCodesCodes::MIGRATION;
    protected $abort_after_repeats = array('main' => 0);

    public function mainDescription()
    {
        $server_from = new server\Server($this->getParams('from'));
        $server_to = new server\Server($this->getParams('to'));
        return 'Migration from ' . $server_from->name . ' to ' . $server_to->name;
    }

    public function main($params)
    {
        $cron_migrator_run_each = manager\GlobalSettingHelper::getSetting(GlobalSettingEnum::CRON_MIGRATION_RUN_EACH? : 5);

        if(!$this->isReadyToRun( $cron_migrator_run_each ))
        {
            return true;
        }

        LogHelper::addSuccessLog('Cron Migrator', 'Cron Migrator 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_MIGRATION_ZONES_PER_RUN);
            $childs = $this->getXChilds($zones_per_run, 'migrate', task\TaskStatusEnum::START);
            
            if(count($childs) < $zones_per_run)
            {
                $childs += $this->getXChilds($zones_per_run - count($childs), 'migrate');
            }

            $success = array();
            $error = array();
            foreach($childs as $child)
            {
                $child->run();
                if($child->getStatus() === task\TaskStatusEnum::FINISHED)
                {
                    $success[] = $child->getParams('domain');
                }
                else
                {
                    $result = $child->getResults(true);
                    $error[$child->getParams('domain')] = is_null($result)?'Unknown reason':$result->data['error'];
                }
            }
            
            $migrated = count($childs);
            if($migrated > 0)
            {
                $count_success = count($success);
                $count_error = count($error);
                EmailNotificationHelper::sendAdminNotification(
                    DefaultNotifications::ADMIN_CRON_MIGRATOR_NOTIFICATION, 
                    array(
                        'zones_migrated_count' => $migrated,
                        'zones_migrated_successfully_count' => $count_success,
                        'zones_migrated_successfully' => $success,
                        'zones_migrated_unsuccessfully_count' => $count_error,
                        'zones_migrated_unsuccessfully' => $error,
                    )
                );
                
                if($count_success > 0)
                {
                    $this->setFinishedStatusOnCronRun('migrate', $zones_per_run);
                    $zonesCountWord = $count_success == 1 ? 'zone' : 'zones';
                    NotificationHelper::addInfoNotification("Cron Migrator - ".$count_success." ".$zonesCountWord." migrated");
                    LogHelper::addSuccessLog('Cron Migrator', 'End Of Cron Migrator Run - '.$count_success.' '.$zonesCountWord.' migrated'); 
                }
                if((int)$count_error > 0)
                {
                    $zonesCountWord = $count_error == 1 ? 'zone' : 'zones';
                    NotificationHelper::addProblemNotification("Cron Migrator - ".$count_error." ".$zonesCountWord." not migrated");
                    LogHelper::addSuccessLog('Cron Migrator', 'End Of Cron Migrator Run - '.$count_error.' '.$zonesCountWord.' not migrated'); 
                }
            }
        }
        else
        {
            $this->setStatus(task\TaskStatusEnum::FINISHED);
            LogHelper::addSuccessLog('Cron Migrator', 'End Of Cron Migrator Run');        
        }
    }

    public function fetchZonesList($params)
    {
        if($this->isInCliMode())
        {
            LogHelper::addSuccessLog('Cron Migrator', 'Fetching Zones List For Server Id: '.$this->parent->getParams('from').' Started.');            
        } 
        
        $server_from = new server\Server($this->parent->getParams('from'));

        foreach($server_from->getModule()->getZones() as $domain => $ip)
        {
            $this->addResult(array(
                'domain' => $domain,
                'ip' => $ip,
            ));
        }
        
        if($this->isInCliMode())
        {
            LogHelper::addSuccessLog('Cron Migrator', 'Fetching Zones List For Server Id: '.$this->parent->getParams('from').' Started.');            
        }         
    }

    public function migrate($params)
    {
        try
        {
            $server_from = new server\Server($this->parent->getParams('from'));
            $server_to = new server\Server($this->parent->getParams('to'));

            $module_from = $server_from->getModule();
            $module_from->setDomain($params['domain']);

            $module_to = $server_to->getModule();
            $module_to->setDomain($params['domain']);
            if($module_to->isIPRequired())
            {
                $module_to->setIP($params['ip']);
            }

            if(!$module_to->zoneExists())
            {
                $module_to->activateZone();
            }
            //TODO: czy usuwać stare rekordy?
            /** @var Record $record */
            foreach($module_from->getRecords() as $record)
            {
                try
                {
                    $record->nameToAbsolute($params['domain']);
                    $module_to->addRecord($record);
                }
                catch(Exception $exc)
                {
                    //TODO: dodać logi albo uwalić migracje
                    LogHelper::addFailLog('Cron Migrator - Addiing New Record Failed', $exc->getMessage());                     
                }
            }

            /** @var Zone $zone */
            $zone = (new Repository())->byName($params['domain'])->one();

            if( $zone && $this->parent->getParams('move_zone') )
            {
                $zone->serverid = (int)$this->parent->getParams('to');
                $zone->save();
            }

            $this->setStatus(task\TaskStatusEnum::FINISHED);
            $result = TaskManager::getTaskResultByID($this->getParams('resultid'));
            $result->data['status'] = 'migrated';
            $result->save();
            
            LogHelper::addSuccessLog('Cron Migrator - Migration Zone', 'Zone Migrated - '.$params['domain']);            
        }
        catch(Exception $exc)
        {
            $result = TaskManager::getTaskResultByID($this->getParams('resultid'));
            $result->data['status'] = $exc->getMessage();
            $result->save();
            
            LogHelper::addFailLog('Cron Migrator - Migration Failed', $exc->getMessage());             
        }
    }
}
