<?php

namespace Shm\ShmPayment\TBankPayment;

use Shm\ShmPayment\TBankPayment\TBankCollections\TPayments;

class TBankCancel
{
    public $paymentId;

    private $amountKopecks = null;
    private $manualAmount = false;

    /**
     * @var TBankReceiptItem[]
     */
    public $Items = [];

    public $success = false;

    public $status;

    /** Сумма исходного платежа в рублях */
    public $originalAmount;

    /** Сумма после отмены в рублях */
    public $newAmount;

    public $description;

    public function __construct() {}

    public static function create($paymentId)
    {
        $TBankCancel = new TBankCancel();
        $TBankCancel->paymentId($paymentId);
        return $TBankCancel;
    }

    public function paymentId($paymentId)
    {
        $this->paymentId = $paymentId;
        return $this;
    }

    public function amount($amount)
    {
        if ($amount <= 0) {
            throw new \Exception("amount должно быть больше 0");
        }
        if (count($this->Items) > 0) {
            throw new \Exception("Нельзя установить amount если есть товары Items: " . count($this->Items));
        }
        $this->manualAmount = true;
        $this->amountKopecks = TBankAmount::toKopecks($amount);
        return $this;
    }

    public function addItem(TBankReceiptItem $item)
    {
        if ($this->manualAmount) {
            throw new \Exception("Нельзя добавить товары если установлен amount");
        }
        $this->Items[] = $item;
        $this->amountKopecks = ($this->amountKopecks ?? 0) + $item->amount();
        return $this;
    }

    public function description($description)
    {
        $this->description = $description;
        return $this;
    }

    public function readyToRequest(): bool
    {
        if (!$this->paymentId) {
            return false;
        }

        return true;
    }

    private function prepareItems()
    {
        return array_map(function (TBankReceiptItem $item) {
            return $item->toArray();
        }, $this->Items);
    }

    private function originalAmountInKopecks($payment): int
    {
        if (isset($payment['initRequest']['Amount'])) {
            return (int) round((float) $payment['initRequest']['Amount']);
        }

        return TBankAmount::toKopecks($payment['amount'] ?? 0);
    }

    private function isFullRefund($payment): bool
    {
        return $this->amountKopecks !== null && $this->amountKopecks === $this->originalAmountInKopecks($payment);
    }

    private function isPartialCancel(): bool
    {
        return $this->amountKopecks !== null || count($this->Items) > 0;
    }

    public function request()
    {
        $payment = TPayments::findOne([
            'paymentId' => $this->paymentId,
        ]);

        if (!$payment) {
            throw new \Exception("Payment not found");
        }

        $data = [
            'PaymentId' => $this->paymentId,
        ];

        if ($this->amountKopecks !== null) {
            $data['Amount'] = $this->amountKopecks;
        }

        if ($this->isPartialCancel() && !$this->isFullRefund($payment)) {
            if (count($this->Items) > 0) {
                $data['Receipt'] = [
                    "Taxation" => TBankPayment::$terminalTaxation,
                    "Items" => $this->prepareItems(),
                ];
            } else {
                $description = $this->description ?? $payment['description'] ?? null;
                if (!$description) {
                    throw new \Exception("description обязательно если нет товаров Items");
                }

                $data['Receipt'] = [
                    "Taxation" => TBankPayment::$terminalTaxation,
                    "Items" => [
                        [
                            "Name" => $description,
                            "Price" => $this->amountKopecks,
                            "Quantity" => 1,
                            "Amount" => $this->amountKopecks,
                            "Tax" => TBankPayment::$terminalTaxRate
                        ]
                    ],
                ];
            }

            if ($payment['phone'] ?? null) {
                $data['Receipt']['Phone'] = $payment['phone'];
            }
            if ($payment['email'] ?? null) {
                $data['Receipt']['Email'] = $payment['email'];
            }
        }

        $response = TBankPayment::sendRequest('Cancel', $data);

        $this->success = $response['Success'] ?? false;
        $this->status = $response['Status'] ?? null;
        $this->originalAmount = isset($response['OriginalAmount'])
            ? TBankAmount::toRubles($response['OriginalAmount'])
            : null;
        $this->newAmount = isset($response['NewAmount'])
            ? TBankAmount::toRubles($response['NewAmount'])
            : null;

        $update = [
            '$push' => [
                'cancelResult' => [
                    'request' => $data,
                    'result' => $response,
                    'created_at' => time(),
                ],
            ],
        ];
        if ($this->status) {
            $update['$set']['status'] = $this->status;
        }

        TPayments::updateOne(
            [
                '_id' => $payment['_id']
            ],
            $update
        );

        return $response;
    }
}
