<?php

namespace FiloBlu\ActiveCampaign\Model;

use FiloBlu\ActiveCampaign\Api\Data\JobsInterface;
use FiloBlu\ActiveCampaign\Api\Data\JobsInterfaceFactory;
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 Magento\Framework\App\ResourceConnection;
use Magento\Framework\Exception\NoSuchEntityException;
use Magento\Framework\Phrase;
use Zend_Db;

/**
 * Class JobsRepository
 * @package FiloBlu\ActiveCampaign\Model
 */
class JobsRepository implements JobsRepositoryInterface
{
    /**
     * @var JobsInterfaceFactory
     */
    protected $jobsFactory;
    /**
     * @var ResourceConnection
     */
    protected $resourceConnection;
    /**
     * @var Data
     */
    protected $helperData;

    /**
     * JobsRepository constructor.
     * @param ResourceConnection $resourceConnection
     * @param JobsInterfaceFactory $jobsFactory
     * @param Data $helperData
     */
    public function __construct(
        ResourceConnection $resourceConnection,
        JobsInterfaceFactory $jobsFactory,
        Data $helperData
    ) {
        $this->jobsFactory = $jobsFactory;
        $this->resourceConnection = $resourceConnection;
        $this->helperData = $helperData;
    }

    /**
     * @param JobsInterface $jobs
     * @return mixed|void
     */
    public function save(JobsInterface $jobs)
    {
        $connection = $this->resourceConnection->getConnection();
        $table = $connection->getTableName(JobsInterface::DB_TABLE);
        $connection->insertOnDuplicate(
            $table,
            [
                JobsInterface::ID => $jobs->getId(),
                JobsInterface::TYPE => $jobs->getType(),
                JobsInterface::DIRECTION => $jobs->getDirection(),
                JobsInterface::ENTITY => $jobs->getEntity(),
                JobsInterface::ENTITY_ID => $jobs->getEntityId(),
                JobsInterface::REQUEST => $jobs->getRequest(),
                JobsInterface::RESPONSE => $jobs->getResponse(),
                JobsInterface::STATUS => $jobs->getStatus(),
                JobsInterface::LOG => $jobs->getLog()
            ],
            [
                JobsInterface::STATUS,
                JobsInterface::LOG
            ]
        );

        $id = $connection->lastInsertId();
        $jobs->setId($id);
    }

    /**
     * @param JobsInterface $jobs
     * @return mixed|void
     */
    public function saveWithRequest(JobsInterface $jobs)
    {
        $connection = $this->resourceConnection->getConnection();
        $table = $connection->getTableName(JobsInterface::DB_TABLE);
        $connection->insertOnDuplicate(
            $table,
            [
                JobsInterface::ID => $jobs->getId(),
                JobsInterface::TYPE => $jobs->getType(),
                JobsInterface::DIRECTION => $jobs->getDirection(),
                JobsInterface::ENTITY => $jobs->getEntity(),
                JobsInterface::ENTITY_ID => $jobs->getEntityId(),
                JobsInterface::REQUEST => $jobs->getRequest(),
                JobsInterface::RESPONSE => $jobs->getResponse(),
                JobsInterface::STATUS => $jobs->getStatus(),
                JobsInterface::LOG => $jobs->getLog()
            ],
            [
                JobsInterface::STATUS,
                JobsInterface::LOG,
                JobsInterface::REQUEST
            ]
        );

        $id = $connection->lastInsertId();
        $jobs->setId($id);
    }

    /**
     * @param $jobId
     * @return mixed|void
     * @throws NoSuchEntityException
     */
    public function getById($jobId)
    {
        $connection = $this->resourceConnection->getConnection();
        $table = $connection->getTableName(JobsInterface::DB_TABLE);
        $sql = $connection->select()->from($table, ['*'])->where('id = (?)', $jobId)->assemble();
        $res = $connection->fetchRow($sql, [], Zend_Db::FETCH_ASSOC);
        if ($res===null) {
            throw new NoSuchEntityException(new Phrase('The job with id ' . $jobId . ' doesn\'t exists'));
        }
        $jobs = $this->jobsFactory->create();
        foreach ($res as $k => $v) {
            $parse = explode('_', $k);
            $method = 'set';
            foreach ($parse as $p) {
                $method .= ucwords($p);
            }
            $jobs->{$method}($v);
        }
        return $jobs;
    }

    /**
     * @param $options
     * @param null $status
     * @param null $limit
     * @return array|mixed
     */
    public function getAll($options, $status = null, $limit = null)
    {
        $connection = $this->resourceConnection->getConnection();
        $table = $connection->getTableName(JobsInterface::DB_TABLE);
        $contextConditions = $this->getContextConditions($options);
        $sql = "SELECT * FROM {$table} WHERE {$contextConditions}";
        if ($status!==null) {
            $sql .= " AND status = '{$status}'";
        }
        if ($limit!==null) {
            $sql .= " LIMIT {$limit}";
        }
        return $connection->fetchAll($sql, [], Zend_Db::FETCH_ASSOC);
    }

    /**
     * @param $options
     * @param $id
     * @param $status
     * @param null $log
     * @return int|mixed
     */
    public function setStatus($options, $id, $status, $log=null)
    {
        $connection = $this->resourceConnection->getConnection();
        $table = $connection->getTableName(JobsInterface::DB_TABLE);
        $contextConditions = $this->getContextConditions($options);
        $updateArray = [JobsInterface::STATUS => $status];
        if ($log!==null) {
            $updateArray[JobsInterface::LOG] = $log;
        }

        if (is_array($id)) {
            $ids = "'" . implode("','", $id) . "'";
        } else {
            $ids = "'" . $id . "'";
        }
        return $connection->update($table, $updateArray, $contextConditions . " AND entity_id IN ({$ids})");
    }

    /**
     * @param $options
     * @return string
     */
    private function getContextConditions($options)
    {
        return "`type` = '{$options[JobsInterface::TYPE]}' AND direction = '{$options[JobsInterface::DIRECTION]}' AND entity = '{$options[JobsInterface::ENTITY]}'";
    }

    /**
     * @param array $conditions
     * @return bool
     */
    public function checkIfExist(array $conditions): bool
    {
        $connection = $this->resourceConnection->getConnection();
        $table = $connection->getTableName(JobsInterface::DB_TABLE);
        $where = $this->helperData->arrayToWhereString($conditions);
        $sql = "SELECT * FROM {$table} WHERE {$where}";
        $row = $connection->fetchAll($sql, [], Zend_Db::FETCH_ASSOC);
        if (count($row)>0) {
            return true;
        }
        return false;
    }

    /**
     * @param $options
     * @param $where
     */
    public function updateJobs($options, $where = '') {
        $connection = $this->resourceConnection->getConnection();
        $tableNameJobs = $this->resourceConnection->getTableName(JobsInterface::DB_TABLE);
        $connection->update($tableNameJobs, $options, $where);
    }
}
