<?php

namespace app\admin\controller\game;

use app\common\controller\Backend;
use app\common\service\GameBetSettleService;
use support\think\Db;
use support\Response;
use Webman\Http\Request as WebmanRequest;

/**
 * 游玩记录（原压注订单）
 */
class PlayRecord extends Backend
{
    protected ?object $model = null;

    protected bool $modelValidate = false;

    protected string|array $quickSearchField = ['id', 'period_no', 'idempotency_key'];

    protected string|array $defaultSortField = ['id' => 'desc'];

    protected string|array $orderGuarantee = ['id' => 'desc'];

    protected array $withJoinTable = ['user', 'channel', 'gameRecord'];

    protected function initController(WebmanRequest $request): ?Response
    {
        $this->model = new \app\common\model\PlayRecord();
        return null;
    }

    public function add(WebmanRequest $request): Response
    {
        $response = $this->initializeBackend($request);
        if ($response !== null) {
            return $response;
        }
        return $this->error(__('Play record is generated by game API; manual creation is not allowed'));
    }

    public function edit(WebmanRequest $request): Response
    {
        $response = $this->initializeBackend($request);
        if ($response !== null) {
            return $response;
        }
        return $this->error(__('Play record cannot be edited'));
    }

    public function del(WebmanRequest $request): Response
    {
        $response = $this->initializeBackend($request);
        if ($response !== null) {
            return $response;
        }
        return $this->error(__('Play record cannot be deleted'));
    }

    public function sortable(WebmanRequest $request): Response
    {
        $response = $this->initializeBackend($request);
        if ($response !== null) {
            return $response;
        }
        return $this->error(__('Sorting is not supported'));
    }

    protected function _index(): Response
    {
        if ($this->request && $this->request->get('select')) {
            return $this->select($this->request);
        }

        list($where, $alias, $limit, $order) = $this->queryBuilder();
        $table = strtolower($this->model->getTable());
        $mainShort = $alias[$table] ?? '';
        if ($mainShort !== '' && $this->auth && !$this->auth->isSuperAdmin()) {
            $where[] = ['user.admin_id', 'in', $this->scopedAdminIds()];
        }

        // 避免 ThinkORM withJoin 对 game_record 的字段缓存导致 select 出已删除列（如 preset_number）
        // 这里改为手写 join + 明确 field 列表，保证数据库字段变更后不受 schema 缓存影响。
        $query = Db::name($table)->alias($mainShort !== '' ? $mainShort : 'play_record')
            ->leftJoin('user user', 'user.id = ' . ($mainShort !== '' ? $mainShort : 'play_record') . '.user_id')
            ->leftJoin('channel channel', 'channel.id = ' . ($mainShort !== '' ? $mainShort : 'play_record') . '.channel_id')
            ->leftJoin('game_record game_record', 'game_record.id = ' . ($mainShort !== '' ? $mainShort : 'play_record') . '.period_id')
            ->where($where);

        $res = $query
            ->field([
                ($mainShort !== '' ? $mainShort : 'play_record') . '.*',
                'user.username as user__username',
                'user.phone as user__phone',
                'channel.name as channel__name',
                'game_record.period_no as gameRecord__period_no',
                'game_record.status as gameRecord__status',
            ])
            ->order($order)
            ->paginate($limit);

        $list = $res->items();
        $total = $res->total();

        // 将 join 扁平字段还原为原页面所需结构：user/channel/gameRecord
        foreach ($list as $idx => $row) {
            if (!is_array($row)) {
                continue;
            }
            $row['user'] = [
                'username' => isset($row['user__username']) ? (string) $row['user__username'] : '',
                'phone' => isset($row['user__phone']) ? (string) $row['user__phone'] : '',
            ];
            $row['channel'] = [
                'name' => isset($row['channel__name']) ? (string) $row['channel__name'] : '',
            ];
            $row['gameRecord'] = [
                'period_no' => isset($row['gameRecord__period_no']) ? (string) $row['gameRecord__period_no'] : '',
                'status' => isset($row['gameRecord__status']) && is_numeric((string) $row['gameRecord__status'])
                    ? (int) $row['gameRecord__status']
                    : null,
            ];
            unset(
                $row['user__username'],
                $row['user__phone'],
                $row['channel__name'],
                $row['gameRecord__period_no'],
                $row['gameRecord__status'],
            );
            $list[$idx] = $row;
        }

        $threshold = $this->jackpotMaxAmount();
        foreach ($list as $idx => $row) {
            if (!is_array($row)) {
                continue;
            }
            $status = isset($row['status']) && is_numeric($row['status']) ? (int) $row['status'] : 0;
            $win = bcadd(strval($row['win_amount'] ?? '0'), '0', 2);
            $needReview = bccomp($threshold, '0', 2) > 0 && bccomp($win, $threshold, 2) >= 0;
            $canApprove = $needReview && $status === GameBetSettleService::PLAY_STATUS_PENDING_REVIEW;
            $row['jackpot_need_review'] = $needReview ? 1 : 0;
            $row['can_jackpot_approve'] = $canApprove ? 1 : 0;
            $list[$idx] = $row;
        }

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

    /**
     * 大奖审核通过并派彩（仅 win_amount >= game_config.jackpot_max_amount 且 status=待审核 才可操作）
     */
    public function approveJackpot(WebmanRequest $request): Response
    {
        $response = $this->initializeBackend($request);
        if ($response !== null) {
            return $response;
        }
        if ($request->method() !== 'POST') {
            return $this->error(__('Parameter error'));
        }

        $idRaw = $request->post('id');
        if ($idRaw === null || $idRaw === '' || !is_numeric(strval($idRaw))) {
            return $this->error(__('Parameter error'));
        }
        $id = (int) $idRaw;
        if ($id <= 0) {
            return $this->error(__('Parameter error'));
        }
        $remarkRaw = $request->post('remark');
        $remark = is_string($remarkRaw) ? trim($remarkRaw) : '';

        // 权限范围校验：复用列表逻辑（非超管只能操作其下辖用户）
        if ($this->auth && !$this->auth->isSuperAdmin()) {
            $uidRaw = Db::name('game_play_record')->where('id', $id)->value('user_id');
            $uid = ($uidRaw === null || $uidRaw === '' || !is_numeric(strval($uidRaw))) ? 0 : (int) $uidRaw;
            if ($uid <= 0) {
                return $this->error(__('Record not found'));
            }
            $ownerAdminId = Db::name('user')->where('id', $uid)->value('admin_id');
            $aid = ($ownerAdminId === null || $ownerAdminId === '' || !is_numeric(strval($ownerAdminId))) ? 0 : (int) $ownerAdminId;
            if ($aid <= 0 || !in_array($aid, $this->scopedAdminIds(), true)) {
                return $this->error(__('You have no permission'));
            }
        }

        $adminId = $this->auth ? (int) ($this->auth->id ?? 0) : 0;

        Db::startTrans();
        try {
            $result = GameBetSettleService::approveJackpotPlayRecord($id, $adminId, $remark);
            if (($result['ok'] ?? false) !== true) {
                Db::rollback();
                $msg = is_string($result['msg'] ?? null) ? $result['msg'] : __('Parameter error');
                return $this->error($msg);
            }
            Db::commit();
        } catch (\Throwable $e) {
            Db::rollback();
            return $this->error($e->getMessage());
        }

        return $this->success(__('Approved'));
    }

    /**
     * 大奖审核拒绝（remark 必填）
     */
    public function rejectJackpot(WebmanRequest $request): Response
    {
        $response = $this->initializeBackend($request);
        if ($response !== null) {
            return $response;
        }
        if ($request->method() !== 'POST') {
            return $this->error(__('Parameter error'));
        }
        $idRaw = $request->post('id');
        if ($idRaw === null || $idRaw === '' || !is_numeric(strval($idRaw))) {
            return $this->error(__('Parameter error'));
        }
        $id = (int) $idRaw;
        if ($id <= 0) {
            return $this->error(__('Parameter error'));
        }
        $remarkRaw = $request->post('remark');
        $remark = is_string($remarkRaw) ? trim($remarkRaw) : '';
        if ($remark === '') {
            return $this->error(__('Please provide reject reason'));
        }

        if ($this->auth && !$this->auth->isSuperAdmin()) {
            $uidRaw = Db::name('game_play_record')->where('id', $id)->value('user_id');
            $uid = ($uidRaw === null || $uidRaw === '' || !is_numeric(strval($uidRaw))) ? 0 : (int) $uidRaw;
            if ($uid <= 0) {
                return $this->error(__('Record not found'));
            }
            $ownerAdminId = Db::name('user')->where('id', $uid)->value('admin_id');
            $aid = ($ownerAdminId === null || $ownerAdminId === '' || !is_numeric(strval($ownerAdminId))) ? 0 : (int) $ownerAdminId;
            if ($aid <= 0 || !in_array($aid, $this->scopedAdminIds(), true)) {
                return $this->error(__('You have no permission'));
            }
        }

        $adminId = $this->auth ? (int) ($this->auth->id ?? 0) : 0;
        Db::startTrans();
        try {
            $result = GameBetSettleService::rejectJackpotPlayRecord($id, $adminId, $remark);
            if (($result['ok'] ?? false) !== true) {
                Db::rollback();
                $msg = is_string($result['msg'] ?? null) ? $result['msg'] : __('Parameter error');
                return $this->error($msg);
            }
            Db::commit();
        } catch (\Throwable $e) {
            Db::rollback();
            return $this->error($e->getMessage());
        }
        return $this->success(__('Rejected'));
    }

    /**
     * @return int[]
     */
    private function scopedAdminIds(): array
    {
        if (!$this->auth) {
            return [0];
        }
        if ($this->auth->isSuperAdmin()) {
            return [];
        }
        $groupIds = $this->auth->getAdminChildGroups();
        $adminIds = $groupIds ? $this->auth->getGroupAdmins($groupIds) : [];
        $adminIds[] = $this->auth->id;
        $adminIds = array_map(static fn($id) => intval(strval($id)), $adminIds);
        $adminIds = array_values(array_unique(array_filter($adminIds, static fn($id) => $id > 0)));
        return $adminIds === [] ? [0] : $adminIds;
    }

    private function jackpotMaxAmount(): string
    {
        $row = Db::name('game_config')->where('config_key', GameBetSettleService::CONFIG_KEY_JACKPOT_MAX_AMOUNT)->find();
        if (!is_array($row)) {
            return '0.00';
        }
        $raw = $row['config_value'] ?? null;
        if ($raw === null || $raw === '') {
            return '0.00';
        }
        $v = is_string($raw) ? trim($raw) : (is_numeric($raw) ? strval($raw) : '');
        if ($v === '' || !is_numeric($v)) {
            return '0.00';
        }
        $normalized = bcadd($v, '0', 2);
        if (bccomp($normalized, '0', 2) <= 0) {
            return '0.00';
        }
        return $normalized;
    }
}

