<?php

namespace App\Http\logic\api;

use App\dao\Estatisticas\RechargeWithDraw;
use App\dao\Pay\AccountPayInfo;
use App\Http\helper\NumConfig;
use App\Inter\CashierInterFace;
use App\Models\PrivateMail;
use App\Models\RecordUserDataStatistics;
use App\Services\AiPay;
use App\Services\StoredProcedure;
use App\Util;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Redis;

class AiPayCashierLogic implements CashierInterFace
{
    const AGENT = 101;
    protected $agent = 101;

    public function payment($RecordID, $amount, $accountName, $phone, $email, $OrderId, $PixNum, $PixType, $IFSCNumber, $BranchBank, $BankNO)
    {
        $query = DB::connection('write')->table('QPAccountsDB.dbo.OrderWithDraw')->where('RecordID', $RecordID)->first();
        if (!$query) {
            return 'fail';
        }

        $service = new AiPay('AiPayOut');
        $config = $service->getConfig();

        if(!$accountName){
            $dao = new AccountPayInfo();
            $$accountName = $dao->randUserName($accountName);
        }

        $paymentMethod = $this->resolvePaymentMethod($PixType);
        $accountData = $this->buildAccountData($paymentMethod, $accountName, $PixNum, $email, $phone, $IFSCNumber, $BranchBank, $BankNO);

        if ($paymentMethod === null || empty($accountData)) {
            Util::WriteLog('AiPay', 'unsupported PixType for withdraw: ' . $PixType.'_'.$accountName);
            return 'fail';
        }

        $amountDecimal = number_format($amount / NumConfig::NUM_VALUE, 2, '.', '');

        $params = [
            'mchNo' => $config['mchNo'] ?? '',
            'mchOrderNo' => $OrderId,
            'paymentMethod' => $paymentMethod,
            'amount' => $amountDecimal,
            'notifyUrl' => $config['cashNotify'] ?? '',
            'timestamp' => (string)round(microtime(true) * 1000),
            'accountData' => $accountData,
        ];

        $signedParams = $service->sign($params);
        $result = $service->post('/api/transfer', $signedParams);

        Log::info('AiPay withdraw request', $signedParams);
        Log::info('AiPay withdraw response', [$result]);

        try {
            $data = \GuzzleHttp\json_decode($result, true);
        } catch (\Throwable $e) {
            Util::WriteLog('AiPay_error', $e->getMessage());
            return 'fail';
        }

        if (isset($data['code']) && (int)$data['code'] === 0) {
            return $data;
        }else{
            if ($query->State == 5) {
                // 同步失败，发送邮件给玩家，退还金币
                $msg = 'Withdraw Fail';
                $WithDraw = $query->WithDraw + $query->ServiceFee;
                $bonus = '30000,' . $WithDraw;

                PrivateMail::failMail($query->UserID, $OrderId, $WithDraw, $msg, $bonus);

                $withdraw_data = ['State' => 6, 'agent' => 1043, 'finishDate' => now(),'remark' => json_encode($data)];
                DB::connection('write')->table('QPAccountsDB.dbo.OrderWithDraw')->where('OrderId', $query->OrderId)->update($withdraw_data);

                $RecordData = ['after_state' => 6, 'update_at' => now()];
                DB::connection('write')->table('QPAccountsDB.dbo.AccountsRecord')->where('type', 1)->where('RecordID', $RecordID)->update($RecordData);
            }
            return 'fail';
        }

    }

    public function notify($post)
    {
        if (!is_array($post)) {
            $post = \GuzzleHttp\json_decode($post, true);
        }

        Util::WriteLog('AiPay', 'cash callback: ' . json_encode($post, JSON_UNESCAPED_UNICODE));

        $OrderId = $post['mchOrderNo'] ?? '';
        $query = DB::connection('write')->table('QPAccountsDB.dbo.OrderWithDraw')->where('OrderId', $OrderId)->first();
        if (!$query) {
            Util::WriteLog('AiPay', 'withdraw order not found: ' . $OrderId);
            return '{"success":true,"message":"order not found"}';
        }

        if (!in_array($query->State, [5, 7])) {
            Util::WriteLog('AiPay', $OrderId . ' already handled');
            return 'success';
        }

        $agentID = DB::connection('write')->table('agent.dbo.admin_configs')
            ->where('config_value', self::AGENT)
            ->where('type', 'cash')
            ->value('id') ?? '';

        $status = (int)($post['status'] ?? 0);
        $now = now();
        $withdraw_data = [];
        $notifyState = 0;
        $msg = $post['msg'] ?? '';

        $TakeMoney = $query->WithDraw + $query->ServiceFee;
        $UserID = $query->UserID;

        switch ($status) {
            case 3: // success
                $withdraw_data = [
                    'State' => 2,
                    'agent' => $agentID,
                    'finishDate' => $now,
                ];
                $this->handleSuccess($UserID, $TakeMoney, $OrderId, $query->ServiceFee);
                $notifyState = 1;
                break;

            case 4: // fail
            case 5: // reversal
                $msg = $msg ?: 'Withdraw rejected';
                $bonus = '30000,' . $TakeMoney;
                PrivateMail::failMail($UserID, $OrderId, $TakeMoney, $msg, $bonus);
                Util::WriteLog('AiPayEmail', [$UserID, $OrderId, $TakeMoney, $msg, $bonus]);
                $withdraw_data = ['State' => 6, 'agent' => $agentID, 'remark' => $msg];
                $notifyState = 2;
                break;

            default:
                Util::WriteLog('AiPay', 'cash notify pending: ' . $OrderId);
                return 'success';
        }

        $recordData = [
            'before_state' => $query->State,
            'after_state' => $withdraw_data['State'] ?? $query->State,
            'RecordID' => $query->RecordID,
            'update_at' => date('Y-m-d H:i:s'),
        ];

        DB::connection('write')->table('QPAccountsDB.dbo.AccountsRecord')
            ->updateOrInsert(['RecordID' => $query->RecordID, 'type' => 1], $recordData);
        DB::connection('write')->table('QPAccountsDB.dbo.OrderWithDraw')
            ->where('OrderId', $OrderId)
            ->update($withdraw_data);

        return 'success';
    }

    protected function resolvePaymentMethod($PixType): ?string
    {
        $map = [
            1 => '1201', // CashApp
            2 => '1202', // PayPal
            3 => '1203', // Venmo
            4 => '1204', // CARD
        ];

        return $map[$PixType] ?? null;
    }

    protected function buildAccountData(?string $paymentMethod, $accountName, $PixNum, $email, $phone, $IFSCNumber, $BranchBank, $BankNO): array
    {
        $splitName = $this->splitName($accountName);

        switch ($paymentMethod) {
            case '1201':
                $account = $PixNum ?: $phone;
                if ($account && strpos($account, '$') !== 0) {
                    $account = '$' . $account;
                }
                return ['account' => $account];

            case '1202':
            case '1203':
                return [
                    'account' => $email ?: $PixNum,
                    'firstName' => $splitName['first'],
                    'lastName' => $splitName['last'],
                ];

            case '1204':
                return [
                    'cardNo' => $PixNum ?: $BankNO,
                    'cardExpireMonth' => $this->extractMonth($BranchBank),
                    'cardExpireYear' => $this->extractYear($BranchBank),
                    'cardSecurityCode' => substr($IFSCNumber ?? '', 0, 4),
                    'cardBrand' => 'visa',
                    'firstName' => $splitName['first'],
                    'lastName' => $splitName['last'],
                ];
        }

        return [];
    }

//    protected function splitName($name): array
//    {
//        $name = trim($name ?: 'User');
//        $parts = preg_split('/\s+/', $name, 2);
//        return [
//            'first' => $parts[0] ?? 'User',
//            'last' => $parts[1] ??  'Edward',
//        ];
//    }

    protected function splitName(string $name = null): array
    {
        $name = trim($name ?? '');
        if ($name === '') $name = 'Willam Edson';

//        // 处理 "Last, First"
//        if (str_contains($name, ',')) {
//            $tmp = array_map('trim', explode(',', $name, 2));
//            $name = ($tmp[1] ?? '') . ' ' . ($tmp[0] ?? '');
//            $name = trim($name);
//        }

        // 清洗：保留字母、空格、-、'
        $name = preg_replace("/[^A-Za-z\\s\\-']/u", ' ', $name);
        $name = trim(preg_replace('/\s+/', ' ', $name));

        $parts = explode(' ', $name, 2);

        return [
            'first' => $parts[0] ?: 'Willam',
            'last'  => $parts[1] ?? 'Edward', // 或 'Edward' / 'User'
        ];
    }


    protected function extractMonth($value): string
    {
        if (preg_match('/(\d{2})/', (string)$value, $match)) {
            return $match[1];
        }
        return '01';
    }

    protected function extractYear($value): string
    {
        if (preg_match('/(\d{2,4})/', (string)$value, $match)) {
            return substr($match[1], -2);
        }
        return '25';
    }

    protected function handleSuccess($UserID, $TakeMoney, $OrderId, $serviceFee): void
    {
        $first = DB::connection('write')->table('QPAccountsDB.dbo.UserTabData')->where('UserID', $UserID)->first();
        if ($first) {
            DB::connection('write')->table('QPAccountsDB.dbo.UserTabData')->where('UserID', $UserID)->increment('TakeMoney', $TakeMoney);
        } else {
            DB::connection('write')->table('QPAccountsDB.dbo.UserTabData')->insert(['TakeMoney' => $TakeMoney, 'UserID' => $UserID]);
            try {
                PrivateMail::praiseSendMail($UserID);
            } catch (\Throwable $e) {
                // ignore mail failure
            }
        }

        try {
            StoredProcedure::addPlatformData($UserID, 4, $TakeMoney);
        } catch (\Throwable $exception) {
            Util::WriteLog('StoredProcedure', $exception->getMessage());
        }

        $withdrawal_position_log = DB::connection('write')->table('agent.dbo.withdrawal_position_log')->where('order_sn', $OrderId)->first();
        if ($withdrawal_position_log) {
            DB::connection('write')->table('agent.dbo.withdrawal_position_log')
                ->where('order_sn', $OrderId)
                ->update(['take_effect' => 2, 'update_at' => date('Y-m-d H:i:s')]);
        }

        RecordUserDataStatistics::updateOrAdd($UserID, $TakeMoney, 0, $serviceFee);
        $fee = DB::table('QPAccountsDB.dbo.OrderWithDraw')->where('OrderId', $OrderId)
            ->value('withdraw_fee');
        (new RechargeWithDraw())->withDraw($UserID, $TakeMoney, $fee, $serviceFee);
        $redis = Redis::connection();
        $redis->incr('draw_' . date('Ymd') . $UserID);
        PrivateMail::successMail($UserID, $OrderId, $TakeMoney);

        StoredProcedure::user_label($UserID, 2, $TakeMoney);
    }
}

