<?php

namespace App\Services;

use App\Models\ShoppingOrder;
use App\Models\ShoppingPayment;
use App\Models\UserPayCredit;
use App\Models\PaymentTransaction;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;

class PaymentService
{
    public static $txaction_art = [
        'user_order' => "Vertriebspartner",
        'customer_order' => "Kundenbestellung",
        'user_for_customer' => "VP.Kundenbestellung",
    ];

    // Konstanten für bessere Wartbarkeit
    const CREDIT_STATUS_DEDUCTION = 2;
    const CREDIT_STATUS_RETURN = 4;
    const CREDIT_STATUS_CHARGED = 7;
    const CREDIT_STATUS_REMOVED = 8;
    
    const TRANSACTION_REQUEST = 'transaction';
    const DEFAULT_TXID = 0;
    const DEFAULT_USERID = 0;
    
    /**
     * Aktualisiert den Transaktionsstatus einer Bestellung
     * 
     * @param int $orderId
     * @param string $txaction
     * @param int $paymentId
     * @return bool
     * @throws \Exception
     */
    public static function updateTransactionStatus($orderId, $txaction, $paymentId)
    {
        // Validierung der Eingabeparameter
        if (empty($orderId) || empty($txaction) || empty($paymentId)) {
            throw new \InvalidArgumentException('Alle Parameter müssen angegeben werden');
        }

        return DB::transaction(function () use ($orderId, $txaction, $paymentId) {
            $shopping_order = ShoppingOrder::findOrFail($orderId);
            $shopping_payment = ShoppingPayment::findOrFail($paymentId);

            // Prüfen ob sich der Status tatsächlich geändert hat
            if ($shopping_payment->txaction === $txaction) {
                return false;
            }

            // Guthaben-Logik für Partner-Center Bestellungen
            self::handlePartnerCenterCredits($shopping_order, $txaction);

            // PaymentTransaction erstellen
            $paymentTransaction = self::createPaymentTransaction($shopping_payment, $txaction);

            // Bestellung und Payment aktualisieren
            self::updateOrderAndPayment($shopping_order, $shopping_payment, $txaction, $paymentTransaction);

            // Paid-Action ausführen falls nötig
            self::handlePaidAction($paymentTransaction, $shopping_order);

            // Credit-Loading Logik
            self::handleCreditLoading($shopping_order, $txaction);

            // E-Mail versenden
            self::sendStatusEmail($shopping_order, $shopping_payment, $paymentTransaction);

            return true;
        });
    }

    /**
     * Behandelt Guthaben-Logik für Partner-Center Bestellungen
     */
    private static function handlePartnerCenterCredits(ShoppingOrder $shoppingOrder, string $txaction): void
    {
        if (!$shoppingOrder->shopping_order_margin || $shoppingOrder->shopping_order_margin->from_payment_credit <= 0) {
            return;
        }

        $lastUserPayCredit = self::getLastUserPayCredit($shoppingOrder->id, [self::CREDIT_STATUS_DEDUCTION, self::CREDIT_STATUS_RETURN]);

        if (!$lastUserPayCredit) {
            return;
        }

        // Status Keine Zahlung, Guthaben zurückführen
        if ($txaction === 'non' && $lastUserPayCredit->status === self::CREDIT_STATUS_DEDUCTION) {
            Payment::handelUserPayCredits($shoppingOrder, 'return');
        }

        // Status Zahlung, vorher gab es eine Storno, Guthaben abziehen
        if ($lastUserPayCredit->status === self::CREDIT_STATUS_RETURN && in_array($txaction, ['open', 'paid'])) {
            Payment::handelUserPayCredits($shoppingOrder, 'deduction');
        }
    }

    /**
     * Erstellt eine neue PaymentTransaction
     */
    private static function createPaymentTransaction(ShoppingPayment $shoppingPayment, string $txaction): PaymentTransaction
    {
        return PaymentTransaction::create([
            'shopping_payment_id' => $shoppingPayment->id,
            'request' => self::TRANSACTION_REQUEST,
            'txid' => self::DEFAULT_TXID,
            'userid' => self::DEFAULT_USERID,
            'status' => $shoppingPayment->clearingtype,
            'transmitted_data' => null,
            'txaction' => $txaction,
            'mode' => $shoppingPayment->mode,
        ]);
    }

    /**
     * Aktualisiert Bestellung und Payment
     */
    private static function updateOrderAndPayment(ShoppingOrder $shoppingOrder, ShoppingPayment $shoppingPayment, string $txaction, PaymentTransaction $paymentTransaction): void
    {
        $shoppingOrder->txaction = $txaction;
        $shoppingOrder->paid = $paymentTransaction->txaction === 'paid';
        $shoppingOrder->save();

        $shoppingPayment->txaction = $txaction;
        $shoppingPayment->save();
    }

    /**
     * Führt Paid-Action aus falls nötig
     */
    private static function handlePaidAction(PaymentTransaction $paymentTransaction, ShoppingOrder $shoppingOrder): void
    {
        if ($paymentTransaction->status === 'vor' && $paymentTransaction->txaction === 'paid') {
            Payment::paymentStatusPaidAction($shoppingOrder, true);
        }
    }

    /**
     * Behandelt Credit-Loading Logik
     */
    private static function handleCreditLoading(ShoppingOrder $shoppingOrder, string $txaction): void
    {
        if (!$shoppingOrder->shopping_user || $shoppingOrder->shopping_user->is_for !== 'cr') {
            return;
        }

        $lastUserPayCredit = self::getLastUserPayCredit($shoppingOrder->id, [self::CREDIT_STATUS_CHARGED, self::CREDIT_STATUS_REMOVED]);

        if (!$lastUserPayCredit) {
            return;
        }

        // Status Keine Zahlung, Guthaben abziehen
        if ($txaction === 'non' && $lastUserPayCredit->status === self::CREDIT_STATUS_CHARGED) {
            Payment::handelUserPayChargingCredits($shoppingOrder, 'remove');
        }

        // Status Zahlung, vorher gab es eine Storno, Guthaben wieder aufladen
        if ($lastUserPayCredit->status === self::CREDIT_STATUS_REMOVED && $txaction === 'paid') {
            Payment::handelUserPayChargingCredits($shoppingOrder, 'add');
        }
    }

    /**
     * Sendet Status-E-Mail
     */
    private static function sendStatusEmail(ShoppingOrder $shoppingOrder, ShoppingPayment $shoppingPayment, PaymentTransaction $paymentTransaction): void
    {
        $emailData = [
            'mode' => $paymentTransaction->mode,
            'txaction' => $paymentTransaction->txaction,
            'send_link' => false,
        ];

        try {
            Payment::paymentStatusSendMail($shoppingOrder, $shoppingPayment, $emailData);
        } catch (\Exception $e) {
            Log::error('Fehler beim Senden der Status-E-Mail', [
                'order_id' => $shoppingOrder->id,
                'payment_id' => $shoppingPayment->id,
                'error' => $e->getMessage()
            ]);
        }
    }

    /**
     * Holt den letzten UserPayCredit Eintrag
     */
    private static function getLastUserPayCredit(int $orderId, array $statuses): ?UserPayCredit
    {
        return UserPayCredit::where('shopping_order_id', $orderId)
            ->whereIn('status', $statuses)
            ->orderBy('id', 'DESC')
            ->first();
    }
} 