<?php

declare(strict_types=1);

namespace app\admin\controller\routine;

use app\admin\model\Admin;
use app\common\service\AdminWalletService;
use app\common\controller\Backend;
use support\think\Db;
use Webman\Http\Request;
use support\Response;
use Throwable;

class AdminInfo extends Backend
{
    protected array $noNeedPermission = ['walletSummary', 'walletRecords', 'withdrawApply'];

    protected ?object $model = null;

    protected array|string $preExcludeFields = ['username', 'last_login_time', 'password', 'salt', 'status'];
    protected array $authAllowFields = ['id', 'username', 'nickname', 'avatar', 'email', 'mobile', 'motto', 'last_login_time'];

    protected function initController(Request $request): ?Response
    {
        $this->auth->setAllowFields($this->authAllowFields);
        $this->model = $this->auth->getAdmin();
        return null;
    }

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

        $info = $this->auth->getInfo();
        return $this->success('', ['info' => $info]);
    }

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

        $pk = $this->model->getPk();
        $id = $request->post($pk) ?? $request->get($pk);
        $row = $this->model->find($id);
        if (!$row) {
            return $this->error(__('Record not found'));
        }

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

            if (!empty($data['avatar'])) {
                $row->avatar = $data['avatar'];
                if ($row->save()) {
                    return $this->success(__('Avatar modified successfully!'));
                }
            }

            if ($this->modelValidate) {
                $validateClass = str_replace("\\model\\", "\\validate\\", get_class($this->model));
                if (class_exists($validateClass)) {
                    try {
                        $validate = new $validateClass();
                        $validate->scene('info')->check($data);
                    } catch (\Throwable $e) {
                        return $this->error($e->getMessage());
                    }
                }
            }

            if (!empty($data['password'])) {
                $this->model->resetPassword($this->auth->id, $data['password']);
            }

            $data = $this->excludeFields($data);
            $result = false;
            $this->model->startTrans();
            try {
                $result = $row->save($data);
                $this->model->commit();
            } catch (\Throwable $e) {
                $this->model->rollback();
                return $this->error($e->getMessage());
            }
            return $result !== false ? $this->success(__('Update successful')) : $this->error(__('No rows updated'));
        }

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

    public function walletSummary(Request $request): Response
    {
        $response = $this->initializeBackend($request);
        if ($response !== null) {
            return $response;
        }
        $adminId = intval($this->auth->id ?? 0);
        if ($adminId <= 0) {
            return $this->error(__('Parameter error'));
        }
        $wallet = AdminWalletService::ensureWallet($adminId);
        return $this->success('', [
            'wallet' => [
                'balance' => strval($wallet['balance'] ?? '0.00'),
                'frozen_balance' => strval($wallet['frozen_balance'] ?? '0.00'),
                'total_income' => strval($wallet['total_income'] ?? '0.00'),
                'total_withdraw' => strval($wallet['total_withdraw'] ?? '0.00'),
            ],
        ]);
    }

    public function walletRecords(Request $request): Response
    {
        $response = $this->initializeBackend($request);
        if ($response !== null) {
            return $response;
        }
        $adminId = intval($this->auth->id ?? 0);
        if ($adminId <= 0) {
            return $this->error(__('Parameter error'));
        }
        $limit = intval((string) $request->get('limit', 10));
        if ($limit <= 0) {
            $limit = 10;
        }
        $res = Db::name('admin_wallet_record')->alias('awr')
            ->leftJoin('channel c', 'awr.channel_id = c.id')
            ->leftJoin('admin oa', 'awr.operator_admin_id = oa.id')
            ->field([
                'awr.id', 'awr.biz_type', 'awr.direction', 'awr.amount', 'awr.balance_before', 'awr.balance_after',
                'awr.ref_type', 'awr.ref_id', 'awr.remark', 'awr.create_time', 'c.name as channel_name', 'oa.username as operator_admin_username',
            ])
            ->where('awr.admin_id', $adminId)
            ->order('awr.id', 'desc')
            ->paginate($limit);
        return $this->success('', [
            'list' => $res->items(),
            'total' => $res->total(),
        ]);
    }

    public function withdrawApply(Request $request): Response
    {
        $response = $this->initializeBackend($request);
        if ($response !== null) {
            return $response;
        }
        if ($request->method() !== 'POST') {
            return $this->error(__('Parameter error'));
        }
        $adminId = intval($this->auth->id ?? 0);
        if ($adminId <= 0) {
            return $this->error(__('Parameter error'));
        }
        $withdrawCoinRaw = $request->post('withdraw_coin', '');
        $withdrawCoin = is_string($withdrawCoinRaw) ? trim($withdrawCoinRaw) : (is_numeric($withdrawCoinRaw) ? strval($withdrawCoinRaw) : '');
        $receiveAccount = trim(is_string($request->post('receive_account', '')) ? $request->post('receive_account', '') : '');
        $receiveType = trim(is_string($request->post('receive_type', '')) ? $request->post('receive_type', '') : '');
        $idempotencyKey = trim(is_string($request->post('idempotency_key', '')) ? $request->post('idempotency_key', '') : '');
        if ($withdrawCoin === '' || $receiveAccount === '' || $receiveType === '' || $idempotencyKey === '') {
            return $this->error(__('Missing required parameters'));
        }
        if (mb_strlen($idempotencyKey) > 64) {
            return $this->error(__('Idempotency key is too long'));
        }
        if (!is_numeric($withdrawCoin) || bccomp($withdrawCoin, '0', 2) <= 0) {
            return $this->error(__('Withdraw amount must be greater than 0'));
        }
        $withdrawCoin = bcadd($withdrawCoin, '0', 2);
        $allowedReceiveTypes = ['bank', 'ewallet', 'crypto'];
        if (!in_array($receiveType, $allowedReceiveTypes, true)) {
            return $this->error(__('Invalid receive type; only bank/ewallet/crypto are supported'));
        }
        $remark = trim((string) $request->post('remark', ''));
        $admin = Db::name('admin')->field(['id', 'channel_id'])->where('id', $adminId)->find();
        $channelId = is_array($admin) ? intval($admin['channel_id'] ?? 0) : 0;
        Db::startTrans();
        try {
            $res = AdminWalletService::applyWithdraw($adminId, $channelId, $withdrawCoin, $receiveType, $receiveAccount, $idempotencyKey, $remark);
            if (($res['ok'] ?? false) !== true) {
                Db::rollback();
                return $this->error(strval($res['msg'] ?? __('Withdraw apply failed')));
            }
            Db::commit();
        } catch (Throwable $e) {
            Db::rollback();
            return $this->error($e->getMessage());
        }
        return $this->success(__('Withdraw request submitted; pending channel super admin review'), [
            'order_id' => intval($res['order_id'] ?? 0),
            'order_no' => strval($res['order_no'] ?? ''),
            'idempotent_hit' => !empty($res['idempotent_hit']),
        ]);
    }
}
