<?php
declare(strict_types=1);

namespace app\dice\controller;

use app\dice\helper\AdminScopeHelper;
use app\dice\model\player\DicePlayer;
use app\dice\model\player_wallet_record\DicePlayerWalletRecord;
use app\dice\model\play_record\DicePlayRecord;
use app\dice\model\reward\DiceRewardConfig;
use plugin\saiadmin\basic\BaseController;
use plugin\saiadmin\service\Permission;
use support\Request;
use support\Response;
use support\think\Db;

/**
 * 大富翁工作台数据统计
 */
class DiceDashboardController extends BaseController
{
    /**
     * 工作台卡片统计：玩家注册、充值、提现、游玩次数（含较上周对比）
     */
    #[Permission('工作台数据统计', 'core:console:list')]
    public function statistics(Request $request): Response
    {
        $thisWeekStart = date('Y-m-d 00:00:00', strtotime('monday this week'));
        $thisWeekEnd = date('Y-m-d 23:59:59', strtotime('sunday this week'));
        $lastWeekStart = date('Y-m-d 00:00:00', strtotime('monday last week'));
        $lastWeekEnd = date('Y-m-d 23:59:59', strtotime('sunday last week'));

        $adminInfo = $this->adminInfo ?? null;
        $filterDeptId = $request->input('dept_id');

        $playerQueryThis = DicePlayer::whereBetween('create_time', [$thisWeekStart, $thisWeekEnd]);
        $playerQueryLast = DicePlayer::whereBetween('create_time', [$lastWeekStart, $lastWeekEnd]);
        AdminScopeHelper::applyAdminScope($playerQueryThis, $adminInfo, $filterDeptId);
        AdminScopeHelper::applyAdminScope($playerQueryLast, $adminInfo, $filterDeptId);
        $playerThis = $playerQueryThis->count();
        $playerLast = $playerQueryLast->count();

        $chargeQueryThis = DicePlayerWalletRecord::where('type', 0)
            ->where('coin', '>', 0)
            ->whereBetween('create_time', [$thisWeekStart, $thisWeekEnd]);
        $chargeQueryLast = DicePlayerWalletRecord::where('type', 0)
            ->where('coin', '>', 0)
            ->whereBetween('create_time', [$lastWeekStart, $lastWeekEnd]);
        AdminScopeHelper::applyAdminScope($chargeQueryThis, $adminInfo, $filterDeptId);
        AdminScopeHelper::applyAdminScope($chargeQueryLast, $adminInfo, $filterDeptId);
        $chargeThis = $chargeQueryThis->sum('coin');
        $chargeLast = $chargeQueryLast->sum('coin');

        $withdrawQueryThis = DicePlayerWalletRecord::where('type', 1)
            ->whereBetween('create_time', [$thisWeekStart, $thisWeekEnd]);
        $withdrawQueryLast = DicePlayerWalletRecord::where('type', 1)
            ->whereBetween('create_time', [$lastWeekStart, $lastWeekEnd]);
        AdminScopeHelper::applyAdminScope($withdrawQueryThis, $adminInfo, $filterDeptId);
        AdminScopeHelper::applyAdminScope($withdrawQueryLast, $adminInfo, $filterDeptId);
        $withdrawThis = $withdrawQueryThis->sum(Db::raw('ABS(coin)'));
        $withdrawLast = $withdrawQueryLast->sum(Db::raw('ABS(coin)'));

        $playQueryThis = DicePlayRecord::whereBetween('create_time', [$thisWeekStart, $thisWeekEnd]);
        $playQueryLast = DicePlayRecord::whereBetween('create_time', [$lastWeekStart, $lastWeekEnd]);
        AdminScopeHelper::applyAdminScope($playQueryThis, $adminInfo, $filterDeptId);
        AdminScopeHelper::applyAdminScope($playQueryLast, $adminInfo, $filterDeptId);
        $playThis = $playQueryThis->count();
        $playLast = $playQueryLast->count();

        $playerChange = $this->calcWeekChange($playerThis, $playerLast);
        $chargeChange = $this->calcWeekChange((float) $chargeThis, (float) $chargeLast);
        $withdrawChange = $this->calcWeekChange((float) $withdrawThis, (float) $withdrawLast);
        $playChange = $this->calcWeekChange($playThis, $playLast);

        return $this->success([
            'player_count' => $playerThis,
            'player_count_change' => $playerChange,
            'charge_amount' => (float) $chargeThis,
            'charge_amount_change' => $chargeChange,
            'withdraw_amount' => (float) $withdrawThis,
            'withdraw_amount_change' => $withdrawChange,
            'play_count' => $playThis,
            'play_count_change' => $playChange,
        ]);
    }

    /**
     * 近期玩家充值统计（近10天每日充值金额）
     */
    #[Permission('工作台数据统计', 'core:console:list')]
    public function rechargeChart(Request $request): Response
    {
        $adminInfo = $this->adminInfo ?? null;
        $deptCondition = $this->buildWalletSqlDeptCondition($adminInfo, $request->input('dept_id'));
        if ($deptCondition === '__empty__') {
                $data = [];
                foreach (range(0, 9) as $n) {
                    $data[] = ['recharge_date' => date('Y-m-d', strtotime("-{$n} days")), 'recharge_amount' => 0];
                }
                $data = array_reverse($data);
                return $this->success([
                    'recharge_amount' => array_map('floatval', array_column($data, 'recharge_amount')),
                    'recharge_date' => array_column($data, 'recharge_date'),
                ]);
        }
        $sql = "
            SELECT
                d.date AS recharge_date,
                IFNULL(SUM(w.coin), 0) AS recharge_amount
            FROM
                (SELECT CURDATE() - INTERVAL (a.N) DAY AS date
                 FROM (SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3
                       UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6
                       UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) a
                 ) d
            LEFT JOIN dice_player_wallet_record w
                ON DATE(w.create_time) = d.date AND w.type = 0 AND w.coin > 0 {$deptCondition}
            GROUP BY d.date
            ORDER BY d.date ASC
        ";
        $data = Db::query($sql);
        return $this->success([
            'recharge_amount' => array_map('floatval', array_column($data, 'recharge_amount')),
            'recharge_date' => array_column($data, 'recharge_date'),
        ]);
    }

    /**
     * 月度玩家充值汇总（当年1-12月每月充值金额）
     */
    #[Permission('工作台数据统计', 'core:console:list')]
    public function rechargeBarChart(Request $request): Response
    {
        $adminInfo = $this->adminInfo ?? null;
        $deptCondition = $this->buildWalletSqlDeptCondition($adminInfo, $request->input('dept_id'));
        if ($deptCondition === '__empty__') {
                $data = [];
                for ($m = 1; $m <= 12; $m++) {
                    $data[] = ['recharge_month' => sprintf('%02d月', $m), 'recharge_amount' => 0];
                }
                return $this->success([
                    'recharge_amount' => array_map('floatval', array_column($data, 'recharge_amount')),
                    'recharge_month' => array_column($data, 'recharge_month'),
                ]);
        }
        $sql = "
            SELECT
                CONCAT(LPAD(m.month_num, 2, '0'), '月') AS recharge_month,
                IFNULL(SUM(w.coin), 0) AS recharge_amount
            FROM
                (SELECT 1 AS month_num UNION ALL SELECT 2 UNION ALL SELECT 3
                 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6
                 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9
                 UNION ALL SELECT 10 UNION ALL SELECT 11 UNION ALL SELECT 12) m
            LEFT JOIN dice_player_wallet_record w
                ON YEAR(w.create_time) = YEAR(CURDATE())
                AND MONTH(w.create_time) = m.month_num
                AND w.type = 0 AND w.coin > 0 {$deptCondition}
            GROUP BY m.month_num
            ORDER BY m.month_num ASC
        ";
        $data = Db::query($sql);
        return $this->success([
            'recharge_amount' => array_map('floatval', array_column($data, 'recharge_amount')),
            'recharge_month' => array_column($data, 'recharge_month'),
        ]);
    }

    /**
     * 工作台-玩家充值记录：最新50条（admin_id=当前管理员及子管理员，type=0）
     * 返回：玩家账号(DicePlayer.username)、充值金额(coin)、充值时间(create_time)
     */
    #[Permission('工作台数据统计', 'core:console:list')]
    public function walletRecordList(Request $request): Response
    {
        $adminInfo = $this->adminInfo ?? null;
        $query = DicePlayerWalletRecord::with([
            'dicePlayer' => function ($q) {
                $q->field('id,username');
            },
        ])
            ->where('type', 0)
            ->order('create_time', 'desc')
            ->limit(50);
        AdminScopeHelper::applyAdminScope($query, $adminInfo, $request->input('dept_id'));
        $list = $query->select();
        $rows = [];
        foreach ($list as $row) {
            $player = $row->dicePlayer;
            $rows[] = [
                'player_name' => $player ? $player->getAttr('username') : '',
                'coin' => $row->getAttr('coin'),
                'create_time' => $row->getAttr('create_time'),
            ];
        }
        return $this->success($rows);
    }

    /**
     * 工作台-新增玩家记录：最新50条（admin_id=当前管理员及子管理员）
     * 返回：玩家账号(username)、余额(coin)、抽奖券(total_ticket_count)
     */
    #[Permission('工作台数据统计', 'core:console:list')]
    public function newPlayerList(Request $request): Response
    {
        $adminInfo = $this->adminInfo ?? null;
        $query = DicePlayer::field('username,coin,total_ticket_count,create_time')
            ->order('create_time', 'desc')
            ->limit(50);
        AdminScopeHelper::applyAdminScope($query, $adminInfo, $request->input('dept_id'));
        $list = $query->select();
        $rows = [];
        foreach ($list as $row) {
            $rows[] = [
                'name' => $row->getAttr('username'),
                'coin' => $row->getAttr('coin'),
                'total_ticket_count' => $row->getAttr('total_ticket_count'),
                'create_time' => $row->getAttr('create_time'),
            ];
        }
        return $this->success($rows);
    }

    /**
     * 工作台-玩家游玩记录：最新50条
     * 返回：玩家账号、中奖档位、赢取平台币、游玩时间
     */
    #[Permission('工作台数据统计', 'core:console:list')]
    public function playRecordList(Request $request): Response
    {
        $adminInfo = $this->adminInfo ?? null;
        $query = DicePlayRecord::with([
            'dicePlayer' => function ($q) {
                $q->field('id,username');
            },
        ])
            ->where('status', 1)
            ->field('id,player_id,reward_tier,win_coin,create_time')
            ->order('create_time', 'desc')
            ->limit(50);
        AdminScopeHelper::applyAdminScope($query, $adminInfo, $request->input('dept_id'));
        $list = $query->select();
        $tierLabels = $this->buildRewardTierLabels();
        $rows = [];
        foreach ($list as $row) {
            $player = $row->dicePlayer;
            $tier = $row->getAttr('reward_tier');
            $rows[] = [
                'player_name' => $player ? $player->getAttr('username') : '',
                'reward_tier' => $tier,
                'reward_tier_label' => $tierLabels[$tier] ?? $tier,
                'win_coin' => $row->getAttr('win_coin'),
                'create_time' => $row->getAttr('create_time'),
            ];
        }
        return $this->success($rows);
    }

    /**
     * @return array<string, string>
     */
    private function buildRewardTierLabels(): array
    {
        $rows = DiceRewardConfig::field('tier,ui_text')->select();
        $labels = [];
        foreach ($rows as $row) {
            $tier = $row->getAttr('tier');
            if ($tier === '' || $tier === null) {
                continue;
            }
            if (!isset($labels[$tier])) {
                $labels[$tier] = $row->getAttr('ui_text') ?: $tier;
            }
        }
        return $labels;
    }

    private function calcWeekChange($current, $last): float
    {
        if ($last == 0) {
            return $current > 0 ? 100.0 : 0.0;
        }
        return round((($current - $last) / $last) * 100, 1);
    }

    /**
     * 钱包流水 SQL 渠道条件；非超管无渠道时返回 __empty__
     */
    private function buildWalletSqlDeptCondition(?array $adminInfo, $requestDeptId): string
    {
        if (AdminScopeHelper::getDeptId($adminInfo) !== null) {
            $deptId = AdminScopeHelper::getDeptId($adminInfo);
            if ($deptId <= 0) {
                return '__empty__';
            }
            return ' AND w.dept_id = ' . $deptId;
        }
        $target = AdminScopeHelper::resolveBusinessDeptId($adminInfo, $requestDeptId);
        if ($target !== null && $target > 0) {
            return ' AND w.dept_id = ' . $target;
        }
        return '';
    }
}
