<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Support\Str;

class Member extends Model
{
    use HasFactory, SoftDeletes;

    /**
     * The attributes that are mass assignable.
     *
     * @var array<int, string>
     */
    protected $fillable = [
        'membership_code',
        'user_id',
        'status',
        'approval_date',
        'approved_by',
        'created_by',
        'membership_start_date',
        'membership_end_date',
        'renewal_type',
        'auto_renewal_enabled',
        'last_renewal_date',
        'next_renewal_date',
        'notes',
    ];

    /**
     * The attributes that should be cast.
     *
     * @var array<string, string>
     */
    protected $casts = [
        'approval_date' => 'date',
        'membership_start_date' => 'date',
        'membership_end_date' => 'date',
        'last_renewal_date' => 'datetime',
        'next_renewal_date' => 'datetime',
        'auto_renewal_enabled' => 'boolean',
        'created_at' => 'datetime',
        'updated_at' => 'datetime',
        'deleted_at' => 'datetime',
    ];

    /**
     * The attributes that should be appended.
     *
     * @var array<int, string>
     */
    protected $appends = ['full_name', 'email', 'primary_category', 'first_name', 'last_name', 'phone', 'initials'];

    /**
     * Get the user that owns the member.
     */
    public function user(): BelongsTo
    {
        return $this->belongsTo(User::class);
    }

    /**
     * Get the user who approved the member.
     */
    public function approver(): BelongsTo
    {
        return $this->belongsTo(User::class, 'approved_by');
    }

    /**
     * Get the user who created the member.
     */
    public function creator(): BelongsTo
    {
        return $this->belongsTo(User::class, 'created_by');
    }

    /**
     * Get the membership categories for the member.
     */
    public function membershipCategories(): BelongsToMany
    {
        return $this->belongsToMany(MembershipCategory::class, 'member_membership_category')
            ->withPivot('assigned_date', 'assigned_by', 'is_primary')
            ->withTimestamps();
    }

    /**
     * Get the contributions for the member.
     */
    public function contributions(): HasMany
    {
        return $this->hasMany(Contribution::class);
    }

    /**
     * Get the loan applications for the member.
     */
    public function loanApplications(): HasMany
    {
        return $this->hasMany(LoanApplication::class);
    }

    /**
     * Get the active loans for the member.
     */
    public function activeLoans(): HasMany
    {
        return $this->hasMany(LoanApplication::class)->where('status', 'active');
    }

    /**
     * Get the transactions for the member.
     */
    public function transactions(): HasMany
    {
        return $this->hasMany(MembershipTransaction::class);
    }

    /**
     * Get the activity logs for the member.
     */
    public function activityLogs(): HasMany
    {
        return $this->hasMany(MemberActivityLog::class);
    }

    /**
     * Get the membership certificates for the member.
     */
    public function certificates(): HasMany
    {
        return $this->hasMany(MembershipCertificate::class);
    }

    /**
     * Get the membership renewals for the member.
     */
    public function renewals(): HasMany
    {
        return $this->hasMany(MembershipRenewal::class);
    }

    /**
     * Get the current active certificate for the member.
     */
    public function currentCertificate(): ?MembershipCertificate
    {
        return $this->certificates()->where('is_current', true)->latest()->first();
    }

    /**
     * Get the member's full name.
     */
    public function getFullNameAttribute(): string
    {
        return $this->user?->name ?? 'N/A';
    }

    /**
     * Get the member's first name.
     */
    public function getFirstNameAttribute(): string
    {
        $parts = explode(' ', $this->user?->name ?? '');
        return $parts[0] ?? 'N/A';
    }

    /**
     * Get the member's last name.
     */
    public function getLastNameAttribute(): string
    {
        $parts = explode(' ', $this->user?->name ?? '');
        return count($parts) > 1 ? implode(' ', array_slice($parts, 1)) : '';
    }

    /**
     * Get the member's email.
     */
    public function getEmailAttribute(): string
    {
        return $this->user?->email ?? 'N/A';
    }

    /**
     * Get the member's phone.
     */
    public function getPhoneAttribute(): ?string
    {
        return $this->user?->phone;
    }

    /**
     * Get the member's initials.
     */
    public function getInitialsAttribute(): string
    {
        return $this->user?->initials ?? 'M';
    }

    /**
     * Get the member's primary category.
     */
    public function getPrimaryCategoryAttribute(): ?MembershipCategory
    {
        return $this->membershipCategories()
            ->wherePivot('is_primary', true)
            ->first() ?? $this->membershipCategories()->first();
    }

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

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

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

    /**
     * Check if member is active.
     */
    public function isActive(): bool
    {
        return $this->status === 'active';
    }

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

    /**
     * Check if member is suspended.
     */
    public function isSuspended(): bool
    {
        return $this->status === 'suspended';
    }

    /**
     * Generate a unique membership code.
     */
    public static function generateMembershipCode(): string
    {
        do {
            $code = 'MEM-' . strtoupper(Str::random(8));
        } while (self::where('membership_code', $code)->exists());

        return $code;
    }

    /**
     * Get total contribution balance.
     */
    public function getContributionBalance(): float
    {
        return $this->contributions()
            ->where('status', 'paid')
            ->sum('amount');
    }

    /**
     * Get outstanding loan balance.
     */
    public function getOutstandingLoanBalance(): float
    {
        return $this->activeLoans()->sum('outstanding_balance');
    }

    /**
     * Get pending contributions.
     */
    public function getPendingContributions(): HasMany
    {
        return $this->contributions()->whereIn('status', ['pending', 'overdue']);
    }

    /**
     * Check if member can apply for loan.
     */
    public function canApplyForLoan(LoanProduct $product): bool
    {
        // Check membership duration
        if ($product->min_membership_months > 0) {
            $membershipDuration = $this->membership_start_date?->diffInMonths(now()) ?? 0;
            if ($membershipDuration < $product->min_membership_months) {
                return false;
            }
        }

        // Check contribution balance
        if ($product->min_contribution_balance > 0) {
            if ($this->getContributionBalance() < $product->min_contribution_balance) {
                return false;
            }
        }

        // Check eligible categories
        if ($product->eligible_categories) {
            $eligibleCategories = json_decode($product->eligible_categories, true);
            $memberCategories = $this->membershipCategories()->pluck('membership_categories.id')->toArray();
            if (!empty($eligibleCategories) && empty(array_intersect($eligibleCategories, $memberCategories))) {
                return false;
            }
        }

        return true;
    }
}
