<?php

namespace App\Libraries;

abstract class CloudflareLibrary
{
    private static $_requestCount = 1;
    private $_parent = null;
    protected $_adapter = null;
    protected $_model = null;
    protected function __construct($parent)
    {
        $this->_parent = $parent;
        $this->setAdapter();
    }
    abstract public function getClassName();
    abstract protected function setAdapter();
    abstract protected function createEntity(\stdClass $cfResult);
    abstract protected function getCFResults_List(int $page): array;
    final protected static function getRequestCount()
    {
        return self::$_requestCount;
    }
    protected function setAdapter()
    {
        if (!is_null($this->_adapter)) {
            throw new \Exception("Adapter가 이미 지정되었습니다.");
        }
        $apikey = new \Cloudflare\API\Auth\APIKey(
            $this->getParent()->getAuthId(),
            $this->getParent()->getAuthKey()
        );
        $this->_adapter = new \Cloudflare\API\Adapter\Guzzle($apikey);
        // throw new \Exception(var_export($this->_adapter, true));
    }
    final protected function getAdapter(): \Cloudflare\API\Adapter\Guzzle
    {
        if (CF_REQUEST_MAX <= self::$_requestCount) {
            log_message('warning', sprintf("--Cloudflare API Call %s초 대기 시작--", CF_REQUEST_WAITTIME));
            sleep(CF_REQUEST_WAITTIME);
            self::$_requestCount = 0;
            log_message('warning', sprintf("--Cloudflare API Call %s초 대기 종료--", CF_REQUEST_WAITTIME));
        }
        self::$_requestCount++;
        if (is_null($this->_adapter)) {
            throw new \Exception("해당 Adapter가 없습니다.");
        }
        // throw new \Exception(var_export($this->_adapter, true));
        return $this->_adapter;
    }
    final public function getParent()
    {
        if (!isset($this->_parent)) {
            throw new \Exception(__METHOD__ . "에서 오류발생: ParentEntity가 선언되지 않았습니다.");
        }
        return $this->_parent;
    }
    //reload관련
    //부모키를 기준으로 CF에 존재하지 않는 데이터 삭제용
    final protected function reload_delete(array $entitys)
    {
        $availableUids = array();
        if (count($entitys)) {
            foreach ($entitys as $entity) {
                array_push($availableUids, $entity->getPrimaryKey());
            }
            $this->_model->where($this->_model::PARENT_FIELD, $this->getParent()->getPrimaryKey())->whereNotIn('uid', $availableUids)->delete();
        } else {
            $this->_model->where($this->_model::PARENT_FIELD, $this->getParent()->getPrimaryKey())->delete();
        }
    }
    final protected function reload_entitys(array $cfResults): array
    {
        $entitys = array();
        if (count($cfResults)) {
            $cnt = 1;
            foreach ($cfResults as $cfResult) {
                $entity = $this->getEntityByResult((object)$cfResult);
                log_message("debug", "{$cnt}번째: {$entity->getTitle()} 저장");
                if (!$this->_model->save($entity)) {
                    log_message("error", __FUNCTION__ . "에서 호출:" . $this->_model->getLastQuery());
                    log_message("error", implode("\n", $this->_model->errors()));
                    throw new \Exception(__FUNCTION__ . " 오류 발생.\n" . var_export($this->_model->errors(), true));
                }
                array_push($entitys, $entity);
                $cnt++;
            }
        }
        return $entitys;
    }
    final protected function reload_cfResults(int $page_limit = 0)
    {
        $page = 1; //Page는 1부터 시작해야함
        $page_cnt = 1;
        $cfResults = array();
        do {
            $temp_cfResults = $this->getCFResults_List($page);
            // throw new \Exception(var_export($temp_cfResults, true));
            $page = count($temp_cfResults) < CF_ADAPTER_PERPAGE_MAX ? 0 : $page + 1;
            //Loop 갯수제한시
            if ($page_limit !== 0 && $page >= $page_limit + 1) {
                $page = 0;
            }
            $cfResults = array_merge($cfResults, $temp_cfResults);
            $page_cnt++;
        } while (0 < $page);
        return $cfResults;
    }

    final public function reload(int $page_limit = 0): array
    {
        $cfResults = $this->reload_cfResults($page_limit);
        log_message("notice", "-----{$this->getParent()->getTitle()} {$this->getClassName()} cfResult 처리[" . count($cfResults) . "개] 시작-----");
        $entitys = $this->reload_entitys($cfResults);
        $this->reload_delete($entitys);
        log_message("notice", "-----{$this->getParent()->getTitle()} {$this->getClassName()} DB 처리[" . count($entitys) . "개] 완료-----");
        return $entitys;
    }
}
