<?php

namespace App\Services\Bank;

use App\Cache\FinanceCache;
use App\Consts\ErrorConst;
use App\Consts\FinanceConsts;
use App\Dao\Bank\BankDao;
use App\Dao\Bank\WithdrawDao;
use App\Exceptions\ApiException;
use App\Facade\Site;
use App\Libs\Utils;
use App\Services\Sms\SmsService;

class BankService
{
    private $bankDao;
    private $withdrawDao;
    private $smsService;

    public function __construct(
        BankDao     $bankDao,
        WithdrawDao $withdrawDao,
        SmsService  $smsService
    )
    {
        $this->bankDao     = $bankDao;
        $this->withdrawDao = $withdrawDao;
        $this->smsService  = $smsService;
    }

    /**
     * 下拉银行列表
     *
     * @return mixed
     */
    public function bankList()
    {
        return $this->bankDao->bankList();
    }

    /**
     * 站点银行卡列表
     *
     * @return array
     */
    public function channelBankAccounts($params): array
    {
        // 账号id
        $channelUserId = Site::getUid();

        // 对公对私
        $isCompany = (int)getProp($params, 'is_company', -1);

        // 获取账号下全部有效银行卡
        $accounts = $this->bankDao->getValidCashAccountsByChannelUserId($channelUserId, $isCompany);
        if (empty($accounts)) {
            return [];
        }

        // 获取银行卡提现记录
        $cardNumbers = array_column($accounts, 'card_number');
        [$startTime, $endTime] = [date('Y-m-d'), date('Y-m-d') . ' 23:59:59'];
        $withDrawOrders = $this->withdrawDao->getWithDrawLogsByBankAccountIds($cardNumbers, $startTime, $endTime);

        // 计算各个银行卡可提余额
        foreach ($accounts as &$account) {
            // 卡号
            $cardNumber = getProp($account, 'card_number');
            $isCompany  = getProp($account, 'is_company');

            // 当前卡今日提现总额
            $amount = collect($withDrawOrders)->where('bank_account', $cardNumber)->sum('amount');

            // 计算剩余额度
            $account['remain_enable_amount'] = -1;
            if (!$isCompany) {
                $account['remain_enable_amount'] = FinanceConsts::WITH_DRAW_PRIVATE_MAX - $amount;
                if ($account['remain_enable_amount'] <= 0) {
                    $account['remain_enable_amount'] = 0;
                }
            }
        }

        return $accounts;
    }

    /**
     * 添加银行卡账号
     *
     * @param $params
     * @return bool|int
     * @throws ApiException
     */
    public function addBankAccount($params)
    {
        // 基本参数
        $accountName   = getProp($params, 'account_name');
        $identityCard  = getProp($params, 'identity_card');
        $cardNumber    = trim(getProp($params, 'card_number'));
        $accountBank   = getProp($params, 'account_bank');
        $bankId        = getProp($params, 'bank_id', 0);
        $isCompany     = (int)getProp($params, 'is_company', 0);
        $province      = getProp($params, 'province');
        $code          = getProp($params, 'sms_code');
        $channelId     = Site::getCurrentChannelId();
        $channelUserId = Site::getUid();
        $phone         = Site::getPhone();

        // 参数简易判断
        if (empty($accountName) || empty($cardNumber) || empty($bankId) || !is_numeric($bankId) || empty($channelUserId)
            || !in_array($isCompany, [FinanceConsts::COMPANY_NO, FinanceConsts::COMPANY_YES], true)) {
            Utils::throwError(ErrorConst::PARAM_ERROR_CODE);
        }

        // 判断手机号是否合理设置
        if (empty($phone) || !preg_match('/^1[34578]\d{9}$/', $phone)) {
            Utils::throwError(ErrorConst::FINANCE_PHONE_ERROR);
        }

        // 检验银行卡号
        if (!preg_match('/^[0-9]{14,19}$/', $cardNumber)) {
            Utils::throwError(ErrorConst::FINANCE_CARD_NUMBER_ERROR);
        }

        // 校验手机验证码
        $isValid = $this->bankDao->checkSmsCode($channelId, $phone, $code);
        if (!$isValid) {
            Utils::throwError(ErrorConst::FINANCE_SMS_CHECK_FAILED);
        }

        // 获取银行信息
        $bank = $this->bankDao->getBank($bankId);
        if (!getProp($bank, 'id')) {
            Utils::throwError(ErrorConst::PARAM_ERROR_CODE);
        }

        // 获取全部账号列表，判断重复提交
        $cashAccounts = $this->bankDao->getValidCashAccountsByChannelUserId($channelUserId);
        if (collect($cashAccounts)->where('card_number', $cardNumber)->all()) {
            Utils::throwError(ErrorConst::FINANCE_ACCOUNT_EXISTED);
        }

        // 写入数据库
        $insertData = [
            'channel_user_id' => $channelUserId,
            'account_name'    => $accountName,
            'identity_card'   => $identityCard,
            'card_number'     => $cardNumber,
            'account_bank'    => $accountBank,
            'bank'            => getProp($bank, 'name'),
            'province'        => $province,
            'phone'           => $phone,
            'bank_id'         => $bankId,
            'is_company'      => $isCompany,
            'status'          => FinanceConsts::STATUS_FORBID_UPDATE,
            'updated_at'      => date('Y-m-d H:i:s'),
        ];
        $insertId   = $this->bankDao->addCashAccount($insertData);
        if (!$insertId) {
            Utils::throwError(ErrorConst::SYS_EXCEPTION);
        }

        // 删除验证码
        FinanceCache::delSmsCode($channelId, $phone);

        return $insertId;
    }

    /**
     * 删除银行卡账号
     *
     * @param $params
     * @return bool
     * @throws ApiException
     */
    public function delBankAccount($params): bool
    {
        // 基本参数
        $id            = getProp($params, 'id');
        $deleteAll     = (int)getProp($params, 'delete_all');
        $channelUserId = Site::getUid();

        // 删除全部
        if ($deleteAll) {
            return $this->bankDao->deleteCashAccountByChannelUserId($channelUserId);
        }

        // 参数简易判断
        if (!$id || !is_numeric($id)) {
            Utils::throwError(ErrorConst::PARAM_ERROR_CODE);
        }

        // 校验银行卡
        $cardInfo = $this->bankDao->getValidCashAccountById($id);
        if (!$cardInfo) {
            Utils::throwError(ErrorConst::RECORD_NOT_EXIST);
        }

        // 权限
        if ((int)getProp($cardInfo, 'channel_user_id') !== (int)$channelUserId) {
            Utils::throwError(ErrorConst::NOT_ACCESS);
        }

        // 执行更新
        $result = $this->bankDao->deleteCashAccountByCardId($id);
        if (!$result) {
            Utils::throwError(ErrorConst::SYS_EXCEPTION);
        }

        return true;
    }

    /**
     * 发送验证码
     *
     * @return bool
     * @throws ApiException
     */
    public function getBankAccountSms(): bool
    {
        $channelId = Site::getCurrentChannelId();
        $phone     = Site::getPhone();

        // 获取当前手机号的验证码
        $code = FinanceCache::getSmsCode($channelId, $phone);
        if ($code) {
            Utils::throwError(ErrorConst::FINANCE_SMS_EXIST);
        }

        // 生成新的验证码并发送
        $newCode = mt_rand(1000, 9999);

        // 记录缓存
        FinanceCache::setSmsCode($channelId, $phone, $newCode);

        // 发送验证码
        $sendRes = $this->smsService->sendSms($phone, 'update_withdraw_cash', ['code' => $newCode]);
        if (!$sendRes) {
            Utils::throwError(ErrorConst::FINANCE_SMS_FAILED);
        }

        return true;
    }
}