<?php

namespace App\Models;

// use Illuminate\Contracts\Auth\MustVerifyEmail;
use Filament\Models\Contracts\FilamentUser;
use Filament\Models\Contracts\HasName;
use Filament\Models\Contracts\HasTenants;
use Filament\Panel;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasOne;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Support\Collection;
use Laravel\Sanctum\HasApiTokens;
use Spatie\Permission\Traits\HasRoles;
use App\Models\ProfileField;
use App\Models\AssociationProfileFieldSetting;
use App\Models\MemberProfileValue;

class User extends Authenticatable implements FilamentUser, HasTenants, HasName
{
    /** @use HasFactory<\Database\Factories\UserFactory> */
    use HasFactory, Notifiable, HasRoles, HasApiTokens;

    public function canAccessPanel(Panel $panel): bool
    {
        if ($panel->getId() === 'system') {
            return $this->hasRole('Super Admin');
        }

        // For association panel, check if user has admin role in ANY association
        return $this->hasAdminRoleInAnyAssociation();
    }

    public function getTenants(Panel $panel): Collection
    {
        // Only return associations where user has admin role
        return $this->associations->filter(function ($association) {
            return $this->hasAdminRoleInAssociation($association);
        });
    }

    public function canAccessTenant(Model $tenant): bool
    {
        // Check if user belongs to association AND has admin role
        return $this->hasAdminRoleInAssociation($tenant);
    }

    /**
     * Check if user has admin role in any association
     */
    public function hasAdminRoleInAnyAssociation(): bool
    {
        foreach ($this->associations as $association) {
            if ($this->hasAdminRoleInAssociation($association)) {
                return true;
            }
        }
        return false;
    }

    /**
     * Check if user has admin role in specific association
     */
    public function hasAdminRoleInAssociation($association): bool
    {
        $pivot = $this->associations()->where('associations.id', $association->id)->first()?->pivot;

        if (!$pivot) {
            return false;
        }

        // NEW: Check if role_id exists (dynamic role system)
        if ($pivot->role_id) {
            $role = AssociationRole::find($pivot->role_id);
            return $role && $role->can_access_admin_panel;
        }

        // FALLBACK: Legacy string-based role check for backward compatibility
        $adminRoles = ['Executive', 'Admin', 'President', 'Vice President', 'Secretary', 'Treasurer'];
        return in_array($pivot->role, $adminRoles);
    }

    /**
     * Get the role object for a specific association
     */
    public function getRoleInAssociation($association): ?AssociationRole
    {
        $pivot = $this->associations()->where('associations.id', $association->id)->first()?->pivot;

        if (!$pivot || !$pivot->role_id) {
            return null;
        }

        return AssociationRole::find($pivot->role_id);
    }

    /**
     * The attributes that are mass assignable.
     *
     * @var list<string>
     */
    protected $fillable = [
        'uuid',
        'firstname',
        'middlename',
        'surname',
        'nickname',
        'email',
        'phone',
        'phone_alt',
        'date_of_birth',
        'gender',
        'profile_photo_path',
        'cover_photo_path', // Added explicit column
        'password',
        'email_verified_at',
        'status',
        'is_deceased',
        'date_of_death',
        'last_login_at',
        'profile_complete_percentage',
        'onboarding_started_at',
        'onboarding_completed_at',
        'last_association_context',
        'is_onboarding_force_redirect',
    ];

    /**
     * The attributes that should be hidden for serialization.
     *
     * @var list<string>
     */
    protected $hidden = [
        'password',
        'remember_token',
    ];

    /**
     * Get the attributes that should be cast.
     *
     * @return array<string, string>
     */
    protected function casts(): array
    {
        return [
            'email_verified_at' => 'datetime',
            'password' => 'hashed',
            'date_of_birth' => 'date',
            'date_of_death' => 'date',
            'is_deceased' => 'boolean',
            'last_login_at' => 'datetime',
            'onboarding_started_at' => 'datetime',
            'onboarding_completed_at' => 'datetime',
            'is_onboarding_force_redirect' => 'boolean',
            'profile_complete_percentage' => 'integer',
        ];
    }

    public function getFilamentName(): string
    {
        return "{$this->firstname} {$this->surname}";
    }

    /**
     * Get the user's full name.
     */
    public function getFullNameAttribute(): string
    {
        return "{$this->firstname} {$this->middlename} {$this->surname}";
    }

    /**
     * Get the user's name (compatibility).
     */
    public function getNameAttribute(): string
    {
        return "{$this->firstname} {$this->surname}";
    }

    /**
     * Get the user's associations.
     */
    public function associations()
    {
        return $this->belongsToMany(Association::class)
            ->withPivot([
                'role',
                'role_id',
                'membership_number',
                'membership_tier',
                'status',
                'joined_at',
                'approved_at',
                'exited_at',
                'emergency_contact_name',
                'emergency_contact_phone',
                'emergency_contact_relationship',
                'referred_by'
            ])
            ->withTimestamps();
    }

    public function onboardingState(): HasOne
    {
        return $this->hasOne(OnboardingState::class);
    }

    public function onboardingStates(): HasMany
    {
        return $this->hasMany(OnboardingState::class);
    }

    public function notifications(): HasMany
    {
        return $this->hasMany(Notification::class);
    }

    public function ownedEvents()
    {
        return $this->hasMany(Event::class, 'user_id');
    }

    public function eventRegistrations()
    {
        return $this->hasMany(EventAttendee::class);
    }

    public function payments()
    {
        return $this->hasMany(Payment::class);
    }

    public function profileFieldValues()
    {
        return $this->hasMany(MemberProfileValue::class);
    }

    public function workProfile()
    {
        return $this->hasOne(WorkProfile::class);
    }

    public function financialAssignments()
    {
        return $this->hasMany(FinancialAssignment::class);
    }

    public function electionCandidacies()
    {
        return $this->hasMany(ElectionCandidate::class);
    }

    public function electionVotes()
    {
        return $this->hasMany(ElectionVote::class, 'voter_id');
    }

    public function isProfileComplete(): bool
    {
        return !is_null($this->onboarding_completed_at);
    }

    public function calculateProfileCompletion(): int
    {
        $associationId = $this->last_association_context ?? $this->associations->first()?->id;

        if (!$associationId) {
            return $this->profile_complete_percentage;
        }

        // 1. Get All Enabled Fields (Global + Association Specific)
        $globalFields = ProfileField::whereNull('association_id')
            ->where('is_visible', true)
            ->get();

        $assocFields = ProfileField::where('association_id', $associationId)
            ->where('is_visible', true)
            ->get();

        $overrides = AssociationProfileFieldSetting::where('association_id', $associationId)
            ->get()
            ->keyBy('profile_field_id');

        $allFields = $globalFields->merge($assocFields);

        $enabledFields = $allFields->filter(function ($field) use ($overrides) {
            $override = $overrides->get($field->id);
            return $override ? $override->is_enabled : true;
        });

        $totalFieldsCount = $enabledFields->count();
        if ($totalFieldsCount === 0) {
            $this->update(['profile_complete_percentage' => 100]);
            return 100;
        }

        // 2. Count Filled Fields
        $filledFieldsCount = MemberProfileValue::where('user_id', $this->id)
            ->where('association_id', $associationId)
            ->whereIn('profile_field_id', $enabledFields->pluck('id'))
            ->whereNotNull('value')
            ->where('value', '!=', '')
            ->count();

        $percentage = (int) round(($filledFieldsCount / $totalFieldsCount) * 100);

        $this->update(['profile_complete_percentage' => $percentage]);

        return $percentage;
    }

    public function getProfileCompletionPercentage(): int
    {
        return $this->profile_complete_percentage;
    }

    /**
     * Get membership status for a specific association
     */
    public function getMembershipStatus(int $associationId): string
    {
        // Check if association requires paid membership
        $association = Association::find($associationId);

        if (!$association || $association->membership_mode !== 'paid') {
            return 'active'; // Free or invite-only associations don't require payment
        }

        $latestAssignment = $this->financialAssignments()
            ->where('association_id', $associationId)
            ->whereHas('financialItem', function($q) {
                $q->where('type', 'membership_dues');
            })
            ->latest('due_date')
            ->first();

        if (!$latestAssignment) {
            return 'active'; // No dues assigned yet (grace for new members)
        }

        if (in_array($latestAssignment->status, ['paid', 'waived'])) {
            return 'active';
        }

        $dueDate = $latestAssignment->due_date;
        $gracePeriod = $latestAssignment->financialItem->grace_period_days ?? 0;
        $gracePeriodEnd = $dueDate->copy()->addDays($gracePeriod);

        if (now()->lt($dueDate)) {
            return 'active'; // Not due yet
        }

        if (now()->between($dueDate, $gracePeriodEnd)) {
            return 'grace_period'; // In grace period
        }

        return 'suspended'; // Overdue, grace expired
    }

    /**
     * Check if user has active subscription in association
     */
    public function hasActiveSubscription(int $associationId): bool
    {
        return in_array(
            $this->getMembershipStatus($associationId),
            ['active', 'grace_period']
        );
    }

    /**
     * Get the latest membership assignment for an association
     */
    public function getLatestMembershipAssignment(int $associationId): ?FinancialAssignment
    {
        return $this->financialAssignments()
            ->where('association_id', $associationId)
            ->whereHas('financialItem', function($q) {
                $q->where('type', 'membership_dues');
            })
            ->latest('due_date')
            ->first();
    }

    /**
     * Accessor for Avatar URL
     */
    public function getAvatarAttribute()
    {
        return $this->profile_photo_path ? asset('storage/' . $this->profile_photo_path) : null;
    }

    /**
     * Accessor for Cover Photo URL
     */
    public function getCoverUrlAttribute()
    {
        // 1. Check if user has a custom cover photo uploaded
        // Uses the explicit column in users table
        if ($this->cover_photo_path) {
            return asset('storage/' . $this->cover_photo_path);
        }

        // 2. Fallback to default static asset
        return asset('images/cover_default.jpg');
    }

    protected $appends = ['full_name', 'name', 'avatar', 'cover_url'];
}
