<?php

namespace app\admin\controller;

use app\admin\model\MoneyLogHistory;
use app\admin\model\User;
use app\admin\model\UserMoneyLog;
use app\common\controller\Backend;
use app\admin\model\Bank;
use think\exception\ValidateException;
use think\facade\Db;
use Throwable;

class Dashboard extends Backend
{
    /**
     * @var object
     * @phpstan-var Bank
     */
    protected object $bank;
    public function initialize(): void
    {
        parent::initialize();
        $this->bank = new Bank();
    }

    public function index(): void
    {
        $rawStart = request()->param('start/s');
        $start = $rawStart ? strtotime($rawStart) : strtotime('today');
        $rawEnd = request()->param('end/s');
        $end = $rawEnd ? strtotime("$rawEnd +1 day") : strtotime('tomorrow');
        if ($start > $end) {
            list($start, $end) = [$end, $start];
        }
        $bankList = Bank::field([
            'id', 'bank_name', 'bank_account', 'current_balance', 'safe_alert', 'label_color', 'weigh',
            // 子查询：入款总额
            "(SELECT SUM(money/100) FROM ba_user_money_log WHERE bank_id = ba_bank.id AND type in (1,3) and create_time BETWEEN {$start} AND {$end}) AS total_fund_in",
            // 子查询：出款总额
            "(SELECT SUM(money/100) FROM ba_user_money_log WHERE bank_id = ba_bank.id AND type in (2,4) and create_time BETWEEN {$start} AND {$end}) AS total_fund_out",
            // 子查询：入款次数
            "(SELECT COUNT(*) FROM ba_user_money_log WHERE bank_id = ba_bank.id AND type in (1,3) and create_time BETWEEN {$start} AND {$end}) AS count_fund_in",
            // 子查询：出款次数
            "(SELECT COUNT(*) FROM ba_user_money_log WHERE bank_id = ba_bank.id AND type in (2,4) and create_time BETWEEN {$start} AND {$end}) AS count_fund_out",
        ])
            ->where('status', 1)
            ->order('weigh', 'desc')
            ->order('id', 'desc')
            ->select()
            ->toArray();

        foreach ($bankList as &$bank) {
            $bank['total_fund_in']  = (float)$bank['total_fund_in'];
            $bank['total_fund_out'] = (float)$bank['total_fund_out'];
            $bank['count_fund_in']  = (int)$bank['count_fund_in'];
            $bank['count_fund_out'] = (int)$bank['count_fund_out'];
        }
        unset($bank);
        $customer = Db::name('user_money_log')->field([
            // 1. 总进款 (type = 1)
            'ROUND(SUM(CASE WHEN type = 1 THEN money/100 ELSE 0 END), 2) AS total_deposit',
            // 2. 总出款 (type = 2)
            'ROUND(SUM(CASE WHEN type = 2 THEN money/100 ELSE 0 END), 2) AS total_withdraw',
            // 3. 总进款次数 (type = 1 的记录总数)
            'COUNT(CASE WHEN type = 1 THEN 1 END) AS count_deposit',
            // 4. 总出款次数 (type = 2 的记录总数)
            'COUNT(CASE WHEN type = 2 THEN 1 END) AS count_withdraw',
            // 5. 活跃玩家数 (去重计算有多少个不同的 user_id 产生了流水)
            'COUNT(DISTINCT user_id) AS active_player',
            //6. 首次充值
            'COUNT(CASE WHEN label = 1 THEN 1 END) AS first_deposit',
            'ROUND(SUM(CASE WHEN label = 2 THEN money/100 ELSE 0 END), 2) AS unclaim_amount',
            'COUNT(CASE WHEN label = 2 THEN 1 END) AS unclaim_receipt',
        ])
            ->whereBetweenTime('create_time', $start, $end)
            ->whereNull('created_by')
            ->find();
        $customerData = [
            'total_deposit'      => (float)($customer['total_deposit'] ?? 0),
            'total_withdraw'     => (float)($customer['total_withdraw'] ?? 0),
            'count_deposit'      => (int)($customer['count_deposit'] ?? 0),
            'count_withdraw'     => (int)($customer['count_withdraw'] ?? 0),
            'active_player' => (int)($customer['active_player'] ?? 0),
            'first_deposit' => (int)($customer['first_deposit'] ?? 0),
            'unclaim_amount' => (float)($customer['unclaim_amount'] ?? 0),
            'unclaim_receipt' => (int)($customer['unclaim_receipt'] ?? 0),
        ];
        $limit = request()->param('limit/d') ?? 15;
        $bindFields = [
            'user' => ['jk_username'],
            'bank' => ['bank_name'],
            'admin' => ['id', 'username'],
        ];
        $transaction = UserMoneyLog::withJoin($bindFields, 'left')
            ->with([
                'scoreLog' => function($query) {
                    $query->field(['money_log_id', 'game_type', 'score']);
                }
            ])
            ->whereBetweenTime('user_money_log.create_time', $start, $end)
            ->order('id', 'desc')
            ->paginate($limit);
        $transactionList = $transaction->items();
        foreach ($transactionList as &$item) {
            $item['user_name'] = $item['user']['jk_username'] ?? '';
            $item['bank_name'] = $item['bank']['bank_name'] ?? '';
            $item['created_by'] = $item['admin']['username'] ?? 'WEBHOOK';
            unset($item['user'], $item['bank'], $item['admin']);
        }
        unset($item);
        $transactionTotal = Db::name('user_money_log')->field([
            // 1. 总进款 (type = 1)
            'ROUND(SUM(CASE WHEN type = 1 THEN money/100 ELSE 0 END), 2) AS total_fund_in',
            // 2. 总出款 (type = 2)
            'ROUND(SUM(CASE WHEN type = 2 THEN money/100 ELSE 0 END), 2) AS total_fund_out',
        ])
            ->whereBetweenTime('create_time', $start, $end)
            ->find();
        $this->success('', [
            'bank' => $bankList,
            'customer' => $customerData,
            'transaction'=> [
                'list' => $transactionList,
                'count' => $transaction->total(),
                'current_page'  => $transaction->currentPage(),
                'last_page'  => $transaction->lastPage(),
                'total_deposit'  => (float)($transactionTotal['total_fund_in'] ?? 0),
                'total_withdraw' => (float)($transactionTotal['total_fund_out'] ?? 0),
            ],
        ]);
    }

    public function bankTransact(): void
    {
        $data = $this->request->post();
        if (!$data) {
            $this->error(__('Parameter %s can not be empty', ['']));
        }

        $money = isset($data['money']) ? (int)$data['money'] : 0;
        $bankFromId = isset($data['bank_from']) ? (int)$data['bank_from'] : 0;
        $bankToId = isset($data['bank_to']) ? (int)$data['bank_to'] : 0;
        if ($money <= 0) {
            $this->error(__('转账金额必须大于 0'));
        }
        if ($bankFromId === $bankToId) {
            $this->error(__('转出银行和转入银行不能相同'));
        }
        $adminId = $this->auth->getInfo()['id'] ?? null;
        \think\facade\Db::startTrans();
        try {
            $bankFrom = Bank::where('id', $bankFromId)->where('status', 1)->lock(true)->find();
            if (!$bankFrom) {
                throw new ValidateException('转出银行账户不存在或已被禁用');
            }
            if ($bankFrom->current_balance < $money) {
                throw new ValidateException("转出银行【{$bankFrom->bank_name}】余额不足");
            }

            $bankTo = Bank::where('id', $bankToId)->where('status', 1)->lock(true)->find();
            if (!$bankTo) {
                throw new ValidateException('转入银行账户不存在或已被禁用');
            }

            // 5. 更新转出银行账户余额
            $bankFrom->current_balance -= $money;
            $bankFrom->save();

            $logFrom = new UserMoneyLog();
            $logFrom->save([
                'user_id'        => 0,
                'money'          => $money,
                'before'         => $bankFrom->current_balance + $money,
                'after'          => $bankFrom->current_balance,
                'type'           => 4,
                'bank_id'        => $bankFromId,
                'created_by'     => $adminId,
                'memo'           => $data['remark'],
                'category'       => 2,
                'create_time'    => time()
            ]);

            $bankTo->current_balance += $money;
            $bankTo->save();

            $logTo = new UserMoneyLog();
            $logTo->save([
                'user_id'        => 0,
                'money'          => $money,
                'before'         => $bankTo->current_balance - $money,
                'after'          => $bankTo->current_balance,
                'type'           => 3,
                'bank_id'        => $bankToId,
                'created_by'     => $adminId,
                'memo'           => $data['remark'],
                'category'       => 2,
                'create_time'    => time()
            ]);

            \think\facade\Db::commit();
            $isCommitSuccess = true;
        } catch (ValidateException $e) {
            \think\facade\Db::rollback();
            $this->error($e->getMessage());
        } catch (Throwable $e) {
            \think\facade\Db::rollback();
            trace($e->getMessage(), 'error');
            $this->error(__('No rows were added'));
        }
        if ($isCommitSuccess) {
            $this->success(__('Added successfully'));
        }
    }

    public function newTransact(): void
    {
        if ($this->request->isPost()) {
            $data = $this->request->post();
            if (!$data) {
                $this->error(__('Parameter %s can not be empty', ['']));
            }
            $result = false;
            $data   = $this->excludeFields($data);

            $bank = Bank::where('id', $data['bank_id'])->where('status', 1)->lock(true)->find();
            if (!$bank) {
                throw new ValidateException('银行账户不存在或已被禁用');
            }

            if (in_array($data['type'], [2,4])) {
                $bank->current_balance -= $data['money'];
            } else {
                $bank->current_balance += $data['money'];
            }
            $bank->save();

            $user_id = User::where('jk_username', $data['user_name'])->value('id');
            if (!$user_id) {
                $this->error(__("The user can't find it", ['']));
            }
            $data['user_id'] = $user_id;
            $userMoneyLog = new UserMoneyLog();
            $userMoneyLog->startTrans();
            try {
                $data['created_by'] = $this->auth->getInfo()['id'];
                $result = $userMoneyLog->save($data);
                $userMoneyLog->commit();
            } catch (Throwable $e) {
                $userMoneyLog->rollback();
                $this->error($e->getMessage());
            }
            if ($result !== false) {
                $this->success(__('Added successfully'));
            } else {
                $this->error(__('No rows were added'));
            }
        }
    }


    public function logHistory($id): void
    {
        $bindFields = [
            'admin' => ['id','username'],
        ];
        $history = MoneyLogHistory::withJoin($bindFields, 'left')
            ->where('money_log_id', $id)
            ->select();
        if (!empty($history)) {
            foreach ($history as &$item) {
                $item['admin_name'] = $item['admin']['username'] ?? '';
                unset($item['admin']);
            }
            unset($item);
        }
        $this->success('', $history);
    }

    public function editTransact(): void
    {
        $userMoneyLog = new UserMoneyLog();
        $pk  = $userMoneyLog->getPk();
        $id  = $this->request->param($pk);
        $row = $userMoneyLog->find($id);
        if (!$row) {
            $this->error(__('Record not found'));
        }

        if ($this->request->isPost()) {
            $data = $this->request->post();
            if (!$data) {
                $this->error(__('Parameter %s can not be empty', ['']));
            }

            $result = false;
            $userMoneyLog->startTrans();
            try {
                $result = $row->save($data);
                $userMoneyLog->commit();
            } catch (Throwable $e) {
                $userMoneyLog->rollback();
                $this->error($e->getMessage());
            }
            if ($result !== false) {
                $this->success(__('Update successful'));
            } else {
                $this->error(__('No rows updated'));
            }
            return;
        }
        $this->success('', [
            'row' => $row
        ]);
    }

    public function delTransact($id): void
    {
        $result = false;
        try {
            $result = Db::table('ba_user_money_log')->delete($id);
        } catch (Throwable $e) {
            $this->error(__('%d records and files have been deleted', [1]) . $e->getMessage());
        }
        if ($result) {
            $this->success(__('%d records and files have been deleted', [1]));
        } else {
            $this->error(__('No rows were deleted'));
        }
    }
}