<?php

namespace app\models\activity;

use app\models\mining\UserMiningMachine;
use app\models\system\SystemMoney;
use app\models\user\User;
use app\models\user\UserBill;
use app\models\user\UserMoney;
use Exception;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use crmeb\traits\ModelTrait;
use crmeb\basic\BaseModel;

/**
 * TODO 文章Model
 * Class Article
 * @package app\models\article
 */
class ActivityJoin extends BaseModel
{
    /**
     * 数据表主键
     * @var string
     */
    protected $pk = 'id';

    /**
     * 模型名称
     * @var string
     */
    protected $name = 'activity_join';

    use ModelTrait;

    public function user()
    {
        return self::hasOne(User::class, 'uid', 'uid')->field('uid,nickname,phone,email,account,avatar');
    }

    public function activity()
    {
        return self::hasOne(Activity::class, 'id', 'aid')->field('name');
    }

    /**
     * @param $page
     * @param $limit
     * @return array
     */
    public static function getList($where): array
    {
        $model = new self();
        $data = $model->with(['user', 'activity'])
            ->where('aid', $where['id'])
            ->page((int)$where['page'], (int)$where['limit'])
            ->select()->each(function ($item) {
                $item['status_name'] = ($item['status'] == 1 ? '一级' : ($item['status'] == 2 ? '二级' : ($item['status'] == 3 ? '三级' : '未知')));
                $item['add_time_text'] = date('Y-m-d H:i:s', $item['add_time']);
            });
        $count = $model->count();
        return compact('data', 'count');
    }

    /**
     * @param $id
     * @param $uid
     */
    public static function join($id, $uid)
    {
        $activity = Activity::get($id);
        if (!$activity) return self::setErrorInfo('找不到活动');
        $user_join = self::where('uid', $uid)
            ->where('aid', $id)
            ->order('add_time', 'desc')
            ->find();
        if (!$user_join) {
            //首次参与
            BaseModel::beginTrans();
            try {
                //支付参与金额给上级
                $user = User::getUserInfo($uid);
                $gp_point = self::getUpPoint($user, $id);
                if (!$gp_point) {
                    BaseModel::rollbackTrans();
                    return self::setErrorInfo(self::getErrorInfo());
                }
                $res1 = self::create([
                    'uid' => $uid,
                    'aid' => $id,
                    'status' => 1,
                    'group_num' => $gp_point,
                    'add_time' => time(),
                ]);
                $up_user = intval(ceil(($gp_point - 1) / $activity['explode_num']));
                $info = self::where('aid', $id)->where('group_num', $up_user)->find();
                $res2 = ActivityCheck::create([
                    'uid' => $uid,
                    'aid' => $id,
                    'uaid' => $res1->id,
                    'money_type' => $activity['l1_money_type'],
                    'money' => $activity['l1_money'],
                    'status' => 1,
                    'layer' => 1,
                    'to_uid' => $info ? $info['uid'] : 0,
                    'add_time' => time(),
                ]);
                $res3 = UserMoney::activityTradeMoney($id, $uid, $info ? $info['uid'] : 0, $res2->id, 1, $activity['l1_money_type'], $activity['l1_money']);
                if ($res1 && $res2 && $res3) {
                    BaseModel::commitTrans();
                    return true;
                } else {
                    BaseModel::rollbackTrans();
                    return self::setErrorInfo('参与失败:' .
                        (!$res1 ? '生成参与记录失败,' : '') .
                        (!$res2 ? '生成审核记录失败,' : '') .
                        (!$res3 ? UserMoney::getErrorInfo() : ''));
                }
            } catch (Exception $e) {
                BaseModel::rollbackTrans();
                return self::setErrorInfo($e->getMessage());
            }
        } else {
            //已有记录
            if ($user_join['status'] >= 3) {
                //是否出局
                $explode_num = $activity['explode_num'];
                $gp_point_list = [];
                $p = 1;
                for ($i = $explode_num - 2; $i >= -1; $i--) {
                    $gp_point_list[] = $user_join['group_num'] * $explode_num - $i;
                }
                while ($p <= 3) {
                    $member_list = self::where('aid', $id)->where('status', '>=', $p)->where('group_num', 'in', $gp_point_list)->order('group_num', 'asc')->select();
                    if (count($member_list) < count($gp_point_list)) {
                        return self::setErrorInfo('尚未出局');
                    }
                    $gp_point_list = [];
                    foreach ($member_list as $v) {
                        for ($i = $explode_num - 2; $i >= -1; $i--) {
                            $gp_point_list[] = $v['group_num'] * $explode_num - $i;
                        }
                    }
                    $p++;
                }
                //再次参与
                BaseModel::beginTrans();
                try {
                    //支付参与金额给上级
                    $user = User::getUserInfo($uid);
                    $gp_point = self::getUpPoint($user, $id, 1);
                    if (!$gp_point) {
                        BaseModel::rollbackTrans();
                        return self::setErrorInfo(self::getErrorInfo());
                    }
                    $res1 = self::create([
                        'uid' => $uid,
                        'aid' => $id,
                        'status' => 1,
                        'group_num' => $gp_point,
                        'add_time' => time(),
                    ]);
                    $up_user = intval(ceil(($gp_point - 1) / $activity['explode_num']));
                    $info = self::where('aid', $id)->where('group_num', $up_user)->find();
                    $res2 = ActivityCheck::create([
                        'uid' => $uid,
                        'aid' => $id,
                        'uaid' => $res1->id,
                        'money_type' => $activity['l1_money_type'],
                        'money' => $activity['l1_money'],
                        'status' => 1,
                        'layer' => 1,
                        'to_uid' => $info ? $info['uid'] : 0,
                        'add_time' => time(),
                    ]);
                    $res3 = UserMoney::activityTradeMoney($id, $uid, $info ? $info['uid'] : 0, $res2->id, 1, $activity['l1_money_type'], $activity['l1_money']);
                    if ($res1 && $res2 && $res3) {
                        BaseModel::commitTrans();
                        return true;
                    } else {
                        BaseModel::rollbackTrans();
                        return self::setErrorInfo('参与失败:' .
                            (!$res1 ? '生成参与记录失败,' : '') .
                            (!$res2 ? '生成审核记录失败,' : '') .
                            (!$res3 ? UserMoney::getErrorInfo() : ''));
                    }
                } catch (Exception $e) {
                    BaseModel::rollbackTrans();
                    return self::setErrorInfo($e->getMessage());
                }
            } else {
                //升级
                BaseModel::beginTrans();
                try {
                    $gp_point = $user_join['group_num'];
                    for ($i = 0; $i < $user_join['status'] + 1; $i++) {
                        $gp_point = intval(ceil(($gp_point - 1) / $activity['explode_num']));
                    }
                    $info = self::where('aid', $id)->where('group_num', $gp_point)->find();
                    $res2 = ActivityCheck::create([
                        'uid' => $uid,
                        'aid' => $id,
                        'uaid' => $user_join['id'],
                        'money_type' => $activity['l' . ($user_join['status'] + 1) . '_money_type'],
                        'money' => $activity['l' . ($user_join['status'] + 1) . '_money'],
                        'status' => 1,
                        'layer' => $user_join['status'] + 1,
                        'to_uid' => $info ? $info['uid'] : 0,
                        'add_time' => time(),
                    ]);
                    $res3 = UserMoney::activityTradeMoney($id, $uid, $info ? $info['uid'] : 0, $res2->id, $user_join['status'] + 1, $activity['l' . ($user_join['status'] + 1) . '_money_type'], $activity['l' . ($user_join['status'] + 1) . '_money'], (isset($info) && $info['status'] >= ($user_join['status'] + 1)) ? 1 : 0);
                    $res1 = self::where('id', $user_join['id'])->update(['status' => $user_join['status'] + 1]);
                    $res4 = self::sendMoney($id, $uid, $user_join['status'] + 1);
                    if ($res1 && $res2 && $res3 && $res4) {
                        BaseModel::commitTrans();
                        return true;
                    } else {
                        BaseModel::rollbackTrans();
                        return self::setErrorInfo('参与失败:' .
                            (!$res1 ? '修改参与记录失败,' : '') .
                            (!$res2 ? '生成审核记录失败,' : '') .
                            (!$res3 ? (UserMoney::getErrorInfo() . ',') : '') .
                            (!$res4 ? self::getErrorInfo() : ''));
                    }
                } catch (Exception $e) {
                    BaseModel::rollbackTrans();
                    return self::setErrorInfo($e->getMessage());
                }
            }
        }
    }

    public static function sendMoney($id, $uid, $layer)
    {
        $list = UserBill::where(['pm' => 1, 'status' => 0])
            ->where('type', 'activity_income')
            ->where('aid', $id)->where('uid', $uid)->where('layer', $layer)
            ->select();
        if ($list) {
            try {
                foreach ($list as $v) {
                    UserMoney::sendMoney($v['id']);
                }
                return true;
            } catch (Exception $e) {
                return self::setErrorInfo($e->getMessage());
            }
        }
        return true;
    }

    /**
     * 找公排点
     * @param $user
     * @param $id
     * @param bool $re
     * @return int|bool
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public static function getUpPoint($user, $id, bool $re = false)
    {
        $activity = Activity::get($id);
        if (!$activity) return self::setErrorInfo('找不到活动');
        $gp_point = 1;
        if (!self::where('aid', $id)->find()) {
            return $gp_point;
        }
        $user_join = self::where('aid', $id)->order('add_time', 'asc')->find();
        if ($re || $activity['group_type'] == 1) goto end;
        while ($user) {
            $user_join_check = self::where('uid', $user['spread_uid'])->where('aid', $id)->order('add_time', 'desc')->find();
            if (!$user_join_check) {
                $user = User::getUserInfo($user['spread_uid']);
            } else {
                $user_join = $user_join_check;
                break;
            }
        }
        end:
        //找推荐人的公排末位
        $gp_point = 1;
        $explode_num = $activity['explode_num'];
        $gp_point_list = [];
        for ($i = $explode_num - 2; $i >= -1; $i--) {
            $gp_point_list[] = $user_join['group_num'] * $explode_num - $i;
        }
        while (1) {
            $member_list = self::where('aid', $id)->where('group_num', 'in', $gp_point_list)->order('group_num', 'asc')->select();
            if (count($member_list) < count($gp_point_list)) {
                foreach ($gp_point_list as $k => $v) {
                    if (!isset($member_list[$k]) || $v != $member_list[$k]['group_num']) {
                        $gp_point = $v;
                        break;
                    }
                }
                break;
            }
            $gp_point_list = [];
            foreach ($member_list as $v) {
                for ($i = $explode_num - 2; $i >= -1; $i--) {
                    $gp_point_list[] = $v['group_num'] * $explode_num - $i;
                }
            }
        }
        return $gp_point;
    }
}