<?php

namespace FiloBlu\ActiveCampaign\Model;

use FiloBlu\ActiveCampaign\Api\Data\JobsInterface;
use FiloBlu\ActiveCampaign\Api\JobsRepositoryInterface;
use FiloBlu\ActiveCampaign\Helper\Data;
use FiloBlu\ActiveCampaign\Model\Config\Source\DirectionType;
use FiloBlu\ActiveCampaign\Model\Config\Source\EntityType;
use FiloBlu\ActiveCampaign\Model\Config\Source\JobStatus;
use FiloBlu\ActiveCampaign\Model\Config\Source\Type;
use Magento\Framework\ObjectManagerInterface;
use Magento\Setup\Exception;
use Psr\Log\LoggerInterface;

class JobManager {

    /**
     * CONSTANTS
     */
    const CONSOLE_ERROR = "error";
    const CONSOLE_INFO = "info";
    /**
     * @var LoggerInterface
     */
    protected $logger;
    /**
     * @var ObjectManagerInterface
     */
    protected $objectManager;
    /**
     * @var Data
     */
    protected $helperData;
    /**
     * @var array
     */
    protected $entityPool;
    /**
     * @var array
     */
    protected $connectorPool;
    /**
     * @var array
     */
    protected $writerPool;
    /**
     * @var mixed
     */
    protected $entity;
    /**
     * @var string
     */
    protected $direction = DirectionType::DIRECTION_EXPORT;
    /**
     * @var mixed
     */
    protected $entityObject;
    /**
     * @var string
     */
    protected $type = Type::TYPE_REST;
    /**
     * @var string
     */
    protected $exportType = JobsInterface::INCREMENTAL;
    /**
     * @var
     */
    protected $statusToProcess = JobStatus::JOB_STATUS_WAITING;
    /**
     * @var
     */
    protected $statusToPrepare = JobStatus::JOB_STATUS_WAITING;


    /**
     * @var JobsRepositoryInterface
     */
    protected $jobsRepository;

    /**
     * JobManager constructor.
     * @param LoggerInterface $logger
     * @param ObjectManagerInterface $objectManager
     * @param Data $helperData
     * @param JobsRepositoryInterface $jobsRepository
     * @param array $entityPool
     * @param array $connectorPool
     * @param array $writerPool
     */
    public function __construct(
        LoggerInterface $logger,
        ObjectManagerInterface $objectManager,
        Data $helperData,
        JobsRepositoryInterface $jobsRepository,
        $entityPool = []
    ) {
        $this->logger = $logger;
        $this->objectManager = $objectManager;
        $this->helperData = $helperData;
        $this->entityPool = $entityPool;
        $this->jobsRepository = $jobsRepository;
    }

    /**
     * @param $entity
     * @return $this
     */
    public function setEntity($entity): JobManager
    {
        $this->entity = $entity;
        $this->entityObject = $this->objectManager->create($this->entityPool[$this->direction][$entity]);
        return $this;
    }

    /**
     * @param $direction
     * @return $this
     */
    public function setDirection($direction): JobManager
    {
        $this->direction = $direction;
        return $this;
    }

    /**
     * @param $type
     * @return $this
     */
    public function setType($type): JobManager
    {
        $this->type = $type;
        return $this;
    }

    /**
     * @param $exportType
     * @return $this
     */
    public function setExportType($exportType): JobManager
    {
        $this->exportType = $exportType;
        return $this;
    }

    /**
     * @param $statusToProcess
     * @return $this
     */
    public function setStatusToProcess($statusToProcess): JobManager
    {
        $this->statusToProcess = $statusToProcess;
        return $this;
    }

    /**
     * @param $statusToProcess
     * @return $this
     */
    public function setStatusToPrepare($statusToPrepare): JobManager
    {
        $this->statusToPrepare = $statusToPrepare;
        return $this;
    }

    /**
     * Prepare Jobs
     * @return array|string[]
     */
    public function prepare(): array
    {
        try {
            if(!$this->helperData->isEnabled()){
                return [self::CONSOLE_INFO, 'ActiveCampaign module is disabled'];
            }
            if($this->exportType === JobsInterface::FULL){
                $this->entityObject->updateJobs([JobsInterface::STATUS => JobStatus::JOB_STATUS_BULK_WAITING, JobsInterface::TYPE => $this->type]);
            }
            $ids = $this->entityObject->setType($this->type)->setStatusToPrepare($this->statusToPrepare)->prepare();
            $string = count($ids)." jobs prepared for ".$this->entity;
            if($this->exportType === JobsInterface::FULL){
                $string = "all jobs prepared for ".$this->entity;
            }
            return [self::CONSOLE_INFO, $string];
        } catch (Exception $exception) {
            $this->logger->error($exception->getMessage());
            return [self::CONSOLE_ERROR, $exception->getMessage()];
        } catch (Throwable $throwable) {
            $this->logger->error($throwable->getMessage());
            return [self::CONSOLE_ERROR, $throwable->getMessage()];
        }
    }

    /**
     * @return array|string[]
     */
    public function process(): array
    {
        try {
            if(!$this->helperData->isEnabled()){
                return [self::CONSOLE_INFO, 'ActiveCampaign module is disabled'];
            }
            list($success,$error) = $this->entityObject->setType($this->type)->setStatusToProcess($this->statusToProcess)->process();
            $string = '';
            if((int)$success > 0) {
                $string .= $success.' jobs processed ';
            }
            if((int)$error > 0) {
                $string .= $error.' jobs in error ';
            }
            if(empty($string)) {
                $string .= '0 jobs processed ';
            }
            return [self::CONSOLE_INFO, $string."for ".$this->entity];
        } catch (Exception $exception) {
            $this->logger->error($exception->getMessage());
            return [self::CONSOLE_ERROR, $exception->getMessage()];
        } catch (Throwable $throwable) {
            $this->logger->error($throwable->getMessage());
            return [self::CONSOLE_ERROR, $throwable->getMessage()];
        }
    }

    /**
     * @param $toStatus
     * @param string $fromStatus
     * @param string $entity
     * @return array|string[]
     */
    public function reset($toStatus,$fromStatus='',$entity='') {
        try {
            if(!$this->helperData->isEnabled()){
                return [self::CONSOLE_INFO, 'ActiveCampaign module is disabled'];
            }

            if(!in_array($toStatus, JobStatus::JOB_STATUS_AVAILABLE)){
                throw new Exception($toStatus.' (status to) cannot be set. Please chose between ['.implode(',',JobStatus::JOB_STATUS_AVAILABLE).']');
            }

            if($toStatus == $fromStatus) {
                throw new Exception('From status and to status cannot be equal');
            }

            $updateArray = [JobsInterface::STATUS => $toStatus];
            $where = [];
            $appendString = '';
            if(!empty($fromStatus)){
                if(!in_array($fromStatus, JobStatus::JOB_STATUS_AVAILABLE)){
                    throw new Exception($fromStatus.' (status from) cannot be set. Please chose between ['.implode(',',JobStatus::JOB_STATUS_AVAILABLE).']');
                }
                $where[JobsInterface::STATUS] = $fromStatus;
                $appendString .= ' from status '.$fromStatus;
            }
            if(!empty($entity)){
                if(!in_array($entity, EntityType::ENTITY_AVAILABLE)){
                    throw new Exception($entity.' (entity) cannot be set. Please chose between ['.implode(',',EntityType::ENTITY_AVAILABLE).']');
                }
                $where[JobsInterface::ENTITY] = $entity;
                $appendString .= ' to entity '.$entity;
            }
            $this->jobsRepository->updateJobs($updateArray,$this->helperData->arrayToWhereString($where));
            return [self::CONSOLE_INFO, 'Jobs setted to status '.$toStatus.$appendString];
        } catch (Exception $exception) {
            $this->logger->error($exception->getMessage());
            return [self::CONSOLE_ERROR, $exception->getMessage()];
        } catch (Throwable $throwable) {
            $this->logger->error($throwable->getMessage());
            return [self::CONSOLE_ERROR, $throwable->getMessage()];
        }
    }


}