<?php
/**
 * StatisticsSwitchLogic.php UTF-8
 * 汇总切量数据
 *
 * @date    : 2019/11/7 15:08
 *
 * @license 这不是一个自由软件,未经授权不许任何使用和传播。
 * @author  : wuyonghong <wyh@huosdk.com>
 * @version : HUOUNION 8.5
 */

namespace huo\logic\data;

use huo\controller\common\CommonFunc;
use huo\logic\agent\AgentLogic;
use huo\logic\member\MemberLogic;
use huo\model\common\CommonModel;
use huo\model\game\GameModel;
use huo\model\log\MemLoginLogModel;
use huo\model\log\MemLoginLogSwitchModel;
use huo\model\member\MemberModel;
use huo\model\member\MemoauthModel;
use huo\model\member\MgRoleModel;
use huo\model\order\OrderModel;
use huo\model\user\UserModel;
use huolib\constant\CacheConst;
use huolib\constant\CommonConst;
use huolib\constant\OrderConst;
use huolib\tool\StrUtils;
use huolib\tool\Time;
use think\Cache;

class StatisticsSwitchLogic extends CommonModel {
    protected $cache_key_prefix = CacheConst::CACHE_STATISTICS_DATA_SWITCH_PREFIX;
    protected $expire_time      = 1;

    /**
     * @param array $param
     *
     * @return array
     */
    protected function getWhere($param = []) {
        $_map = [];
        /* 时间搜索 */
        list($_start_time, $_end_time) = $this->getTime($param);
        $_map['create_time'] = ['between', [$_start_time, $_end_time]];
        if (!empty($param['agent_id'])) {
            if (is_array($param['agent_id'])) {
                if (in_array('in', $param['agent_id'])) {
                    $_map['agent_id'] = $param['agent_id'];
                } else {
                    $_map['agent_id'] = ['in', $param['agent_id']];
                }
            } else {
                $_map['agent_id'] = $param['agent_id'];
            }
        }
        if (!empty($param['app_id'])) {
            if (is_array($param['app_id'])) {
                $_map['app_id'] = ['in', $param['app_id']];
            } else {
                $_map['app_id'] = $param['app_id'];
            }
        }

        return $_map;
    }

    public function getTime($param) {
        list($_start_time, $_end_time) = time::today();
        $_start_time = 0;
        if (!empty($param['start_time'])) {
            $_start_time = strtotime($param['start_time']);
        }
        if (!empty($param['end_time'])) {
            $_end_time = strtotime($param['end_time']) + CommonConst::CONST_DAY_SECONDS;
        }

        return [$_start_time, $_end_time];
    }

    public function getTodayData($where) {
        $where['start_time'] = $where['start_time'] = date('Y-m-d');
        $_data = $this->getStatisticsData($where);
        $_data['date'] = $where['start_time'];

        return $_data;
    }

    /**
     * 获取聚合今日数据
     *
     * @param $where
     *
     * @return array
     */
    public function getStatisticsData($where) {
        list($_start_time, $_end_time) = $this->getTime($where);
        $_map = $this->getWhere($where);
        $_data_by_login = $this->getDataByLoginData($_map, $_start_time, $_end_time);
        $_data_by_member = $this->getDataByMember($_map, $_start_time, $_end_time);
        $_data_by_order = $this->getDataByOrder($_map, $_start_time, $_end_time);
        $_data = array_merge($_data_by_login, $_data_by_member, $_data_by_order);
        if ($_data['user_cnt'] < $_data['reg_cnt']) {
            $_data['user_cnt'] = $_data['reg_cnt'];
        }
        if ($_data['ip_cnt'] < $_data['reg_ip_cnt']) {
            $_data['ip_cnt'] = $_data['reg_ip_cnt'];
        }
        if ($_data['device_cnt'] < $_data['reg_device_cnt']) {
            $_data['device_cnt'] = $_data['reg_device_cnt'];
        }
        /* 新增付费率 */
        if (isset($_data['reg_pay_cnt'])) {
            $_data['reg_pay_rate'] = StrUtils::getRate($_data['reg_pay_cnt'], $_data['reg_cnt']);
            /* 活跃付费率 */
            $_data['user_pay_rate'] = StrUtils::getRate($_data['pay_user_cnt'], $_data['user_cnt']);
            /* 新增ARPU */
            $_data['reg_arpu'] = StrUtils::getArpu($_data['reg_sum_money'], $_data['reg_pay_cnt']);
            /* ARPU */
            $_data['arppu'] = StrUtils::getArpu($_data['sum_money'], $_data['pay_user_cnt']);
            /* ARPPU */
            $_data['arpu'] = StrUtils::getArpu($_data['sum_money'], $_data['user_cnt']);
        }
        if (!empty($where['app_id'])) {
            $_game_data = (new GameModel())->getInfoById($where['app_id']);
            $_data['game_name'] = get_val($_game_data, 'name', '');
            $_data['game_icon'] = get_val($_game_data, 'icon', '');
            $_data['classify'] = get_val($_game_data, 'classify', '');
        }
        if (!empty($where['agent_id'])) {
            $_agent_info = (new UserModel())->getInfoById($where['agent_id']);
            $_data['agent_name'] = get_val($_agent_info, 'user_login', '');
            $_data['agent_nickname'] = get_val($_agent_info, 'user_nicename', '');
        }
        $_data['cpa_cnt'] = 0; /* cpa有效用户 */
        $_role_map = [
            'start_time' => $_start_time,
            'end_time'   => $_end_time,
            'app_id'     => get_val($where, 'app_id', 0),
            'agent_id'   => get_val($where, 'agent_id', 0)
        ];
        $_data['role_cnt'] = $this->getDayRole($_role_map); /* 创角数 */
        $_data['openid_cnt'] = $this->getOpenidCnt($_role_map); /* 第三方注册用户 */

        return $_data;
    }

    /**
     * 获取创角数
     *
     * @param      $param
     *
     * @return int|string
     */
    public function getDayRole($param) {
        list($_start_time, $_end_time) = Time::today();
        $_start_time = get_val($param, 'start_time', $_start_time);
        $_end_time = get_val($param, 'end_time', $_end_time);
        $_role_model = new MgRoleModel();
        $_map = [
            'mg_role_model.create_time' => ['between', [$_start_time, $_end_time]],
        ];
        $_app_id = get_val($param, 'app_id', 0);
        if (!empty($_app_id)) {
            $_map['mg_role_model.app_id'] = $_app_id;
        }
        $_agent_id = get_val($param, 'agent_id', 0);
        $_mem_ids = [];
        if (!empty($_agent_id)) {
            if (-1 == $_agent_id) {
                $_mem_ids = (new MemberLogic())->getIdsByAgentId(0);
                $_map['mg.mem_id'] = ['in', $_mem_ids];
            } else {
                if (is_array($_agent_id)) {
                    $_agent_mem_ids = (new MemberLogic())->getIdsByAgentId(
                        $_agent_id, ['is_switch' => OrderConst::PAY_SWITCH_NO]
                    );
                } else {
                    $_agent_ids = (new AgentLogic())->getAgentIds($_agent_id, true);
                    $_agent_mem_ids = (new MemberLogic())->getIdsByAgentId(
                        ['in', $_agent_ids], ['is_switch' => OrderConst::PAY_SWITCH_NO]
                    );
                }
                $_mem_ids = $_agent_mem_ids;
            }
            if (empty($_mem_ids)) {
                return 0;
            }
        }
        $_role_mem_ids = $_role_model->with('mg')->where($_map)->column('mem_id');
        if (!empty($_mem_ids)) {
            $_role_mem_ids = array_intersect($_role_mem_ids, $_mem_ids);
        }

        return count($_role_mem_ids);
    }

    /**
     * 获取单条记录缓存key
     *
     * @param array $where 条件
     *
     * @return string
     */
    protected function getCacheKeyByLoginData($where) {
        return $this->cache_key_prefix.'ld_'.md5(json_encode($where));
    }

    /**
     * 获取单条记录缓存key
     *
     * @param array $where 条件
     *
     * @return string
     */
    protected function getCacheKeyByMember($where) {
        return $this->cache_key_prefix.'m_'.md5(json_encode($where));
    }

    /**
     * 获取单条记录缓存key
     *
     * @param array $where 条件
     *
     * @return string
     */
    protected function getCacheKeyByMemberRetain($where) {
        return $this->cache_key_prefix.'mr_'.md5(json_encode($where));
    }

    /**
     * 获取单条记录缓存key
     *
     * @param array $where 条件
     *
     * @return string
     */
    protected function getCacheKeyByOpenidCnt($where) {
        return $this->cache_key_prefix.'oc_'.md5(json_encode($where));
    }

    /**
     * 获取第三方注册数
     *
     * @param $param
     *
     * @return mixed
     */
    public function getOpenidCnt($param) {
        /* 缓存操作 */
        $_cache_key = $this->getCacheKeyByOpenidCnt($param);
        $_data = Cache::get($_cache_key);
        if (!empty($_data)) {
            return $_data;
        }
        list($_start_time, $_end_time) = Time::today();
        $_start_time = get_val($param, 'start_time', $_start_time);
        $_end_time = get_val($param, 'end_time', $_end_time);
        $_map = [
            'ljmem.create_time' => ['between', [$_start_time, $_end_time]],
        ];
        $_app_id = get_val($param, 'app_id', 0);
        if (!empty($_app_id)) {
            $_map['app_id'] = $_app_id;
        }
        $_agent_id = get_val($param, 'agent_id', 0);
        if (!empty($_agent_id)) {
            if (-1 == $_agent_id) {
                $_map['agent_id'] = 0;
            } else {
                $_map['agent_id'] = $_agent_id;
            }
        }
        $_cnt = (new MemoauthModel())->with('ljmem')->where($_map)->count('DISTINCT mem_id');
        if (!empty($_cnt)) {
            Cache::set($_cache_key, $_cnt, $this->expire_time);
        }

        return $_cnt;
    }

    /**
     * 'user_cnt'           活跃玩家数量
     * 'ip_cnt'            IP数量
     * 'device_cnt'       设备数量
     *
     * @param array  $where
     *
     * @param string $start_time 开始时间
     * @param string $end_time   结束时间
     *
     * @return array
     */
    public function getDataByLoginData($where, $start_time, $end_time) {
        $_date = date('Y-m', $start_time);
        $_date_end = date('Y-m', $end_time);
        $_cache_where = $where;
        $_map = $where;
        /* 缓存操作 */
        $_cache_key = $this->getCacheKeyByLoginData($_cache_where);
        $_data = Cache::get($_cache_key);
        if (!empty($_data)) {
            return $_data;
        }
        $_field = [
            'count(distinct(`mem_id`))'    => 'user_cnt',
            'count(distinct(`device_id`))' => 'device_cnt',
            'count(distinct(`ip`))'        => 'ip_cnt',
        ];
        $_model = new MemLoginLogModel();
        $_data = $_model->computeTable($_date)->field($_field)->where($_map)->find();
        if (is_object($_data)) {
            $_data = $_data->toArray();
        }
        if (empty($_data)) {
            $_data = [
                'user_cnt'   => 0,
                'device_cnt' => 0,
                'ip_cnt'     => 0,
            ];
        }
        if ($_date_end != $_date) {
            $_data2 = $_model->computeTable($_date_end)->field($_field)->where($_map)->find();
            if (is_object($_data2)) {
                $_data2 = $_data2->toArray();
            }
            if (!empty($_data2)) {
                $_data['user_cnt'] += $_data2['user_cnt'];
                $_data['device_cnt'] += $_data2['device_cnt'];
                $_data['ip_cnt'] += $_data2['ip_cnt'];
            }
        }
        /* 取切量数据 */
        $_switch_model = new MemLoginLogSwitchModel();
        $_switch_data = $_switch_model->computeTable($_date)->field($_field)->where($_map)->find();
        if (is_object($_switch_data)) {
            $_switch_data = $_switch_data->toArray();
        }
        if ($_date_end != $_date) {
            $_switch_data2 = $_switch_model->computeTable($_date_end)->field($_field)->where($_map)->find();
            if (is_object($_switch_data2)) {
                $_switch_data2 = $_switch_data2->toArray();
            }
            if (!empty($_switch_data2)) {
                $_switch_data['user_cnt'] += $_switch_data2['user_cnt'];
                $_switch_data['device_cnt'] += $_switch_data2['device_cnt'];
                $_switch_data['ip_cnt'] += $_switch_data2['ip_cnt'];
            }
        }
        $_data['user_cnt'] = CommonFunc::safeDivMinValue($_data['user_cnt'], $_switch_data['user_cnt']);
        $_data['device_cnt'] = CommonFunc::safeDivMinValue($_data['device_cnt'], $_switch_data['device_cnt']);
        $_data['ip_cnt'] = CommonFunc::safeDivMinValue($_data['ip_cnt'], $_switch_data['ip_cnt']);
        if (empty($_data)) {
            return [];
        }
        Cache::set($_cache_key, $_data, $this->expire_time);

        return $_data;
    }

    /**
     *  'history_user_cnt'       注册玩家数
     *  'reg_cnt'         注册玩家数
     * 'reg_device_cnt'    新增设备
     * 'reg_ip_cnt'        新增IP
     *
     * @param array  $where      条件
     * @param string $start_time 开始时间
     * @param string $end_time   结束时间
     *
     * @return array
     */
    public function getDataByMember($where = [], $start_time = 0, $end_time = 0) {
        $_cache_where = $where;
        $_map = $where;
        $_map['is_switch'] = OrderConst::PAY_SWITCH_NO;
        /* 缓存操作 */
        $_cache_key = $this->getCacheKeyByMember($_cache_where);
        $_data = Cache::get($_cache_key);
        if (!empty($_data)) {
            return $_data;
        }
        $_model = (new MemberModel());
        $_field = [
            'count(distinct(`id`))'        => 'reg_cnt',
            'count(distinct(`device_id`))' => 'reg_device_cnt',
            'count(distinct(`reg_ip`))'    => 'reg_ip_cnt',
        ];
        $_data = $_model->field($_field)->where($_map)->find();
        if (is_object($_data)) {
            $_data = $_data->toArray();
        }
        if (empty($_data)) {
            $_data = [
                'reg_cnt'        => 0,
                'reg_device_cnt' => 0,
                'reg_ip_cnt'     => 0,
            ];
        }
        $_data['history_user_cnt'] = $_model->getRegisterCount(0, $end_time, $_map);
        Cache::set($_cache_key, $_data, $this->expire_time);

        return $_data;
    }

    /**
     * 通过订单获取今日数据
     * 'pay_user_cnt'          付费玩家数
     * 'order_cnt'             成功订单数
     * 'fail_order_cnt'        失败订单数
     * 'un_order_cnt'          待支付订单数
     * 'reg_order_cnt'         新增订单
     * 'reg_pay_cnt'           新增即付费人数
     * 'sum_money'             充值金额
     * 'sum_real_money'        充值流水
     * 'first_pay_cnt'         首次付费人数
     * 'first_pay_money'       首付金额
     * 'reg_sum_money'         新增即付总额
     * 'reg_real_sum_money'    自然流水金额
     *
     * @param array $where
     *
     * @param int   $start_time 开始时间
     * @param int   $end_time   结束时间
     *
     * @return array
     */
    public function getDataByOrder($where = [], $start_time = 0, $end_time = 0) {
        $_cache_where = $where;
        $_map = $where;
        $_map['is_switch'] = OrderConst::PAY_SWITCH_NO;
        /* 缓存操作 */
        $_cache_key = $this->getCacheKeyByMemberRetain($_cache_where);
        $_data = Cache::get($_cache_key);
        if (!empty($_data)) {
            return $_data;
        }
        $_model = (new OrderModel());
        $_map_order_cnt = $_map;
        $_map_pay_user_cnt = $_map;
        $_map_pay_user_cnt['status'] = OrderConst::PAY_STATUS_SUC;
        $_map_order_cnt['status'] = OrderConst::PAY_STATUS_SUC;
        $_map_fail_order_cnt['status'] = OrderConst::PAY_STATUS_FAIL;
        $_map_un_order_cnt['status'] = OrderConst::PAY_STATUS_NOT;
        $_data = [
            'pay_user_cnt'   => $_model->where($_map_pay_user_cnt)->count('distinct mem_id'),
            'order_cnt'      => $_model->where($_map_order_cnt)->count('id'),
            'fail_order_cnt' => $_model->where($_map_fail_order_cnt)->count('id'),
            'un_order_cnt'   => $_model->where($_map_un_order_cnt)->count('id'),
            'sum_money'      => $_model->where($_map_order_cnt)->sum('amount'),
            'sum_real_money' => $_model->where($_map_order_cnt)->sum('real_amount'),
        ];
        $_where_str = 'uo.`status` =2 and uo.create_time between '.$start_time.' AND '.$end_time
                      .' and m.create_time between '.$start_time.' AND '.$end_time;
        if (!empty($_map['agent_id'])) {
            if (is_array($_map['agent_id'])) {
                $_where_str .= ' and uo.agent_id in ('.implode(',', $_map['agent_id'][1]).')';
            } else {
                $_where_str .= ' and uo.agent_id='.$_map['agent_id'];
            }
        }
        if (!empty($_map['app_id'])) {
            if (is_array($_map['app_id'])) {
                $_where_str .= ' and uo.app_id in ('.implode(',', $_map['app_id'][1]).')';
            } else {
                $_where_str .= ' and uo.app_id='.$_map['app_id'];
            }
        }
        $_sql
            = 'SELECT 
count(DISTINCT(uo.id)) AS reg_order_cnt,
count(DISTINCT(uo.mem_id)) AS reg_pay_cnt,
sum(uo.amount) AS reg_sum_money,
sum(uo.real_amount) AS reg_real_sum_money
FROM h_pay uo INNER JOIN  h_member m ON m.id=uo.mem_id  
WHERE '.$_where_str;
        $_sql_data = db()->query($_sql);
        $_reg_data = $_sql_data[0];
        $_data = array_merge($_data, $_reg_data);
        if (empty($_data)) {
            $_data = [
                'pay_user_cnt'       => 0,
                'order_cnt'          => 0,
                'fail_order_cnt'     => 0,
                'un_order_cnt'       => 0,
                'sum_money'          => 0,
                'sum_real_money'     => 0,
                'reg_order_cnt'      => 0,
                'reg_pay_cnt'        => 0,
                'reg_sum_money'      => 0,
                'reg_real_sum_money' => 0
            ];
        }
        if (empty($_data['reg_sum_money'])) {
            $_data['reg_sum_money'] = 0;
        }
        Cache::set($_cache_key, $_data, $this->expire_time);

        return $_data;
    }
}