<?php
/**
 *  ╔═══════════════════════════════════════════════════╗
 *  ║                                                   ║
 *  ║     ██╗  ██╗   █████╗    ██████╗                  ║
 *  ║     ██║  ██║  ██╔══██╗  ██╔═══██╗                 ║
 *  ║     ███████║  ███████║  ██║   ██║                 ║
 *  ║     ██╔══██║  ██╔══██║  ██║   ██║                 ║
 *  ║     ██║  ██║  ██║  ██║  ╚██████╔╝   SNS           ║
 *  ║                                                   ║    
 *  ║                                                   ║    
 *  ║     © 2023 HaoSNS™ All Rights Reserved            ║
 *  ║     官方网站: https://www.haosns.com                *
 *  ║     本代码由赣州乐易网络科技有限公司®提供             *
 *  ║                                                    *
 *  ║   未经授权禁止复制、传播或用于其他商业目的            *
 *  ║                                                   ║
 *  ╚═══════════════════════════════════════════════════╝
 */


namespace app\adminapi\logic\sign;

use app\common\enum\AccountLogEnum;
use app\common\enum\SignEnum;
use app\common\enum\YesNoEnum;
use app\common\logic\BaseLogic;
use app\common\model\AccountLog;
use app\common\model\SignDaily;
use app\common\model\SignLog;
use app\common\service\ConfigService;
use app\common\service\FileService;
use think\facade\Config;
use think\facade\Db;

/**
 * 签到逻辑层
 * Class SignLogic
 * @package app\adminapi\logic
 */
class SignLogic extends BaseLogic
{
    /**
     * @notes 获取签到规则
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public static function getConfig()
    {
        $daily = SignDaily::field('money_status,money,points_status,points')
            ->where('type', SignEnum::DAILY)
            ->findOrEmpty()
            ->toArray();
        if(empty($daily)) {
            $daily = [
                'money_status' => YesNoEnum::NO,
                'money' => 0
            ];
        }
        $continuous = SignDaily::field('id,money_status,money,days,points_status,points')
            ->where('type', SignEnum::CONTINUOUS)
            ->order('days', 'asc')
            ->select()
            ->toArray();
        $config = [
            'is_open' => ConfigService::get('sign', 'is_open', YesNoEnum::YES),
            'daily' => $daily,
            'continuous'  => $continuous,
            'remark' => ConfigService::get('sign', 'remark')
        ];

        return $config;
    }

    /**
     * @notes 设置签到规则
     * @param $params
     * @return bool
     */
    public static function setConfig($params)
    {
        Db::startTrans();
        try {
            // 更新状态
            ConfigService::set('sign', 'is_open', $params['is_open']);

            // 更新每日签到规则
            $signDaily = SignDaily::where('type', SignEnum::DAILY)->findOrEmpty();
            if($signDaily->isEmpty()) {
                $params['daily']['type'] = SignEnum::DAILY;
                $params['daily']['days'] = 1;
                SignDaily::create($params['daily']);
            }else{
                SignDaily::where('type', SignEnum::DAILY)->update($params['daily']);
            }

            // 更新签到说明
            ConfigService::set('sign', 'remark', $params['remark']);

            Db::commit();
            return true;
        } catch (\Exception $e) {
            Db::rollback();
            self::setError($e->getMessage());
            return false;
        }
    }

    /**
     * @notes 添加连续签到规则
     * @param $params
     * @return bool
     */
    public static function add($params)
    {
        try {
            SignDaily::create($params);
            return true;
        } catch(\Exception $e) {
            self::setError($e->getMessage());
            return false;
        }
    }

    /**
     * @notes 编辑连续签到规则
     * @param $params
     * @return bool
     */
    public static function edit($params)
    {
        try {
            SignDaily::update($params);
            return true;
        } catch(\Exception $e) {
            self::setError($e->getMessage());
            return false;
        }
    }

    /**
     * @notes 删除连续签到规则
     * @param $params
     * @return bool
     */
    public static function delete($params)
    {
        try {
            SignDaily::destroy($params['id']);
            return true;
        } catch(\Exception $e) {
            self::setError($e->getMessage());
            return false;
        }
    }

    /**
     * @notes 查看连续签到规则详情
     * @param $params
     * @return array
     */
    public static function detail($params)
    {
        $signDialy = SignDaily::field('money, money_status, days, id')
            ->where('id', $params['id'])
            ->findOrEmpty()
            ->toArray();

        return $signDialy;
    }

    /**
     * @notes 重置说明
     */
    public static function resetRemark()
    {
        $default = Config::get('project.sign.remark');
        ConfigService::set('sign', 'remark', $default);
    }

    /**
     * @notes 签到数据中心
     * @return array
     */
    public static function dataCenter()
    {
        return [
            'sign_data' => self::signData(),
            'recent_data' => self::recentData(),
            'top_data' => self::topData()
        ];
    }

    /**
     * @notes 签到数据
     * @return array
     */
    public static function signData()
    {
        $totalSign = SignLog::count();
        $totalMoney = AccountLog::where('change_type', AccountLogEnum::BW_INC_SIGN)->sum('change_amount');
        return [
            'total_sign' => $totalSign,
            'total_money' => $totalMoney
        ];
    }

    /**
     * @notes 近30天签到数据
     * @return array
     */
    public static function recentData()
    {
        $field = [
            "FROM_UNIXTIME(create_time,'%Y%m%d') as date",
            "count(id) as num"
        ];
        $lists = SignLog::field($field)
            ->group('date')
            ->whereMonth('create_time')
            ->select()
            ->toArray();
        $lists = array_column($lists, 'num', 'date');

        $data = [];
        for($i = 0; $i < 30; $i ++) {
            $today = new \DateTime();
            $targetDay = $today->add(\DateInterval::createFromDateString('-'. $i . 'day'));
            $targetDay = $targetDay->format('Ymd');
            $item['date'] = $targetDay;
            $item['num'] = isset($lists[$targetDay]) ? $lists[$targetDay]: 0;
            $data[] = $item;
        }
        return $data;
    }

    /**
     * @notes 签到排行榜
     * @return array
     */
    public static function topData()
    {
        $fieldNum = 'count(sl.id) as num, u.nickname,u.avatar';
        $topNum = SignLog::alias('sl')
            ->leftJoin('user u', 'u.id = sl.user_id')
            ->field($fieldNum)
            ->group('u.id')
            ->order('num', 'desc')
            ->limit(10)
            ->select()
            ->toArray();
        foreach($topNum as &$item) {
            $item['avatar'] = FileService::getFileUrl($item['avatar']);
        }
        $fieldAward = 'sum(al.change_amount) as amount, u.nickname,u.avatar';
        $topAward = AccountLog::alias('al')
            ->leftJoin('user u', 'u.id = al.user_id')
            ->field($fieldAward)
            ->where('change_type', AccountLogEnum::BW_INC_SIGN)
            ->group('u.id')
            ->order('amount', 'desc')
            ->limit(10)
            ->select()
            ->toArray();
        foreach($topAward as &$item) {
            $item['avatar'] = FileService::getFileUrl($item['avatar']);
            $item['amount'] = (int)$item['amount'];
        }
        return [
            'top_num' => $topNum,
            'top_award' => $topAward
        ];
    }
}