<?php
/**
 * 基础服务类
 * 本服务相等于一个容器,如果要使用到Phalcon框架中的di则继承
 */

namespace SRVX\Service;

use Phalcon\Di\Injectable;
use Phalcon\Logger;
use Phalcon\Logger\Adapter\Stream;
use Phalcon\Messages\Message;
use Phalcon\Messages\Messages as MessageGroup;
use Phalcon\Paginator\Adapter\QueryBuilder;
use SRVX\Utils\OTP;
use SRVX\Utils\Common;

/**
 * Class BaseService
 * @package SRVX\Service
 * @property \SRVX\Service $s
 * @property \Redis $redis
 * @property \Phalcon\Session\Adapter\Redis $session
 * @property \Phalcon\Config $config
 * @property \Phalcon\Db\Adapter\AdapterInterface $dbWrite
 * @property \Phalcon\Db\Adapter\AdapterInterface $dbRead
 * @property \Phalcon\Cache\Adapter\Redis $cache
 */
class BaseService extends Injectable
{
    protected $errorMessages;

    /**
     * 如果有错误信息返回真
     * @return bool
     */
    public function validationHasFailed()
    {
        return ($this->errorMessages instanceof MessageGroup) ? $this->errorMessages->count() > 0 : false;
    }

    /**
     * 设置错误信息
     * @param $messages
     */
    public function setMessages($messages)
    {
        if (!$this->errorMessages instanceof MessageGroup) {
            $this->errorMessages = new MessageGroup();
        }
        if (count($messages) > 0 && !empty($messages)) {
            foreach ($messages as $msg) {
                ($msg instanceof Message) ? $this->errorMessages->appendMessage(new Message($msg->getMessage(), $msg->getField(), $msg->getType())) : $this->errorMessages->appendMessage($msg);
            }
        }
    }

    /**
     * 取错误信息
     * @param string $filter
     * @return mixed
     */
    public function getMessages($filter = '')
    {
        if (is_string($filter) && !empty($filter)) {
            $filtered = new MessageGroup();
            foreach ($this->errorMessages as $message) {
                is_object($message) && method_exists($message, 'getField') && ($message->getField() == $filter) && $filtered->appendMessage($message);
            }
            return $filtered;
        }
        return $this->errorMessages;
    }

    /**
     * 使用curl的get方法
     * @param $url
     * @param bool $conv
     * @param int $SSL
     * @param int $timeout
     * @param array $basicAuthData 需要basic auth 认证
     * @param int $retStatusCode 是否返回状态码
     * @return bool|mixed|string
     */
    public function curlGet($url, $conv = false, $SSL = 0, $timeout = 30, $basicAuthData = [], $retStatusCode = 0)
    {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $SSL); // 让CURL支持HTTPS访问
        if ($basicAuthData) {
            curl_setopt($ch, CURLOPT_USERPWD, $basicAuthData['username'] . ":" . $basicAuthData['password']);
        }
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
        curl_setopt($ch, CURLOPT_ENCODING, 'text');
        $res = curl_exec($ch);
        $res = $conv ? mb_convert_encoding($res, 'utf-8', 'GBK,UTF-8,ASCII') : $res;
        $code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);
        return $retStatusCode ? $code : $res;
    }

    /**
     * 使用curl的post方法
     * @param      $url
     * @param      $params
     * @param bool $use_http_build_query
     * @param int $SSL
     * @return mixed
     */
    public function curlPost($url, $params, $use_http_build_query = true, $SSL = 0)
    {
        $use_http_build_query && $params = http_build_query($params);
        $curlHandle = curl_init();
        curl_setopt($curlHandle, CURLOPT_POST, 1);
        curl_setopt($curlHandle, CURLOPT_URL, $url);
        curl_setopt($curlHandle, CURLOPT_SSL_VERIFYPEER, $SSL); // 让CURL支持HTTPS访问
        curl_setopt($curlHandle, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($curlHandle, CURLOPT_CONNECTTIMEOUT, 30);
        curl_setopt($curlHandle, CURLOPT_TIMEOUT, 30);
        curl_setopt($curlHandle, CURLOPT_POSTFIELDS, $params);
        $result = curl_exec($curlHandle);
        curl_close($curlHandle);
        return $result;
    }

    /**
     * 使用curl的post方法
     * @param      $url
     * @param      $params
     * @param bool $use_http_build_query
     * @param int $SSL
     * @return mixed
     */
    public function curlPostJson($url, $data)
    {
        $this->logger([
            "url" => $url,
            "data" => $data
        ], "maka_baka_trader", true, true);
        $data = json_encode($data);
        $ch = curl_init();//初始化curl
        curl_setopt($ch, CURLOPT_URL, $url);//抓取指定网页
        curl_setopt($ch, CURLOPT_HEADER, 0);//设置header
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);//要求结果为字符串且输出到屏幕上
        curl_setopt($ch, CURLOPT_HTTPHEADER, array(
                'Content-Type: application/json',
                'Content-Length: ' . strlen($data))
        );
        curl_setopt($ch, CURLOPT_POST, 1);//post提交方式
        curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
        $data = curl_exec($ch);//运行curl
        curl_close($ch);
        return $data;
    }

    /**
     * 使用curl的post方法
     * @param      $url
     * @param      $params
     * @param bool $use_http_build_query
     * @param int $SSL
     * @return mixed
     */
    public function curlHeadersPost($url, $params, $use_http_build_query = true, $SSL = 0, $headers = [])
    {
        $use_http_build_query && $params = http_build_query($params);
        $curlHandle = curl_init();
        curl_setopt($curlHandle, CURLOPT_POST, 1);
        curl_setopt($curlHandle, CURLOPT_URL, $url);
        curl_setopt($curlHandle, CURLOPT_SSL_VERIFYPEER, $SSL); // 让CURL支持HTTPS访问
        curl_setopt($curlHandle, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($curlHandle, CURLOPT_CONNECTTIMEOUT, 30);
        curl_setopt($curlHandle, CURLOPT_TIMEOUT, 30);
        curl_setopt($curlHandle, CURLOPT_POSTFIELDS, $params);
        !empty($headers) && curl_setopt($curlHandle, CURLOPT_HTTPHEADER, $headers);
        $result = curl_exec($curlHandle);
        curl_close($curlHandle);
        return $result;
    }

    /**
     * 字符串转化成SQL语句或者数组
     * @param string $str
     * @param bool $toSqlIn
     * @return array|bool
     */
    public function strToArray($str = '', $toSqlIn = false)
    {
        $str = str_replace([" ", "　", "\t", "\n", "\r"], '', $str);
        $res = preg_match('/^\d(,[\d]+)+$/', $str) ? ($toSqlIn ? " IN ('" . implode("','", array_filter(explode(',', $str))) . "') " : array_filter(explode(',', $str))) : false;
        return $toSqlIn && preg_match('/^\d+$/', $str) ? " = '$str'" : $res;
    }

    /**
     * @param array|string $ids
     * @return string
     */
    public function arrayToSqlIn($ids)
    {
        return is_array($ids) ? " IN ('" . implode("','", array_unique($ids)) . "') " : " = '" . addslashes($ids) . "'";
    }

    /**
     * 密码加密
     * @param        $password
     * @param string $salt
     * @return string
     */
    public function hash($password, $salt = '')
    {
        return md5(md5(trim($password) . $salt) . $salt);
    }

    /**
     * @param $gAuthKey
     * @param $code
     * @return bool
     */
    public function checkOtpAuth($gAuthKey, $code)
    {
        $g = new OTP();
        return $g->checkCode($gAuthKey, $code);
    }

    public function checkIpBlock()
    {
    }

    /**
     * @return string
     */
    public function getIpAddr()
    {
        return (string)$_SERVER['REMOTE_ADDR'];
    }

    /**
     * 记录日志
     * @param        $msg
     * @param string $name
     * @param bool $mode
     * @param bool $isForce 强制开启记录
     */
    public function logger($msg, $name = 'debug', $mode = false, $isForce = false)
    {
        //开启了debug模式才记录日志
        if (DEBUG || $isForce) {
            $time = time();
            if (file_exists(DIR_LOG)) {
                $path = DIR_LOG . date('Y_m_d', $time) . '_' . $name . '.log';
                $logger = new Logger('messages', ['main' => new Stream($path),]);
                $msg = is_array($msg) ? json_encode($msg, 320) : $msg;
                $ip = Common::getRealIP() ? Common::getRealIP() : ' IP NULL ';
                $msg = $ip . ' ' . $msg;
                $logger->debug($msg);
            } else {
                if ($mode) {
                    return;
                }
                @mkdir(DIR_LOG, 0755, true);
                $this->logger($msg, $name, true);
            }
        }
    }

    public function timeSQL($columnName, $bucket)
    {
        [$start, $end] = explode('|', $bucket);
        return ' (' . $columnName . ' >= ' . strtotime($start) . ' AND ' . $columnName . ' <= ' . strtotime($end) . ') ';
    }

    /**
     * 此方法由子类的getOne类型方法调用，用于执行查询前生成phalcon原生find/findFirst方法所需要的参数数组
     * @access protected
     * @param array|string $conditions 条件数组（键名为数据库字段名，键值为目标值）或字符串（同原生findFirst方法）
     * @param array $params find/findFirst方法参数数组（除conditions以外）
     * @return mixed    phalcon原生find/findFirst方法参数数组
     * @todo   to be optimized
     */
    protected function toParams($conditions, array $params = [], $is_sql = 0)
    {
        /****检查conditions****/
        if (is_string($conditions)) {
            $conditions = trim($conditions);
        } elseif (is_array($conditions)) {
            foreach ($conditions as $key => $val) {
                $conditions[$key] = trim($val);

                if ($conditions[$key] === '') {
                    unset($conditions[$key]);
                }
            }
        } else {
            return false;
        }
        if (!$conditions) {
            return false;
        }
        /****过滤参数****/
        foreach ($params as $key => $val) {
            if (empty($val)) {
                unset($params[$key]);
            }
        }
        $params['conditions'] = $conditions;
        /****生成（或覆盖）conditions 和 bind参数****/
        $sql = ' 1 ';
        $old = $conditions;
        if (is_array($conditions)) {
            $params['bind'] = array_values($conditions);
            $conditions = array_keys($conditions);
            foreach ($conditions as $key => $val) {
                $conditions[$key] = "{$val} = ?{$key}";
            }
            $params['conditions'] = implode(' AND ', $conditions);
        } else {
            $params['conditions'] = $conditions;
        }
        foreach ($old as $k => $v) {
            $sql .= " and " . $k . " = '" . $v . "'";
        }
        return $is_sql == 1 ? $sql : $params;
    }

    // 分割时间语句

    /**
     * 更新一个数据对象及其对应的数据库记录
     * @param array $data 新数据数组（键名为数据库字段名，键值为待更新值）
     * @param \stdClass $objData 待更新的对象
     * @return boolean           是否更新成功
     */
    protected function updateOne(array $data, $objData)
    {
        if (!is_object($objData) || !method_exists($objData, 'update')) {
            return false;
        }
        /*****检查新数据数组****/
        foreach ($data as $key => $val) {
            if (!property_exists($objData, $key)) {
                unset($data[$key]);
                continue;
            }
            $data[$key] = trim($val);
        }
        /*****执行更新****/
        return !$data ? false : $objData->update($data);
    }


    protected function returnRes($status = true, $msg = 'success', $data = [])
    {
        return ['status' => $status, 'data' => $data, 'msg' => $msg];
    }

    public function ossInfo()
    {
        return $this->s->generalSet()->getSet(['file_bucket_scheme', 'file_bucket_host'], false);
    }

    public function formatOssUrl($file, $oss = [])
    {
        if (empty($file)) {
            return $file;
        }
        if (empty($oss)) {
            $oss = $this->ossInfo();
        }
        if (strstr($file, "http")) {
            return $file;
        }
        return sprintf("%s://%s/%s", $oss['file_bucket_scheme'], $oss['file_bucket_host'], $file);
    }

    //用智莺的
    public function zyosFormatOssUrl($file, $oss = [])
    {
        return sprintf("%s://%s/%s", 'http', 'ossq.izhyin.cn', $file);
    }

    /**
     * 分页处理
     * @param $builder
     * @param $limit
     * @param $page
     * @param $cb
     * @return array
     */
    public function paginator($builder, $limit, $page, $cb)
    {
        $paginate = (new QueryBuilder(['builder' => $builder, 'limit' => $limit, 'page' => $page]))->paginate();

        $lists = $cb($paginate->getItems() ? $paginate->getItems()->toArray() : []);
        return [
            'paginate' => [
                'limit' => $paginate->getLimit(),
                'p' => $paginate->getCurrent(),
                'total' => $paginate->getTotalItems(),
            ],
            'lists' => $lists,
        ];
    }

    /**
     * @param $uri
     * @param $masterId
     * @param $payload
     * @return mixed
     */
    public function postAppApi($uri, $masterId, $payload, $apiType = '')
    {
        if ($apiType == 'oss') {
            $url = OSS_URL . $uri;
        } elseif (APP_ENV == 'dev') {
            $url = DEV_APP_URL . $uri;
//            $url = '192.168.0.30:53282' . $uri;
            //$url = "localhost:5000".$uri;
        } else {
            $url = PROD_APP_URL . $uri;
        }

        $ch = curl_init($url);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
        curl_setopt($ch, CURLOPT_HTTPHEADER, [
            'Content-Type:application/json',
            "MasterId:{$masterId}",
            'Platform:wap'
        ]);
        if (stristr($url, 'https') === 0) {
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        }

        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        $result = curl_exec($ch);
        curl_close($ch);

        $result = json_decode($result, true);
        return $result;
    }

    public function postAppApiNew($uri, $masterId, $payload, $apiType = '')
    {
        if ($apiType == 'oss') {
            $url = OSS_URL . $uri;
        } elseif (APP_ENV == 'dev') {
            $url = DEV_APP_URL . $uri;
//            $url = '192.168.0.30:53282' . $uri;
            //$url = "localhost:5000".$uri;
        } else {
            $url = PROD_APP_URL . $uri;
        }

        $ch = curl_init($url);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
        curl_setopt($ch, CURLOPT_HTTPHEADER, [
            'Content-Type:application/json',
            "MasterId:{$masterId}",
            'Platform:wap'
        ]);
        curl_setopt($ch, CURLOPT_TIMEOUT, 1);
        if (stristr($url, 'https') === 0) {
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        }

        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        $result = curl_exec($ch);
        curl_close($ch);

        $result = json_decode($result, true);
        return $result;
    }

    public function getFromAppApi($uri, $masterId, $apiType = '')
    {
        if ($apiType == 'oss') {
            $url = OSS_URL . $uri;
        } elseif (APP_ENV == 'dev') {
            $url = DEV_APP_URL . $uri;
//            $url = '192.168.0.30:53282' . $uri;
//             $url = "localhost:5000".$uri;
        } else {
            $url = PROD_APP_URL . $uri;
        }

        $ch = curl_init($url);
        curl_setopt($ch, CURLOPT_HTTPHEADER, [
            'Content-Type:application/json',
            "MasterId:{$masterId}",
            'Platform:wap'
        ]);

        if (stristr($url, 'https') === 0) {
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        }

        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        $result = curl_exec($ch);
        curl_close($ch);

        $result = json_decode($result, true);
        return $result;

    }
}
