<?php

namespace app\admin\controller\game;

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

/**
 * 游戏对局记录
 */
class Record extends Backend
{
    protected ?object $model = null;

    protected string|array $preExcludeFields = ['id', 'create_time', 'update_time', 'platform_profit_amount', 'winner_user_count'];

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

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

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

    protected bool $modelValidate = true;

    protected bool $modelSceneValidate = true;

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

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

        list($where, $alias, $limit, $order) = $this->queryBuilder();

        $res = $this->model
            ->field($this->indexField)
            ->withJoin($this->withJoinTable, $this->withJoinType)
            ->with($this->withJoinTable)
            ->alias($alias)
            ->where($where)
            ->order($order)
            ->paginate($limit);

        $list = $res->items();
        foreach ($list as $idx => $row) {
            if (!is_array($row)) {
                continue;
            }
            $status = isset($row['status']) && is_numeric((string) $row['status']) ? (int) $row['status'] : 0;
            $reason = isset($row['void_reason']) && is_string($row['void_reason']) ? $row['void_reason'] : '';
            // 将“系统自愈作废”的对局在列表中标记为【异常】（展示态，不改库中 status=5 的事实）
            if ($status === 5 && $reason !== '' && str_starts_with($reason, 'system_recover:')) {
                $row['status'] = 6;
                $list[$idx] = $row;
            }
        }

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

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

    public function edit(WebmanRequest $request): Response
    {
        $response = $this->initializeBackend($request);
        if ($response !== null) {
            return $response;
        }
        if ($request->method() === 'POST') {
            return $this->error(__('Game record cannot be edited'));
        }
        $pk = $this->model->getPk();
        $id = $request->get($pk);
        $row = $this->model->find($id);
        if (!$row) {
            return $this->error(__('Record not found'));
        }
        return $this->success('', ['row' => $row]);
    }

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

    public function abnormalList(WebmanRequest $request): Response
    {
        $response = $this->initializeBackend($request);
        if ($response !== null) {
            return $response;
        }

        $limitRaw = $request->get('limit', 30);
        $limit = is_numeric((string) $limitRaw) ? (int) $limitRaw : 30;
        if ($limit < 1) {
            $limit = 1;
        }
        if ($limit > 200) {
            $limit = 200;
        }

        $rows = Db::name('game_record')
            ->where('status', 5)
            // 仅展示服务重启自愈导致的异常作废，排除管理员手动作废
            ->whereLike('void_reason', 'system_recover:%')
            ->field(['id', 'period_no', 'void_reason', 'update_time'])
            ->order('id', 'desc')
            ->limit($limit)
            ->select()
            ->toArray();

        $periodIds = [];
        foreach ($rows as $row) {
            $pid = (int) ($row['id'] ?? 0);
            if ($pid > 0) {
                $periodIds[] = $pid;
            }
        }
        $refundAggByPeriod = [];
        $refundIdsByPeriod = [];
        if ($periodIds !== []) {
            $aggRows = Db::name('bet_order')
                ->whereIn('period_id', $periodIds)
                ->where('status', 3)
                ->fieldRaw('period_id as pid, COUNT(*) as cnt, COUNT(DISTINCT user_id) as users, COALESCE(SUM(total_amount), 0) as amt')
                ->group('period_id')
                ->select()
                ->toArray();
            foreach ($aggRows as $a) {
                $pid = (int) ($a['pid'] ?? 0);
                if ($pid <= 0) {
                    continue;
                }
                $refundAggByPeriod[$pid] = [
                    'orders' => (int) ($a['cnt'] ?? 0),
                    'users' => (int) ($a['users'] ?? 0),
                    'amount' => (string) ($a['amt'] ?? '0.00'),
                ];
            }

            $idRows = Db::name('bet_order')
                ->whereIn('period_id', $periodIds)
                ->where('status', 3)
                ->field(['period_id', 'id'])
                ->order('id', 'desc')
                ->limit(2000)
                ->select()
                ->toArray();
            foreach ($idRows as $r) {
                $pid = (int) ($r['period_id'] ?? 0);
                $bid = (int) ($r['id'] ?? 0);
                if ($pid <= 0 || $bid <= 0) {
                    continue;
                }
                if (!isset($refundIdsByPeriod[$pid])) {
                    $refundIdsByPeriod[$pid] = [];
                }
                if (count($refundIdsByPeriod[$pid]) < 50) {
                    $refundIdsByPeriod[$pid][] = $bid;
                }
            }
        }

        $list = [];
        foreach ($rows as $row) {
            $meta = $this->parseRecoverVoidReason(is_string($row['void_reason'] ?? null) ? $row['void_reason'] : '');
            $reason = is_string($row['void_reason'] ?? null) ? $row['void_reason'] : '';
            $isAutoRecover = $this->isSystemRecoverReason($reason);
            $pid = (int) ($row['id'] ?? 0);
            $agg = $refundAggByPeriod[$pid] ?? null;
            $users = (int) ($meta['users'] ?? 0);
            $orders = (int) ($meta['orders'] ?? 0);
            $amount = is_string($meta['amount'] ?? null) ? $meta['amount'] : '0.00';
            if (is_array($agg)) {
                if ($orders <= 0 && ($agg['orders'] ?? 0) > 0) {
                    $orders = (int) ($agg['orders'] ?? 0);
                }
                if ($users <= 0 && ($agg['users'] ?? 0) > 0) {
                    $users = (int) ($agg['users'] ?? 0);
                }
                if (bccomp($amount, '0', 2) <= 0 && is_string($agg['amount'] ?? null)) {
                    $amount = (string) $agg['amount'];
                }
            }
            $list[] = [
                'id' => (int) ($row['id'] ?? 0),
                'period_no' => (string) ($row['period_no'] ?? ''),
                'abnormal_from_status' => $meta['from_status'],
                'refunded_user_count' => $users,
                'refunded_order_count' => $orders,
                'refunded_total_amount' => $amount,
                'refunded_order_ids' => $refundIdsByPeriod[$pid] ?? [],
                'recovered_at' => (int) ($row['update_time'] ?? 0),
                'void_reason' => $reason,
                'is_auto_recover' => $isAutoRecover ? 1 : 0,
            ];
        }

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

    /**
     * 某期对局的游玩（压注）记录列表（用于对局记录页弹窗查看）。
     */
    public function playRecordList(WebmanRequest $request): Response
    {
        $response = $this->initializeBackend($request);
        if ($response !== null) {
            return $response;
        }

        $periodIdRaw = $request->get('period_id');
        if (!is_numeric((string) $periodIdRaw)) {
            return $this->error(__('Parameter error'));
        }
        $periodId = (int) $periodIdRaw;
        if ($periodId <= 0) {
            return $this->error(__('Parameter error'));
        }

        $pageRaw = $request->get('page', 1);
        $page = is_numeric((string) $pageRaw) ? (int) $pageRaw : 1;
        if ($page < 1) {
            $page = 1;
        }

        $limitRaw = $request->get('limit', 30);
        $limit = is_numeric((string) $limitRaw) ? (int) $limitRaw : 30;
        if ($limit < 1) {
            $limit = 1;
        }
        if ($limit > 200) {
            $limit = 200;
        }

        $query = Db::name('game_play_record')
            ->alias('pr')
            ->leftJoin('user u', 'u.id = pr.user_id')
            ->leftJoin('channel c', 'c.id = pr.channel_id')
            ->where('pr.period_id', $periodId);

        $total = (int) $query->count('pr.id');
        $list = $query
            ->field([
                'pr.id',
                'pr.period_id',
                'pr.user_id',
                'pr.channel_id',
                'pr.pick_numbers',
                'pr.total_amount',
                'pr.streak_at_bet',
                'pr.is_auto',
                'pr.win_amount',
                'pr.jackpot_extra_amount',
                'pr.status',
                'pr.idempotency_key',
                'pr.create_time',
                'pr.update_time',
                'u.username as user_username',
                'c.name as channel_name',
            ])
            ->order('pr.id', 'desc')
            ->page($page, $limit)
            ->select()
            ->toArray();

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

    /**
     * @return array{from_status:int,users:int,orders:int,amount:string}
     */
    private function parseRecoverVoidReason(string $reason): array
    {
        $meta = [
            'from_status' => -1,
            'users' => 0,
            'orders' => 0,
            'amount' => '0.00',
        ];
        if (!$this->isSystemRecoverReason($reason)) {
            return $meta;
        }
        $payload = substr($reason, strlen('system_recover:'));
        if (!str_contains($payload, '=')) {
            return $meta;
        }
        $parts = explode('|', $payload);
        foreach ($parts as $part) {
            $item = trim($part);
            if ($item === '' || !str_contains($item, '=')) {
                continue;
            }
            [$key, $value] = explode('=', $item, 2);
            $key = trim($key);
            $value = trim($value);
            if ($key === 'from' && is_numeric($value)) {
                $meta['from_status'] = (int) $value;
                continue;
            }
            if ($key === 'users' && is_numeric($value)) {
                $meta['users'] = (int) $value;
                continue;
            }
            if ($key === 'orders' && is_numeric($value)) {
                $meta['orders'] = (int) $value;
                continue;
            }
            if ($key === 'amount' && $value !== '') {
                $meta['amount'] = $value;
            }
        }
        return $meta;
    }

    private function isSystemRecoverReason(string $reason): bool
    {
        return $reason !== '' && str_starts_with($reason, 'system_recover:');
    }
}
