<?php

namespace App\Models\Mentorship;

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

class Payment extends Model
{
    use HasFactory;

    /**
     * The table associated with the model.
     */
    protected $table = 'mentorship_payments';

    /**
     * The attributes that are mass assignable.
     */
    protected $fillable = [
        'application_id',
        'programme_id',
        'user_id',
        'amount',
        'currency',
        'payment_type',
        'description',
        'payment_method',
        'phone_number',
        'reference',
        'transaction_id',
        'external_reference',
        'status',
        'momo_transaction_id',
        'momo_reference',
        'momo_financial_transaction_id',
        'initiated_at',
        'completed_at',
        'failed_at',
        'refunded_at',
        'request_data',
        'response_data',
        'callback_data',
        'error_code',
        'error_message',
        'retry_count',
        'last_retry_at',
        'retry_reason',
        'refund_amount',
        'refund_reference',
        'refund_reason',
        'refunded_by',
        'receipt_number',
        'receipt_sent_at',
        'admin_notes',
        'ip_address',
        'user_agent',
    ];

    /**
     * The attributes that should be cast.
     */
    protected $casts = [
        'amount' => 'decimal:2',
        'refund_amount' => 'decimal:2',
        'retry_count' => 'integer',
        'request_data' => 'array',
        'response_data' => 'array',
        'callback_data' => 'array',
        'initiated_at' => 'datetime',
        'completed_at' => 'datetime',
        'failed_at' => 'datetime',
        'refunded_at' => 'datetime',
        'last_retry_at' => 'datetime',
        'receipt_sent_at' => 'datetime',
    ];

    /*
    |--------------------------------------------------------------------------
    | Status Constants
    |--------------------------------------------------------------------------
    */

    const STATUS_PENDING = 'pending';
    const STATUS_PROCESSING = 'processing';
    const STATUS_SUCCESSFUL = 'successful';
    const STATUS_FAILED = 'failed';
    const STATUS_CANCELLED = 'cancelled';
    const STATUS_REFUNDED = 'refunded';
    const STATUS_TIMEOUT = 'timeout';

    /*
    |--------------------------------------------------------------------------
    | Payment Method Constants
    |--------------------------------------------------------------------------
    */

    const METHOD_MTN_MOMO = 'mtn_momo';

    /*
    |--------------------------------------------------------------------------
    | Relationships
    |--------------------------------------------------------------------------
    */

    /**
     * Get the application for this payment.
     */
    public function application()
    {
        return $this->belongsTo(Application::class, 'application_id');
    }

    /**
     * Get the programme for this payment.
     */
    public function programme()
    {
        return $this->belongsTo(Programme::class, 'programme_id');
    }

    /**
     * Get the user who made the payment.
     */
    public function user()
    {
        return $this->belongsTo(\App\Models\User::class, 'user_id');
    }

    /**
     * Get the user who processed the refund.
     */
    public function refundProcessor()
    {
        return $this->belongsTo(\App\Models\User::class, 'refunded_by');
    }

    /*
    |--------------------------------------------------------------------------
    | Scopes
    |--------------------------------------------------------------------------
    */

    /**
     * Scope to get pending payments.
     */
    public function scopePending($query)
    {
        return $query->where('status', self::STATUS_PENDING);
    }

    /**
     * Scope to get successful payments.
     */
    public function scopeSuccessful($query)
    {
        return $query->where('status', self::STATUS_SUCCESSFUL);
    }

    /**
     * Scope to get failed payments.
     */
    public function scopeFailed($query)
    {
        return $query->where('status', self::STATUS_FAILED);
    }

    /**
     * Scope to get payments for a specific application.
     */
    public function scopeForApplication($query, $applicationId)
    {
        return $query->where('application_id', $applicationId);
    }

    /**
     * Scope to get payments for a specific programme.
     */
    public function scopeForProgramme($query, $programmeId)
    {
        return $query->where('programme_id', $programmeId);
    }

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

    /*
    |--------------------------------------------------------------------------
    | Accessors & Mutators
    |--------------------------------------------------------------------------
    */

    /**
     * Get the status label.
     */
    public function getStatusLabelAttribute(): string
    {
        return match($this->status) {
            self::STATUS_PENDING => 'Pending',
            self::STATUS_PROCESSING => 'Processing',
            self::STATUS_SUCCESSFUL => 'Successful',
            self::STATUS_FAILED => 'Failed',
            self::STATUS_CANCELLED => 'Cancelled',
            self::STATUS_REFUNDED => 'Refunded',
            self::STATUS_TIMEOUT => 'Timeout',
            default => ucfirst($this->status),
        };
    }

    /**
     * Get the status color for badges.
     */
    public function getStatusColorAttribute(): string
    {
        return match($this->status) {
            self::STATUS_PENDING => 'yellow',
            self::STATUS_PROCESSING => 'blue',
            self::STATUS_SUCCESSFUL => 'green',
            self::STATUS_FAILED => 'red',
            self::STATUS_CANCELLED => 'gray',
            self::STATUS_REFUNDED => 'purple',
            self::STATUS_TIMEOUT => 'orange',
            default => 'gray',
        };
    }

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

    /*
    |--------------------------------------------------------------------------
    | Helper Methods
    |--------------------------------------------------------------------------
    */

    /**
     * Check if payment is pending.
     */
    public function isPending(): bool
    {
        return $this->status === self::STATUS_PENDING;
    }

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

    /**
     * Check if payment is failed.
     */
    public function isFailed(): bool
    {
        return $this->status === self::STATUS_FAILED;
    }

    /**
     * Check if payment can be retried.
     */
    public function canBeRetried(): bool
    {
        return in_array($this->status, [self::STATUS_FAILED, self::STATUS_TIMEOUT])
            && $this->retry_count < 3;
    }

    /**
     * Check if payment can be refunded.
     */
    public function canBeRefunded(): bool
    {
        return $this->status === self::STATUS_SUCCESSFUL;
    }

    /**
     * Mark as processing.
     */
    public function markAsProcessing(): bool
    {
        return $this->update([
            'status' => self::STATUS_PROCESSING,
            'initiated_at' => now(),
        ]);
    }

    /**
     * Mark as successful.
     */
    public function markAsSuccessful(string $transactionId, array $responseData = []): bool
    {
        return $this->update([
            'status' => self::STATUS_SUCCESSFUL,
            'transaction_id' => $transactionId,
            'completed_at' => now(),
            'response_data' => $responseData,
        ]);
    }

    /**
     * Mark as failed.
     */
    public function markAsFailed(string $errorCode, string $errorMessage): bool
    {
        return $this->update([
            'status' => self::STATUS_FAILED,
            'error_code' => $errorCode,
            'error_message' => $errorMessage,
            'failed_at' => now(),
        ]);
    }

    /**
     * Record retry attempt.
     */
    public function recordRetry(string $reason): bool
    {
        return $this->update([
            'retry_count' => $this->retry_count + 1,
            'last_retry_at' => now(),
            'retry_reason' => $reason,
            'status' => self::STATUS_PENDING,
        ]);
    }

    /**
     * Process refund.
     */
    public function processRefund(int $refundedBy, string $reason, ?float $amount = null): bool
    {
        return $this->update([
            'status' => self::STATUS_REFUNDED,
            'refund_amount' => $amount ?? $this->amount,
            'refund_reason' => $reason,
            'refunded_by' => $refundedBy,
            'refunded_at' => now(),
        ]);
    }

    /**
     * Generate receipt number.
     */
    public function generateReceiptNumber(): string
    {
        $receiptNumber = 'RCT-' . str_pad($this->id, 6, '0', STR_PAD_LEFT) . '-' . date('Ymd');

        $this->update(['receipt_number' => $receiptNumber]);

        return $receiptNumber;
    }
}
