<?php

namespace app\admin\controller\user;

use app\admin\model\PromoReward;
use app\common\service\JK8Services;
use Throwable;
use app\common\controller\Backend;
use app\admin\model\User as UserModel;
use app\admin\model\UserScore;

class User extends Backend
{
    /**
     * @var object
     * @phpstan-var UserModel
     */
    protected object $model;
    protected object $score;

    protected array $withJoinTable = ['userGroup'];
    protected $jk8Services;

    // 排除字段
    protected string|array $preExcludeFields = ['last_login_time', 'login_failure', 'password', 'salt'];

    protected string|array $quickSearchField = ['username', 'nickname', 'id'];

    public function initialize(): void
    {
        parent::initialize();
        $this->jk8Services = app(JK8Services::class);
        $this->model = new UserModel();
        $this->score = new UserScore();
    }

    /**
     * 验证逻辑
     */
    protected function validateModelData(array $data, string $scene = ''): void
    {
        if (!$this->modelValidate) return;

        $validateClass = str_replace("\\model\\", "\\validate\\", get_class($this->model));
        if (class_exists($validateClass)) {
            $validate = new $validateClass();
            if ($scene) $validate->scene($scene);
            $validate->check($data);
        }
    }

    /**
     * 查看
     * @throws Throwable
     */
    public function index(): void
    {
        if ($this->request->param('select')) {
            $this->select();
        }

        list($where, $alias, $limit, $order) = $this->queryBuilder();
        $res = $this->model
            ->withoutField('password,salt')
            ->withJoin($this->withJoinTable, $this->withJoinType)
            ->alias($alias)
            ->where($where)
            ->order($order)
            ->paginate($limit);

        $this->success('', [
            'list'   => $res->items(),
            'total'  => $res->total(),
            'remark' => get_route_remark(),
        ]);
    }

    /**
     * 添加
     * @throws Throwable
     */
    public function add(): void
    {
        if (!$this->request->isPost()) {
            $this->error(__('Parameter error'));
        }
        $data = $this->request->post();
        if (!$data) {
            $this->error(__('Parameter %s can not be empty', ['']));
        }

        $result = false;
        $passwd = $data['password']; // 密码将被排除不直接入库
        $data   = $this->excludeFields($data);

        try {
            // 模型验证
            $this->validateModelData($data, 'add');
            $jkId = $this->jk8Services->register($data['mobile'], $data['nickname'] ?? '', $data['referrer_code'] ?? '');
            $jkUserName = $this->jk8Services->getAllUsers($jkId);
        } catch (Throwable $e) {
            $this->error($e->getMessage());
        }
        if (!empty($data['referrer_code'])) {
            $parentId = $this->model->where('jk_username', $data['referrer_code'])->value('id');
            $data['parent_id'] = $parentId;
        }
        $this->model->startTrans();
        try {
            $data['jk_user_id'] = $jkId;
            $data['jk_username'] = $jkUserName;
            $result = $this->model->save($data);
            $this->model->commit();

            if (!empty($passwd)) {
                $this->model->resetPassword($this->model->id, $passwd);
            }
        } catch (Throwable $e) {
            $this->model->rollback();
            $this->error($e->getMessage());
        }
        if ($result !== false) {
            $this->success(__('Added successfully'));
        } else {
            $this->error(__('No rows were added'));
        }
    }

    /**
     * 编辑
     * @throws Throwable
     */
    public function edit(): void
    {
        $pk  = $this->model->getPk();
        $id  = $this->request->param($pk);
        $row = $this->model->find($id);
        if (!$row) {
            $this->error(__('Record not found'));
        }

        if ($this->request->isPost()) {
            $password = $this->request->post('password', '');
            if ($password) {
                $this->model->resetPassword($id, $password);
            }
            parent::edit();
        }

        unset($row->salt);
        $row->password = '';
        $this->success('', [
            'row' => $row
        ]);
    }

    /**
     * 重写select
     * @throws Throwable
     */
    public function select(): void
    {
        list($where, $alias, $limit, $order) = $this->queryBuilder();
        $res = $this->model
            ->withoutField('password,salt')
            ->withJoin($this->withJoinTable, $this->withJoinType)
            ->alias($alias)
            ->where($where)
            ->order($order)
            ->paginate($limit);

        foreach ($res as $re) {
            $re->nickname_text = $re->username . '(ID:' . $re->id . ')';
        }

        $this->success('', [
            'list'   => $res->items(),
            'total'  => $res->total(),
            'remark' => get_route_remark(),
        ]);
    }

    /**
     * 钱包
     * @throws Throwable
     */
    public function wallet(): void
    {
        $miniGames = config('mini_game') ?: [];
        $pk  = $this->model->getPk();
        $id  = $this->request->param($pk);

        if ($this->request->isPost()) {
            $this->model = new UserScore();
            parent::edit();
            return;
        }

        $row = $this->model->find($id);
        if (!$row) {
            $this->error(__('Record not found'));
        }
        $existGameTypes = $row->userScore()
            ->whereIn('game_type', array_keys($miniGames))
            ->column('game_type');

        $scoreInsert = [];
        foreach ($miniGames as $key => $name) {
            if (!in_array($key, $existGameTypes)) {
                $scoreInsert[] = [
                    'user_id'   => $id,
                    'game_type' => $key,
                    'score'     => 0,
                ];
            }
        }

        if (!empty($scoreInsert)) {
            $row->userScore()->saveAll($scoreInsert);
        }

        $data = [
            'mini_game' => $miniGames,
            'score'     => $row->userScore()
                ->whereIn('game_type', array_keys($miniGames))
                ->withoutField(['user_id'])
                ->order('game_type', 'asc')
                ->select()
        ];
        $this->success('', $data);
    }

    public function submittedReward()
    {
        $games = config('mini_game') ?: [];
        $rawStart = request()->param('start/s');
        $start = $rawStart ? strtotime($rawStart) : strtotime('today');
        $rawEnd = request()->param('end/s');
        $end = $rawEnd ? strtotime("$rawEnd +1 day") : strtotime('tomorrow');
        $status = $this->request->param('status');
        $username = $this->request->param('username');
        $gameId = $this->request->param('game_id');
        $limit = request()->param('limit/d') ?? 15;
        $where = [];
        if ($start > $end) {
            list($start, $end) = [$end, $start];
        }
        if (!empty($gameId)) {
            $where[] = ['game_type', '=', $gameId];
        }

        if (!empty($status)) {
            $where[] = ['status', '=', $status];
        }

        $query = PromoReward::with(['user']);

        if (!empty($username)) {
            $has = UserModel::where('jk_username', 'LIKE', '%'. $username . '%');
            $query->hasWhere('user', $has);
        }

        $list = $query->where($where)
            ->whereBetweenTime('create_time', $start, $end)->order('create_time', 'desc')->paginate($limit);

        $list->each(function($item) use ($games) {
            $item->submitted_time = date('Y-m-d H:i:s', $item->update_time);
            $item->username = $item->user->jk_username ?? 'Unknown';
            $gameName = $games[$item->game_type] ?? 'Game';
            $item->reward_claim = $gameName . ' AUD' . $item->amount;

            if ($item->status == 1) {
                $item->status_text = 'Approve Reward (by JDK API (Manual))';
            } elseif ($item->status == 2){
                $item->status_text = 'Reject Reward';
            } else {
                $item->status_text = 'In process';
            }
            unset($item->user);
        });
        $this->success('', [
            'game_id' => $gameId,
            'games' => $games,
            'list' => $list
        ]);
    }
    public function editReward()
    {
        $pk  = $this->model->getPk();
        $id  = $this->request->param($pk);
        $promoReward = new PromoReward();
        $row = $promoReward->find($id);
        if (!$row) {
            $this->error(__('Record not found'));
        }

        $status = $this->request->post('status');

        if (!$status || !in_array($status, [1, 2])) {
            $this->error(__('Parameter %s can not be empty', ['']));
        }

        $result = false;
        $promoReward->startTrans();
        try {
            if ($status == 1) {
                $user = UserModel::find($row['user_id']);
                $this->jk8Services->setScore($user['jk_username'], $row['amount']);
            }
            $result = $row->save([
                'status' => (int)$status,
                'update_time' => time(),
            ]);
            $promoReward->commit();
        } catch (Throwable $e) {
            $promoReward->rollback();
            $this->error($e->getMessage());
        }
        if ($result !== false) {
            $this->success(__('Update successful'));
        } else {
            $this->error(__('No rows updated'));
        }
    }
}