<?php

declare(strict_types=1);

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\SoftDeletes;

final class Transaction extends Model
{
    use SoftDeletes;

    protected $fillable = [
        'booking_id',
        'user_id',
        'property_id',
        'owner_id',
        'payment_method',
        'amount',
        'currency',
        'platform_fee',
        'owner_amount',
        'status',
        'payout_status',
        'payment_proof',
        'payment_notes',
        'verification_notes',
        'verified_by',
        'verified_at',
        'rejected_reason',
        'dispute_reason',
        'disputed_by',
        'disputed_at',
        'dispute_resolution',
        'dispute_resolved_by',
        'dispute_resolved_at',
        'paypal_email',
        'paypal_transaction_id',
        'paystack_reference',
        'crypto_type',
        'crypto_wallet_address',
        'crypto_network',
        'crypto_transaction_hash',
        'bank_transaction_reference',
        'refund_amount',
        'refund_reason',
        'refunded_at',
        'metadata',
    ];

    protected function casts(): array
    {
        return [
            'amount' => 'decimal:2',
            'platform_fee' => 'decimal:2',
            'owner_amount' => 'decimal:2',
            'refund_amount' => 'decimal:2',
            'verified_at' => 'datetime',
            'disputed_at' => 'datetime',
            'dispute_resolved_at' => 'datetime',
            'refunded_at' => 'datetime',
            'metadata' => 'array',
        ];
    }

    // Relationships
    public function booking(): BelongsTo
    {
        return $this->belongsTo(Booking::class);
    }

    public function user(): BelongsTo
    {
        return $this->belongsTo(User::class);
    }

    public function owner(): BelongsTo
    {
        return $this->belongsTo(User::class, 'owner_id');
    }

    public function property(): BelongsTo
    {
        return $this->belongsTo(Property::class);
    }

    public function verifiedBy(): BelongsTo
    {
        return $this->belongsTo(User::class, 'verified_by');
    }

    public function disputedBy(): BelongsTo
    {
        return $this->belongsTo(User::class, 'disputed_by');
    }

    public function disputeResolvedBy(): BelongsTo
    {
        return $this->belongsTo(User::class, 'dispute_resolved_by');
    }

    // Scopes
    public function scopePending($query)
    {
        return $query->where('status', 'pending_payment');
    }

    public function scopeVerified($query)
    {
        return $query->where('status', 'verified');
    }

    public function scopeNeedsVerification($query)
    {
        return $query->where('status', 'payment_verification');
    }

    public function scopeDisputed($query)
    {
        return $query->where('status', 'disputed');
    }

    public function scopeRefunded($query)
    {
        return $query->whereIn('status', ['refunded', 'partially_refunded']);
    }

    public function scopeByPaymentMethod($query, string $method)
    {
        return $query->where('payment_method', $method);
    }

    public function scopeCompleted($query)
    {
        return $query->where('status', 'completed');
    }

    // Status Check Methods
    public function isPending(): bool
    {
        return $this->status === 'pending_payment';
    }

    public function isVerified(): bool
    {
        return $this->status === 'verified';
    }

    public function isRejected(): bool
    {
        return $this->status === 'rejected';
    }

    public function isDisputed(): bool
    {
        return $this->status === 'disputed';
    }

    public function isDisputeResolved(): bool
    {
        return $this->status === 'dispute_resolved';
    }

    public function needsVerification(): bool
    {
        return $this->status === 'payment_verification';
    }

    public function isCompleted(): bool
    {
        return $this->status === 'completed';
    }

    public function isRefunded(): bool
    {
        return in_array($this->status, ['refunded', 'partially_refunded']);
    }

    // Action Check Methods
    public function canRefund(): bool
    {
        return in_array($this->status, ['verified', 'completed']);
    }

    public function canResubmit(): bool
    {
        return $this->status === 'rejected';
    }

    public function canDispute(): bool
    {
        return in_array($this->status, ['verified', 'rejected']);
    }

    public function hasProofOfPayment(): bool
    {
        return ! empty($this->payment_proof);
    }

    // Fee Calculation Methods
    public function calculatePlatformFee(float $percentage = 10.0): float
    {
        return round($this->amount * ($percentage / 100), 2);
    }

    public function calculateOwnerAmount(float $percentage = 10.0): float
    {
        return round($this->amount - $this->calculatePlatformFee($percentage), 2);
    }

    // Status Update Methods
    public function markAsVerified(int $verifierId, ?string $notes = null): bool
    {
        $this->status = 'verified';
        $this->verified_by = $verifierId;
        $this->verified_at = now();
        $this->verification_notes = $notes;

        return $this->save();
    }

    public function markAsRejected(int $verifierId, string $reason): bool
    {
        $this->status = 'rejected';
        $this->verified_by = $verifierId;
        $this->rejected_reason = $reason;

        return $this->save();
    }

    public function markAsCompleted(): bool
    {
        $this->status = 'completed';

        return $this->save();
    }

    public function markAsDisputed(int $disputerId, string $reason): bool
    {
        $this->status = 'disputed';
        $this->disputed_by = $disputerId;
        $this->disputed_at = now();
        $this->dispute_reason = $reason;

        return $this->save();
    }

    public function resolveDispute(int $adminId, string $outcome, string $resolution): bool
    {
        $this->status = $outcome; // 'verified', 'rejected', or 'refunded'
        $this->dispute_resolved_by = $adminId;
        $this->dispute_resolved_at = now();
        $this->dispute_resolution = $resolution;

        return $this->save();
    }
}
