<?php

namespace App\Settlement\Service;

use App\Config\Repository\SiteConfigRepository;
use App\Payment\Entity\Payment;
use App\Representation\Entity\Representation;
use App\Representation\Repository\RepresentationRepository;
use App\Settlement\Entity\FinancialBreakdown;
use App\Settlement\Entity\WalletTransaction;
use App\Settlement\Repository\FinancialBreakdownRepository;
use App\Settlement\Repository\SettlementRepository;
use App\Settlement\Repository\WalletTransactionRepository;
use Doctrine\ORM\EntityManagerInterface;

/**
 * موتور تقسیم مالی پس از پرداخت موفق.
 * ترتیب ثابت: ۱) کسر هزینه پنل پیامک  ۲) کسر مالیات از باقی‌مانده  ۳) پورسانت نماینده از خالصِ پس از مالیات.
 */
class CommissionService
{
    public function __construct(
        private readonly SiteConfigRepository         $configRepo,
        private readonly RepresentationRepository     $representationRepo,
        private readonly SettlementRepository         $settlementRepo,
        private readonly WalletTransactionRepository  $walletRepo,
        private readonly FinancialBreakdownRepository $breakdownRepo,
        private readonly EntityManagerInterface       $em,
    ) {}

    /**
     * پورسانت نوبت: درصد = commission_percent همان نماینده.
     * گاردِ دامنه: فقط وقتی که پزشک متعلق به نماینده باشد و نوبت هم از دامنه‌ی همان نماینده ثبت شده باشد.
     */
    public function processAppointment(Payment $payment, ?int $doctorRepId, ?int $bookingRepId, ?int $doctorId): void
    {
        if ($this->configRepo->get('appointment_commission_enabled') !== '1') return;

        // هر دو شرط لازم است و باید یکی باشند.
        if ($doctorRepId === null || $bookingRepId === null || $doctorRepId !== $bookingRepId) return;

        $rep = $this->resolveRep($doctorRepId);
        if ($rep === null) return;

        $this->settle(
            $payment,
            FinancialBreakdown::SOURCE_APPOINTMENT,
            (float) $rep->getCommissionPercent(),
            $rep,
            $doctorId,
            null,
        );
    }

    /**
     * پورسانت ارتقاء اشتراک: درصد سراسری = upgrade_commission_percent.
     * گاردِ دامنه (مثل نوبت): مالک پزشک/کلینیک و نماینده‌ی دامنه‌ی خرید باید یکی باشند.
     */
    public function processSubscription(Payment $payment, ?int $ownerRepId, ?int $bookingRepId, ?int $doctorId, ?int $clinicId): void
    {
        if ($this->configRepo->get('upgrade_commission_enabled') !== '1') return;

        if ($ownerRepId === null || $bookingRepId === null || $ownerRepId !== $bookingRepId) return;

        $rep = $this->resolveRep($ownerRepId);
        if ($rep === null) return;

        $this->settle(
            $payment,
            FinancialBreakdown::SOURCE_SUBSCRIPTION,
            (float) $this->configRepo->get('upgrade_commission_percent'),
            $rep,
            $doctorId,
            $clinicId,
        );
    }

    private function resolveRep(?int $representationId): ?Representation
    {
        if ($representationId === null) return null;
        $rep = $this->representationRepo->find($representationId);
        return ($rep !== null && $rep->isActive()) ? $rep : null;
    }

    private function settle(
        Payment $payment,
        string $source,
        float $commissionPercent,
        Representation $rep,
        ?int $doctorId,
        ?int $clinicId,
    ): void {
        // پرداخت دوبار پردازش نشود.
        if ($this->breakdownRepo->existsForPayment($payment)) return;

        $gross = $payment->getAmountRials();

        // مرحله ۱: کسر هزینه ثابت پنل پیامک.
        $smsFee   = (int) $this->configRepo->get('sms_panel_fee_rials');
        $afterSms = max(0, $gross - $smsFee);

        // مرحله ۲: مالیاتِ استخراجی از مبلغِ شامل مالیات: tax = amount × p/(100+p).
        $taxEnabled = $this->configRepo->get('tax_enabled') === '1';
        $taxPercent = $taxEnabled ? (float) $this->configRepo->get('tax_percent') : 0.0;
        $taxRials   = ($taxEnabled && $taxPercent > 0)
            ? (int) round($afterSms * $taxPercent / (100 + $taxPercent))
            : 0;
        $netAfterTax = $afterSms - $taxRials;

        // مرحله ۳: پورسانت نماینده از خالصِ پس از مالیات.
        $repShare    = (int) round($netAfterTax * $commissionPercent / 100);
        $systemShare = $gross - $smsFee - $taxRials - $repShare;

        $repUser = $rep->getUser();

        if ($repShare > 0) {
            $balance = $this->settlementRepo->getWalletBalance($repUser);
            $tx = new WalletTransaction($repUser, $repShare, WalletTransaction::TYPE_CREDIT, $balance + $repShare);
            $tx->setPayment($payment);
            $tx->setDescription(sprintf('پورسانت %s %s', $source, $payment->getOrderId()));
            $this->walletRepo->save($tx, false);
        }

        $breakdown = new FinancialBreakdown(
            $payment,
            $source,
            $payment->getUser(),
            $gross,
            $smsFee,
            number_format($taxPercent, 2, '.', ''),
            $taxRials,
            $netAfterTax,
            number_format($commissionPercent, 2, '.', ''),
            $repShare,
            $systemShare,
            $rep->getId(),
            $doctorId,
            $clinicId,
        );
        $this->breakdownRepo->save($breakdown, false);

        $this->em->flush();
    }
}
