<?php

namespace app\admin\controller\order;

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

/**
 * 管理员提现记录（审核）
 */
class AdminWithdrawOrder extends Backend
{
    protected array $noNeedPermission = ['stats', 'approve', 'reject'];

    protected ?object $model = null;

    protected bool $modelValidate = false;

    protected string|array $quickSearchField = ['id', 'order_no', 'receive_account', 'remark'];

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

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

    protected array $withJoinTable = ['admin', 'channel', 'reviewAdmin'];

    protected function initController(WebmanRequest $request): ?Response
    {
        $this->model = new \app\common\model\AdminWithdrawOrder();
        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();
        $table = strtolower($this->model->getTable());
        $mainShort = $alias[$table] ?? '';
        if ($mainShort !== '' && $this->auth && !$this->auth->isSuperAdmin()) {
            $where[] = [$mainShort . '.channel_id', 'in', $this->getCurrentAdminChannelIds()];
        }
        $res = $this->model
            ->withJoin($this->withJoinTable, $this->withJoinType)
            ->with($this->withJoinTable)
            ->visible([
                'admin' => ['username'],
                'channel' => ['name'],
                'reviewAdmin' => ['username'],
            ])
            ->alias($alias)
            ->where($where)
            ->order($order)
            ->paginate($limit);

        $list = $res->items();
        foreach ($list as $idx => $item) {
            $list[$idx]['can_review'] = $this->canReviewOrder(is_array($item) ? $item : []) ? 1 : 0;
        }

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

    protected function _edit(): Response
    {
        $pk = $this->model->getPk();
        $id = $this->request ? ($this->request->post($pk) ?? $this->request->get($pk)) : null;
        if ($id === null || $id === '') {
            return $this->error(__('Parameter error'));
        }
        if ($this->request && $this->request->method() === 'POST') {
            return $this->error(__('Please use approve/reject buttons to review'));
        }
        $row = $this->loadWithRelations(intval(strval($id)));
        if (!$row) {
            return $this->error(__('Record not found'));
        }
        if (!$this->canReviewOrder($row)) {
            return $this->error(__('You have no permission'));
        }
        return $this->success('', ['row' => $row]);
    }

    public function approve(WebmanRequest $request): Response
    {
        $response = $this->initializeBackend($request);
        if ($response !== null) {
            return $response;
        }
        if ($request->method() !== 'POST') {
            return $this->error(__('Parameter error'));
        }
        $id = intval(strval($request->post('id', 0)));
        if ($id <= 0) {
            return $this->error(__('Parameter error'));
        }
        $order = Db::name('admin_withdraw_order')->where('id', $id)->find();
        if (!is_array($order)) {
            return $this->error(__('Record not found'));
        }
        if (!$this->canReviewOrder($order)) {
            return $this->error(__('You have no permission'));
        }
        if (intval($order['status'] ?? 0) !== 0) {
            return $this->error(__('This withdraw order has already been reviewed'));
        }
        $remark = trim((string) $request->post('remark', ''));
        Db::startTrans();
        try {
            AdminWalletService::approveWithdraw($order, intval($this->auth->id), $remark);
            Db::commit();
        } catch (Throwable $e) {
            Db::rollback();
            return $this->error($e->getMessage());
        }
        return $this->success(__('Approved'));
    }

    public function reject(WebmanRequest $request): Response
    {
        $response = $this->initializeBackend($request);
        if ($response !== null) {
            return $response;
        }
        if ($request->method() !== 'POST') {
            return $this->error(__('Parameter error'));
        }
        $id = intval(strval($request->post('id', 0)));
        if ($id <= 0) {
            return $this->error(__('Parameter error'));
        }
        $remark = trim((string) $request->post('remark', ''));
        if ($remark === '') {
            return $this->error(__('Please provide reject reason'));
        }
        $order = Db::name('admin_withdraw_order')->where('id', $id)->find();
        if (!is_array($order)) {
            return $this->error(__('Record not found'));
        }
        if (!$this->canReviewOrder($order)) {
            return $this->error(__('You have no permission'));
        }
        if (intval($order['status'] ?? 0) !== 0) {
            return $this->error(__('This withdraw order has already been reviewed'));
        }
        Db::startTrans();
        try {
            AdminWalletService::rejectWithdraw($order, intval($this->auth->id), $remark);
            Db::commit();
        } catch (Throwable $e) {
            Db::rollback();
            return $this->error($e->getMessage());
        }
        return $this->success(__('Rejected'));
    }

    public function stats(WebmanRequest $request): Response
    {
        $response = $this->initializeBackend($request);
        if ($response !== null) {
            return $response;
        }
        $query = Db::name('admin_withdraw_order');
        if ($this->auth && !$this->auth->isSuperAdmin()) {
            $query->where('channel_id', 'in', $this->getCurrentAdminChannelIds());
        }
        $rows = $query->field(['status', 'amount', 'actual_amount'])->select()->toArray();
        $total = count($rows);
        $pending = 0;
        $approved = 0;
        $rejected = 0;
        $totalAmount = '0.00';
        $pendingAmount = '0.00';
        $approvedAmount = '0.00';
        foreach ($rows as $row) {
            $status = intval($row['status'] ?? 0);
            $amount = bcadd(strval($row['amount'] ?? '0'), '0', 2);
            $actual = bcadd(strval($row['actual_amount'] ?? '0'), '0', 2);
            $totalAmount = bcadd($totalAmount, $amount, 2);
            if ($status === 0) {
                $pending++;
                $pendingAmount = bcadd($pendingAmount, $amount, 2);
            } elseif ($status === 1) {
                $approved++;
                $approvedAmount = bcadd($approvedAmount, $actual, 2);
            } elseif ($status === 2) {
                $rejected++;
            }
        }
        return $this->success('', [
            'total_count' => $total,
            'pending_count' => $pending,
            'approved_count' => $approved,
            'rejected_count' => $rejected,
            'total_amount' => $totalAmount,
            'pending_amount' => $pendingAmount,
            'approved_amount' => $approvedAmount,
        ]);
    }

    private function loadWithRelations(int $id): ?array
    {
        $row = $this->model
            ->withJoin($this->withJoinTable, $this->withJoinType)
            ->with($this->withJoinTable)
            ->visible([
                'admin' => ['username'],
                'channel' => ['name'],
                'reviewAdmin' => ['username'],
            ])
            ->where($this->model->getTable() . '.id', $id)
            ->find();
        return $row ? $row->toArray() : null;
    }

    private function canReviewOrder(array $order): bool
    {
        if (!$this->auth) {
            return false;
        }
        if ($this->auth->isSuperAdmin()) {
            return true;
        }
        $channelId = intval($order['channel_id'] ?? 0);
        if ($channelId <= 0) {
            return false;
        }
        $allowed = $this->getCurrentAdminChannelIds();
        return in_array($channelId, $allowed, true);
    }

    /**
     * 当前管理员可审核的渠道（优先取自身 channel_id，同时兼容角色组继承链上的 channel_id）
     *
     * @return int[]
     */
    private function getCurrentAdminChannelIds(): array
    {
        $uid = intval($this->auth->id ?? 0);
        if ($uid <= 0) {
            return [0];
        }
        $channelIds = [];

        $selfChannelId = intval(Db::name('admin')->where('id', $uid)->value('channel_id') ?? 0);
        if ($selfChannelId > 0) {
            $channelIds[] = $selfChannelId;
        }

        $groupIds = Db::name('admin_group_access')->where('uid', $uid)->column('group_id');
        if ($groupIds !== []) {
            $groupIds = array_values(array_unique(array_merge($groupIds, $this->auth->getAdminChildGroups())));
            $rows = Db::name('admin_group')
                ->field(['id', 'channel_id'])
                ->where('id', 'in', $groupIds)
                ->whereNotNull('channel_id')
                ->select()
                ->toArray();
            foreach ($rows as $row) {
                $cid = intval($row['channel_id'] ?? 0);
                if ($cid > 0) {
                    $channelIds[] = $cid;
                }
            }
        }

        return $channelIds === [] ? [0] : array_values(array_unique($channelIds));
    }
}

