<?php

namespace App\Modules\Finance\Services;

use App\Modules\Channel\Models\Channel;
use App\Modules\Finance\Models\Bill;
use App\Modules\Finance\Models\CommissionRate;
use App\Modules\Finance\Models\FinancialPayMerchantBalance;
use App\Modules\Finance\Models\FinancialStat;
use App\Modules\Trade\Models\Order;
use DB;
use Exception;

/**
 * 渠道结算
 * 
 * @property \App\Modules\Channel\Models\Channel $channel 渠道Model
 * @property string $day 日期
 * @property float $rate 结算比例
 */
class CalcChannel
{
    private $channel;

    private $day;

    private $rate;

    public function __construct(Channel $channel)
    {
        $this->day = date('Y-m-d', strtotime("-1 day"));
        $this->channel = $channel;
        $this->rate = $this->getRate();
    }

    /**
     * 获取渠道当前结算比例
     * @return float
     */
    private function getRate()
    {
        $rate = 0.0;
        $commissionRates = CommissionRate::where('distribution_channel_id', $this->channel->id)
            ->orderBy('begin_amount', 'asc')
            ->get()
            ->all();
        if (count($commissionRates) == 1) {
            $commissionRate = $commissionRates[0];
            $rate = $commissionRate->rate;
        } else if ($commissionRates) {
            $startMonth = date('Y-m-01');
            $endMonth = date('Y-m-d', strtotime("$startMonth +1 month -1 day"));
            $rechargeAmountCount = Bill::where('distribution_channel_id', $this->channel->id)
                ->where('date', '<=', $endMonth)
                ->where('date', '>=', $startMonth)
                ->sum('recharge_amount');
            foreach ($commissionRates as $commissionRate) {
                if ($rechargeAmountCount >=  $commissionRate->begin_amount) {
                    //结束金额存在，并且结算金额小于结束金额，结束
                    if (
                        is_numeric($commissionRate->end_amount) &&
                        $commissionRate->end_amount > 0 &&
                        $rechargeAmountCount < $commissionRate->end_amount
                    ) {
                        $rate = $commissionRate->rate;
                        break;
                    }
                    $rate = $commissionRate->rate;
                }
            }
        }
        return $rate;
    }


    /**
     * 计算结算数据
     */
    public function calc()
    {
        $amount = $this->getChannelOrdersAmount();
        $pay_merchants_amount = $this->getChannelPayMerchantsOrdersAmount();
        try {
            DB::beginTransaction();
            $this->createBill($amount);
            $this->createPayMerchantBills($pay_merchants_amount);
            DB::commit();
        } catch (Exception $e) {
            DB::rollback();
        }
    }

    /**
     * 获取结算金额
     * @return float
     */
    private function getChannelOrdersAmount()
    {
        return Order::join('pay_merchants', 'pay_merchants.id', 'orders.pay_merchant_id')
            ->where('orders.status', 'PAID')->where('orders.distribution_channel_id', $this->channel->id)
            ->where('orders.created_at', '<=', $this->day . '23:59:59')->where('orders.created_at', '>=', $this->day)
            ->where('pay_merchants.is_self_channel', 1)
            ->sum('orders.price');
    }

    /**
     * 创建结算单
     */
    private function createBill(float $amount)
    {
        $params = [
            'distribution_channel_id' => $this->channel->id,
            'distribution_channel_name' => $this->channel->nickname,
            'date' => $this->day,
            'recharge_amount' => $amount,
            'settlement_price' => $amount * $this->rate,
            'rate' => $this->rate,
            'tallage' => 0,
        ];
        Bill::create($params);
        $this->updateFinance($params);
    }

    /**
     * 更新渠道可提现金额
     */
    private function updateFinance(array $data)
    {
        $financialStat = FinancialStat::where('distribution_channel_id', $this->channel->id)->first();
        if ($financialStat) {
            $financialStat->enable_withdrawal_amount = (float) $financialStat->enable_withdrawal_amount + (float) $data['settlement_price'];
            $financialStat->commission_rate = $this->rate;
            $financialStat->save();
        } else {
            $params = [
                'distribution_channel_id' => $this->channel->id,
                'accumulative_withdrawal_amount' => 0,
                'enable_withdrawal_amount' => $data['settlement_price'],
                'latest_withdrawal_amount' => 0,
                'withdraw_pending_amount' => 0,
                'commission_rate' => $this->rate
            ];
            FinancialStat::create($params);
        }
    }

    /**
     * 获取不同的支付通道的结算金额
     * @return array
     */
    private function getChannelPayMerchantsOrdersAmount()
    {
        return Order::join('pay_merchants', 'pay_merchants.id', 'orders.pay_merchant_id')
            ->where('orders.status', 'PAID')->where('orders.distribution_channel_id', $this->channel->id)
            ->where('orders.created_at', '<=', $this->day . '23:59:59')->where('orders.created_at', '>=', $this->day)
            ->where('pay_merchants.is_self_channel', 1)
            ->groupBy('pay_merchants.pay_company_id')
            ->selectRaw('sum(orders.price) as amount,pay_company_id,pay_company_name')
            ->get()
            ->all();
    }

    /**
     * 创建不同支付通道的结算单
     */
    private function createPayMerchantBills(array $pay_merchants_amount)
    {
        foreach ($pay_merchants_amount as $item) {
            $params = [
                'distribution_channel_id' => $this->channel->id,
                'date' => $this->day,
                'recharge_amount' => $item->amount,
                'settlement_price' => $item->amount * $this->rate,
                'rate' => $this->rate,
                'pay_company_id' => $item->pay_company_id,
                'tallage' => 0,
            ];
            BillPayMerchant::create($params);
            $this->updatePayMerchantFinance($params);
        }
    }

    /**
     * 更新不同支付通道的可提现金额
     */
    private function updatePayMerchantFinance(array $data)
    {
        $financialStat = FinancialPayMerchantBalance::where('distribution_channel_id', $this->channel->id)
            ->where('pay_merchant_company_id', $data['pay_company_id'])
            ->first();
        if ($financialStat) {
            $financialStat->enable_withdrawal_amount = (float) $financialStat->enable_withdrawal_amount + (float) $data['settlement_price'];
            $financialStat->commission_rate = $this->rate;
            $financialStat->save();
        } else {
            $params = [
                'distribution_channel_id' => $this->channel->id,
                'pay_merchant_company_id' => $data['pay_company_id'],
                'accumulative_withdrawal_amount' => 0,
                'enable_withdrawal_amount' => $data['settlement_price'],
                'latest_withdrawal_amount' => 0,
                'withdraw_pending_amount' => 0,
                'commission_rate' => $this->rate
            ];
            FinancialPayMerchantBalance::create($params);
        }
    }
}
