<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;

/**
 * MachinePayment Model
 *
 * Represents a payment transaction for digital machine listings.
 * Integrates with MTN MoMo PaymentService for collection.
 *
 * @property int $id
 * @property int|null $digital_machine_id
 * @property int|null $user_id
 * @property float $amount
 * @property string $currency
 * @property string $payment_frequency
 * @property string $payment_method
 * @property string|null $transaction_id
 * @property string $reference
 * @property string|null $phone_number
 * @property string $status
 *
 * Requirements: 3.3, 3.4, 9.2, 10.2
 */
class MachinePayment extends Model
{
    use HasFactory;

    /**
     * The attributes that are mass assignable.
     *
     * @var array<int, string>
     */
    protected $fillable = [
        'digital_machine_id',
        'user_id',
        'amount',
        'currency',
        'payment_frequency',
        'payment_method',
        'transaction_id',
        'reference',
        'phone_number',
        'payer_message',
        'payee_note',
        'status',
        'status_message',
        'failure_reason',
        'initiated_at',
        'paid_at',
        'expires_at',
        'coverage_start',
        'coverage_end',
        'metadata',
    ];

    /**
     * The attributes that should be cast.
     *
     * @var array<string, string>
     */
    protected $casts = [
        'amount' => 'decimal:2',
        'initiated_at' => 'datetime',
        'paid_at' => 'datetime',
        'expires_at' => 'datetime',
        'coverage_start' => 'datetime',
        'coverage_end' => 'datetime',
        'metadata' => 'array',
    ];

    /**
     * The model's default values for attributes.
     *
     * @var array
     */
    protected $attributes = [
        'currency' => 'SSP',
        'payment_method' => 'mtn_momo',
        'payment_frequency' => 'yearly',
        'status' => 'pending',
    ];

    // =========================================================================
    // RELATIONSHIPS
    // =========================================================================

    /**
     * Get the digital machine associated with this payment.
     */
    public function machine(): BelongsTo
    {
        return $this->belongsTo(DigitalMachine::class, 'digital_machine_id');
    }

    /**
     * Get the user who made this payment.
     */
    public function user(): BelongsTo
    {
        return $this->belongsTo(User::class);
    }

    // =========================================================================
    // SCOPES
    // =========================================================================

    /**
     * Scope a query to only include successful payments.
     */
    public function scopeSuccessful($query)
    {
        return $query->where('status', 'successful');
    }

    /**
     * Scope a query to only include pending payments.
     */
    public function scopePending($query)
    {
        return $query->where('status', 'pending');
    }

    /**
     * Scope a query to only include failed payments.
     */
    public function scopeFailed($query)
    {
        return $query->whereIn('status', ['failed', 'timeout', 'cancelled']);
    }

    /**
     * Scope a query to filter by user.
     */
    public function scopeByUser($query, int $userId)
    {
        return $query->where('user_id', $userId);
    }

    /**
     * Scope a query to filter by machine.
     */
    public function scopeByMachine($query, int $machineId)
    {
        return $query->where('digital_machine_id', $machineId);
    }

    /**
     * Scope to order by latest.
     */
    public function scopeLatest($query)
    {
        return $query->orderBy('created_at', 'desc');
    }

    // =========================================================================
    // ACCESSORS
    // =========================================================================

    /**
     * Get the formatted amount.
     */
    public function getFormattedAmountAttribute(): string
    {
        $currency = $this->currency === 'USD' ? '$' : 'SSP ';
        return $currency . number_format($this->amount, 2);
    }

    /**
     * Get the status badge color.
     */
    public function getStatusBadgeColorAttribute(): string
    {
        return match ($this->status) {
            'successful' => 'green',
            'pending', 'processing' => 'yellow',
            'failed', 'timeout', 'cancelled' => 'red',
            'refunded' => 'purple',
            default => 'gray',
        };
    }

    /**
     * Get the payment frequency label.
     */
    public function getFrequencyLabelAttribute(): string
    {
        return match ($this->payment_frequency) {
            'one_time' => 'One-time Payment',
            'monthly' => 'Monthly Subscription',
            'quarterly' => 'Quarterly Subscription',
            'biannual' => 'Bi-annual Subscription',
            'yearly' => 'Annual Subscription',
            default => ucfirst($this->payment_frequency),
        };
    }

    /**
     * Check if payment is successful.
     */
    public function isSuccessful(): bool
    {
        return $this->status === 'successful';
    }

    /**
     * Check if payment is pending.
     */
    public function isPending(): bool
    {
        return in_array($this->status, ['pending', 'processing']);
    }

    /**
     * Check if payment has failed.
     */
    public function hasFailed(): bool
    {
        return in_array($this->status, ['failed', 'timeout', 'cancelled']);
    }

    // =========================================================================
    // HELPER METHODS
    // =========================================================================

    /**
     * Mark payment as successful.
     */
    public function markSuccessful(string $transactionId, ?\Carbon\Carbon $paidAt = null): void
    {
        $this->update([
            'status' => 'successful',
            'transaction_id' => $transactionId,
            'paid_at' => $paidAt ?? now(),
            'status_message' => 'Payment completed successfully',
        ]);

        // Update machine payment status
        if ($this->machine) {
            $this->machine->update([
                'payment_status' => 'paid',
                'next_payment_date' => $this->coverage_end,
                'listing_status' => 'pending_approval', // Requires admin approval
                'expires_at' => $this->coverage_end,
            ]);
        }
    }

    /**
     * Mark payment as failed.
     */
    public function markFailed(string $reason): void
    {
        $this->update([
            'status' => 'failed',
            'failure_reason' => $reason,
            'status_message' => 'Payment failed: ' . $reason,
        ]);
    }

    /**
     * Generate a unique reference.
     *
     * Uses MCH-PAY- prefix so MomoCallbackController can route callbacks correctly.
     * Requirements: 19.6
     */
    public static function generateReference(): string
    {
        return 'MCH-PAY-' . strtoupper(uniqid()) . '-' . time();
    }

    // =========================================================================
    // STATIC METHODS
    // =========================================================================

    /**
     * Get payment status options.
     */
    public static function getStatuses(): array
    {
        return [
            'pending' => 'Pending',
            'processing' => 'Processing',
            'successful' => 'Successful',
            'failed' => 'Failed',
            'timeout' => 'Timeout',
            'cancelled' => 'Cancelled',
            'refunded' => 'Refunded',
        ];
    }

    /**
     * Get payment frequency options.
     */
    public static function getFrequencies(): array
    {
        return [
            'one_time' => 'One-time',
            'monthly' => 'Monthly',
            'quarterly' => 'Quarterly',
            'biannual' => 'Bi-annual',
            'yearly' => 'Yearly',
        ];
    }
}
