<?php

namespace App\Services;

use App\Models\Customer;
use App\Models\Invoice;
use App\Models\LoyaltyTransaction;
use App\Models\Currency;
use Illuminate\Database\Eloquent\Model;

class LoyaltyService
{
    /**
     * Calculate and award points for a payment.
     * 
     * @param Customer $customer
     * @param float $amount The payment amount
     * @param Currency|null $currency
     * @param string $description
     * @param Model $reference The related model (Invoice or Payment)
     * @return LoyaltyTransaction|null
     */
    public function awardPoints(Customer $customer, float $amount, ?Currency $currency, string $description, $reference)
    {
        if (!$customer->loyalty_enabled) {
            return null;
        }

        // Determine rate
        // Default rate is usually 1 if not specified
        // But we added points_per_currency_unit to Currency model.
        // If currency is null (default currency), we might need a default rate or fetch default currency.

        $rate = 1;

        if ($currency) {
            $rate = $currency->points_per_currency_unit;
        } elseif ($defaultCurrency = Currency::where('is_default', true)->first()) {
            $rate = $defaultCurrency->points_per_currency_unit;
        }

        $points = $amount * $rate;

        if ($points <= 0) {
            return null;
        }

        // Add to customer balance
        $customer->increment('loyalty_points', $points);

        // Record Transaction
        return LoyaltyTransaction::create([
            'customer_id' => $customer->id,
            'points' => $points,
            'type' => 'earned',
            'reference_type' => get_class($reference),
            'reference_id' => $reference->id,
            'description' => $description,
            'date' => now(),
        ]);
    }

    /**
     * Redeem points for a discount/payment on an invoice.
     *
     * @param Invoice $invoice
     * @param float $pointsToRedeem
     * @return LoyaltyTransaction|null
     */
    public function redeemPoints(Invoice $invoice, float $pointsToRedeem)
    {
        $customer = $invoice->customer;

        if (!$customer || $pointsToRedeem <= 0) {
            return null;
        }

        if ($customer->loyalty_points < $pointsToRedeem) {
            throw new \Exception("Insufficient loyalty points.");
        }

        // Calculate value
        // Value = Points / Rate ??
        // Actually, usually: 1 Point = X Money.
        // We defined "Points Per Currency Unit" (e.g. 10 Points for 1 USD).
        // So Value = Points / Points_Per_Unit.
        // E.g. 100 Points / 10 = 10 USD.

        // Use currency of the invoice if possible, or customer currency, or default.
        // Ideally invoices should have a currency_id. If not, assuming system default.

        $rate = 1;
        // Assuming default currency for now if invoice doesn't store currency
        // Or if we want to be precise, we need the currency of the invoice.
        // Let's assume default for now as we don't have currency_id on invoice yet (maybe?).
        // Checking Invoice model... it doesn't show currency_id.

        $defaultCurrency = Currency::where('is_default', true)->first();
        if ($defaultCurrency) {
            $rate = $defaultCurrency->points_per_currency_unit;
        }

        if ($rate <= 0)
            $rate = 1; // Prevent division by zero

        $moneyValue = $pointsToRedeem / $rate;

        // Verify if invoice total is enough?
        // Usually we can't pay more than total.
        if ($moneyValue > $invoice->total - $invoice->paid_amount) {
            // Optional: Limit redemption to remaining balance?
            // Or throw error.
            // For now, let's just proceed.
        }

        // Deduct from customer
        $customer->decrement('loyalty_points', $pointsToRedeem);

        // Update Invoice
        $invoice->loyalty_points_redeemed += $pointsToRedeem;
        $invoice->loyalty_amount_redeemed += $moneyValue;

        // Should we mark it as "paid" amount or "discount"?
        // Detailed requirement: "Anzel men el fatora el noqat".
        // It acts like a discount or payment.
        // Ideally updates paid_amount too effectively, OR total is reduced?
        // If it's a discount, Subtotal - Discount = Total.
        // If it's a payment, Total stays same, Paid Amount increases.
        // "Convert money to points... user pays it".
        // Sounds like a payment method (Loyalty Payment).

        $invoice->paid_amount += $moneyValue;
        $invoice->save();

        if ($invoice->paid_amount >= $invoice->total) {
            $invoice->status = 'paid';
            $invoice->save();
        }

        // Record Transaction
        return LoyaltyTransaction::create([
            'customer_id' => $customer->id,
            'points' => -$pointsToRedeem,
            'type' => 'redeemed',
            'reference_type' => get_class($invoice),
            'reference_id' => $invoice->id,
            'description' => "Redemption for Invoice #{$invoice->code}",
            'date' => now(),
        ]);
    }
}
