<?php

namespace App\Models;

use App\Enums\AssociationType;
use App\Events\AssociationProfileCompleted;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasManyThrough;
use Illuminate\Notifications\Notifiable;
use Monzer\FilamentWorkflows\Traits\TrackWorkflowModelEvents;
use Spatie\MediaLibrary\HasMedia;
use Spatie\MediaLibrary\InteractsWithMedia;

class Association extends Model implements HasMedia
{
    use HasFactory, InteractsWithMedia, Notifiable, TrackWorkflowModelEvents;

    protected $fillable = [
        'name',
        'type',
        'license_number',
        'license_expiration_date',
        'representative_full_name',
        'representative_position',
        'phone_number',
        'phone_verified',
        'phone_verified_at',
        'secondary_phone_number',
        'email',
        'email_verified',
        'email_verified_at',

        'map_location', // Deprecated, use 'location' instead
        'city',
        'postal_code',
        'neighborhood',
        'building_number',
        'street',
        'branch_number',

        'lat',
        'lng',
        'location',

        'iban',
        'bank_name',
        'account_holder_name',

        'is_verified',
        'is_locked',

        // Media collection attributes for SpatieMediaLibraryFileUpload
        'logo',
        'authorization_letter',
        'license_certificate',
        'iban_certificate',
        'national_address_certificate',
        'governance_certificate',
        'financial_reports',
        'basic_bylaws',
    ];

    protected $casts = [
        'type' => AssociationType::class,
        'license_expiration_date' => 'date',
        'lat' => 'decimal:8',
        'lng' => 'decimal:8',
        'is_verified' => 'boolean',
        'is_locked' => 'boolean',
        'phone_verified' => 'boolean',
        'email_verified' => 'boolean',
        'phone_verified_at' => 'datetime',
        'email_verified_at' => 'datetime',
        'created_at' => 'datetime',
        'updated_at' => 'datetime',
    ];

    protected $appends = [
        'location',
        'profile_completion_percentage',
    ];

    protected static function boot()
    {
        parent::boot();

        static::saved(function ($association) {
            // Check if this is an update operation and not a new creation
            if (! $association->wasRecentlyCreated) {
                // Get the current completion percentage
                $newCompletionPercentage = $association->getProfileCompletionPercentageAttribute();

                // Get the original completion percentage before changes
                $originalCompletionPercentage = 0;

                // If we have the original model, calculate its completion percentage manually
                if ($association->getOriginal()) {
                    $originalAssociation = clone $association;
                    $originalAssociation->setRawAttributes($association->getOriginal());
                    $originalCompletionPercentage = $originalAssociation->getProfileCompletionPercentageAttribute();
                }

                // If completion changed from < 100% to 100%, fire the event
                if ($originalCompletionPercentage < 100 && $newCompletionPercentage == 100) {
                    AssociationProfileCompleted::dispatch(
                        $association,
                        $originalCompletionPercentage,
                        $newCompletionPercentage
                    );
                }
            }
        });
    }

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

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

    public function projectCharters(): HasManyThrough
    {
        return $this->hasManyThrough(ProjectCharter::class, Order::class);
    }

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

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

    public function registerMediaCollections(): void
    {
        $this->addMediaCollection('logo')->singleFile();
        $this->addMediaCollection('authorization_letter')->singleFile();
        $this->addMediaCollection('license_certificate')->singleFile();
        $this->addMediaCollection('iban_certificate')->singleFile();
        $this->addMediaCollection('national_address_certificate')->singleFile();
        $this->addMediaCollection('governance_certificate')->singleFile();
        $this->addMediaCollection('financial_reports')->singleFile();
        $this->addMediaCollection('basic_bylaws')->singleFile();
    }

    /**
     * Get the logo URL
     */
    public function getLogoUrlAttribute(): ?string
    {
        return $this->getFirstMedia('logo')?->getTemporaryUrl(Carbon::now()->addMinutes(30)) ?: null;
    }

    /**
     * Get the authorization letter URL
     */
    public function getAuthorizationLetterUrlAttribute(): ?string
    {
        return $this->getFirstMedia('authorization_letter')?->getTemporaryUrl(Carbon::now()->addMinutes(30)) ?: null;
    }

    /**
     * Get the license certificate URL
     */
    public function getLicenseCertificateUrlAttribute(): ?string
    {
        return $this->getFirstMedia('license_certificate')?->getTemporaryUrl(Carbon::now()->addMinutes(30)) ?: null;
    }

    /**
     * Get the IBAN certificate URL
     */
    public function getIbanCertificateUrlAttribute(): ?string
    {
        return $this->getFirstMedia('iban_certificate')?->getTemporaryUrl(Carbon::now()->addMinutes(30)) ?: null;
    }

    /**
     * Get the national address certificate URL
     */
    public function getNationalAddressCertificateUrlAttribute(): ?string
    {
        return $this->getFirstMedia('national_address_certificate')?->getTemporaryUrl(Carbon::now()->addMinutes(30)) ?: null;
    }

    /**
     * Get the governance certificate URL
     */
    public function getGovernanceCertificateUrlAttribute(): ?string
    {
        return $this->getFirstMedia('governance_certificate')?->getTemporaryUrl(Carbon::now()->addMinutes(30)) ?: null;
    }

    /**
     * Get the financial reports URL
     */
    public function getFinancialReportsUrlAttribute(): ?string
    {
        return $this->getFirstMedia('financial_reports')?->getTemporaryUrl(Carbon::now()->addMinutes(30)) ?: null;
    }

    /**
     * Get the basic bylaws URL
     */
    public function getBasicBylawsUrlAttribute(): ?string
    {
        return $this->getFirstMedia('basic_bylaws')?->getTemporaryUrl(Carbon::now()->addMinutes(30)) ?: null;
    }

    /**
     * Get the profile completion percentage
     */
    public function getProfileCompletionPercentageAttribute(): int
    {
        $steps = [
            'contact_info' => $this->isContactInfoCompleted(),
            'national_address' => $this->isNationalAddressCompleted(),
            'geographic_scope' => $this->isGeographicScopeCompleted(),
            'bank_details' => $this->isBankDetailsCompleted(),
            'documents' => $this->isDocumentsCompleted(),
        ];

        $completedSteps = array_filter($steps);
        $totalSteps = count($steps);

        return $totalSteps > 0 ? (int) round((count($completedSteps) / $totalSteps) * 100) : 0;
    }

    /**
     * Check if contact information is completed
     */
    public function isContactInfoCompleted(): bool
    {
        return ! is_null($this->phone_number) && ! is_null($this->email);
    }

    /**
     * Check if national address information is completed
     */
    public function isNationalAddressCompleted(): bool
    {
        return ! is_null($this->city)
            && ! is_null($this->postal_code)
            && ! is_null($this->neighborhood)
            && ! is_null($this->building_number)
            && ! is_null($this->street)
            && ! is_null($this->branch_number);
    }

    /**
     * Check if geographic scope information is completed
     */
    public function isGeographicScopeCompleted(): bool
    {
        return $this->states()->exists()
            && $this->cities()->exists()
            && $this->centers()->exists();
    }

    /**
     * Check if bank details are completed
     */
    public function isBankDetailsCompleted(): bool
    {
        return ! is_null($this->iban)
            && ! is_null($this->bank_name)
            && ! is_null($this->account_holder_name)
            && $this->hasMedia('iban_certificate');
    }

    /**
     * Check if required documents are completed
     */
    public function isDocumentsCompleted(): bool
    {
        return $this->hasMedia('authorization_letter')
            && $this->hasMedia('license_certificate')
            && $this->hasMedia('iban_certificate')
            && $this->hasMedia('national_address_certificate')
            && $this->hasMedia('governance_certificate')
            && $this->hasMedia('financial_reports')
            && $this->hasMedia('basic_bylaws');
    }

    /**
     * Get detailed completion status for each step
     */
    public function getCompletionSteps(): array
    {
        return [
            [
                'id' => 'contactInfo',
                'label' => 'معلومات التواصل',
                'completed' => $this->isContactInfoCompleted(),
            ],
            [
                'id' => 'nationalAddress',
                'label' => 'العنوان الوطني',
                'completed' => $this->isNationalAddressCompleted(),
            ],
            [
                'id' => 'geographicScope',
                'label' => 'النطاق الجغرافي',
                'completed' => $this->isGeographicScopeCompleted(),
            ],
            [
                'id' => 'bankDetails',
                'label' => 'البيانات البنكية',
                'completed' => $this->isBankDetailsCompleted(),
            ],
            [
                'id' => 'documents',
                'label' => 'مستندات',
                'completed' => $this->isDocumentsCompleted(),
            ],
        ];
    }

    /**
     * Get the logo path for backward compatibility
     */
    public function getLogoAttribute(): ?string
    {
        return $this->getFirstMedia('logo')?->getTemporaryUrl(Carbon::now()->addMinutes(30)) ?: null;
    }

    public function states(): BelongsToMany
    {
        return $this->belongsToMany(State::class);
    }

    public function cities(): BelongsToMany
    {
        return $this->belongsToMany(City::class);
    }

    public function centers(): BelongsToMany
    {
        return $this->belongsToMany(Center::class);
    }

    public function residentialGatherings(): BelongsToMany
    {
        return $this->belongsToMany(ResidentialGathering::class);
    }

    /**
     * Returns the 'lat' and 'lng' attributes as the computed 'location' attribute,
     * as a standard Google Maps style Point array with 'lat' and 'lng' attributes.
     *
     * Used by the Filament Google Maps package.
     *
     * Requires the 'location' attribute be included in this model's $fillable array.
     */
    public function getLocationAttribute(): array
    {
        return [
            'lat' => (float) $this->lat,
            'lng' => (float) $this->lng,
        ];
    }

    /**
     * Takes a Google style Point array of 'lat' and 'lng' values and assigns them to the
     * 'lat' and 'lng' attributes on this model.
     *
     * Used by the Filament Google Maps package.
     *
     * Requires the 'location' attribute be included in this model's $fillable array.
     */
    public function setLocationAttribute(?array $location): void
    {
        if (is_array($location)) {
            $this->attributes['lat'] = $location['lat'];
            $this->attributes['lng'] = $location['lng'];
            unset($this->attributes['location']);
        }
    }

    /**
     * Get the lat and lng attribute/field names used on this table
     *
     * Used by the Filament Google Maps package.
     *
     * @return string[]
     */
    public static function getLatLngAttributes(): array
    {
        return [
            'lat' => 'lat',
            'lng' => 'lng',
        ];
    }

    /**
     * Get the name of the computed location attribute
     *
     * Used by the Filament Google Maps package.
     */
    public static function getComputedLocation(): string
    {
        return 'location';
    }
}
