<?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\HasMany;
use Illuminate\Support\Str;

/**
 * HealthInstitution Model
 *
 * Represents a healthcare facility listing in the directory.
 * Supports multi-step registration, payment integration, and publication management.
 *
 * @property int $id
 * @property int|null $user_id
 * @property string $name
 * @property string|null $short_name
 * @property string $slug
 * @property string|null $logo
 * @property string $city
 * @property string $address
 * @property string $country
 * @property string $email
 * @property string $phone
 * @property string|null $website_url
 * @property string|null $description
 * @property array|null $services
 * @property array|null $images
 * @property array|null $videos
 * @property bool $is_published
 * @property string $listing_status
 * @property string $payment_status
 * @property \Carbon\Carbon|null $next_payment_date
 * @property \Carbon\Carbon|null $published_at
 * @property \Carbon\Carbon|null $expires_at
 * @property int $view_count
 *
 * Requirements: 1.4, 10.2, 10.3
 */
class HealthInstitution extends Model
{
    use HasFactory, SoftDeletes;

    /**
     * The attributes that are mass assignable.
     *
     * @var array<int, string>
     */
    protected $fillable = [
        'user_id',
        'name',
        'short_name',
        'slug',
        'logo',
        'city',
        'address',
        'country',
        'latitude',
        'longitude',
        'email',
        'phone',
        'website_url',
        'description',
        'services',
        'images',
        'videos',
        'is_published',
        'listing_status',
        'payment_status',
        'next_payment_date',
        'published_at',
        'expires_at',
        'view_count',
    ];

    /**
     * The attributes that should be cast.
     *
     * @var array<string, string>
     */
    protected $casts = [
        'services' => 'array',
        'images' => 'array',
        'videos' => 'array',
        'is_published' => 'boolean',
        'latitude' => 'decimal:7',
        'longitude' => 'decimal:7',
        'next_payment_date' => 'datetime',
        'published_at' => 'datetime',
        'expires_at' => 'datetime',
        'view_count' => 'integer',
    ];

    /**
     * The attributes that should be hidden for serialization.
     *
     * @var array<int, string>
     */
    protected $hidden = [
        // No sensitive data to hide
    ];

    /**
     * The model's default values for attributes.
     *
     * @var array
     */
    protected $attributes = [
        'is_published' => false,
        'listing_status' => 'draft',
        'payment_status' => 'pending',
        'country' => 'South Sudan',
        'view_count' => 0,
    ];

    // =========================================================================
    // RELATIONSHIPS
    // =========================================================================

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

    /**
     * Get all payments for this institution.
     */
    public function payments(): HasMany
    {
        return $this->hasMany(InstitutionPayment::class, 'health_institution_id');
    }

    /**
     * Get the latest successful payment.
     */
    public function latestPayment()
    {
        return $this->payments()
            ->where('status', 'successful')
            ->latest('paid_at')
            ->first();
    }

    // =========================================================================
    // SCOPES
    // =========================================================================

    /**
     * Scope a query to only include published institutions.
     */
    public function scopePublished($query)
    {
        return $query->where('is_published', true)
            ->where('listing_status', 'published');
    }

    /**
     * Scope a query to filter by city (exact match, case-insensitive).
     */
    public function scopeByCity($query, string $city)
    {
        return $query->where('city', $city);
    }

    /**
     * Scope a query to filter by country.
     */
    public function scopeByCountry($query, string $country)
    {
        return $query->where('country', $country);
    }

    /**
     * Scope a query to filter by listing status.
     */
    public function scopeByStatus($query, string $status)
    {
        return $query->where('listing_status', $status);
    }

    /**
     * Scope a query to filter by payment status.
     */
    public function scopeByPaymentStatus($query, string $status)
    {
        return $query->where('payment_status', $status);
    }

    /**
     * Scope a query to search across multiple fields.
     * Services are stored as JSON so we use whereJsonContains for that column.
     */
    public function scopeSearch($query, string $term)
    {
        return $query->where(function ($q) use ($term) {
            $q->where('name', 'like', "%{$term}%")
                ->orWhere('short_name', 'like', "%{$term}%")
                ->orWhere('city', 'like', "%{$term}%")
                ->orWhere('description', 'like', "%{$term}%")
                ->orWhereJsonContains('services', $term);
        });
    }

    /**
     * Scope a query to only include active listings.
     */
    public function scopeActive($query)
    {
        return $query->whereIn('listing_status', ['published', 'pending_payment'])
            ->where(function ($q) {
                $q->whereNull('expires_at')
                    ->orWhere('expires_at', '>', now());
            });
    }

    /**
     * Scope a query to only include expired listings.
     */
    public function scopeExpired($query)
    {
        return $query->where('expires_at', '<', now());
    }

    // =========================================================================
    // ACCESSORS & MUTATORS
    // =========================================================================

    /**
     * Set the slug attribute.
     */
    public function setSlugAttribute($value)
    {
        $this->attributes['slug'] = $value ?? Str::slug($this->attributes['name'] ?? '');
    }

    /**
     * Get the logo URL.
     */
    public function getLogoUrlAttribute(): string
    {
        if ($this->logo) {
            return asset('storage/' . $this->logo);
        }
        return asset('images/default-institution.png');
    }

    /**
     * Get the services as a formatted string.
     */
    public function getServicesListAttribute(): string
    {
        if (empty($this->services) || !is_array($this->services)) {
            return '';
        }
        return implode(', ', $this->services);
    }

    /**
     * Get the status badge color.
     */
    public function getStatusBadgeColorAttribute(): string
    {
        return match ($this->listing_status) {
            'published' => 'green',
            'draft' => 'gray',
            'pending_payment' => 'yellow',
            'paused' => 'orange',
            'expired' => 'red',
            'suspended' => 'red',
            default => 'gray',
        };
    }

    /**
     * Get the payment status badge color.
     */
    public function getPaymentBadgeColorAttribute(): string
    {
        return match ($this->payment_status) {
            'paid' => 'green',
            'pending' => 'yellow',
            'overdue' => 'red',
            'exempt' => 'blue',
            default => 'gray',
        };
    }

    // =========================================================================
    // HELPER METHODS
    // =========================================================================

    /**
     * Check if the institution is publicly viewable.
     */
    public function isPubliclyViewable(): bool
    {
        return $this->is_published && $this->listing_status === 'published';
    }

    /**
     * Check if the institution requires payment.
     */
    public function requiresPayment(): bool
    {
        if ($this->payment_status === 'exempt') {
            return false;
        }

        if ($this->payment_status === 'paid' && $this->next_payment_date) {
            return $this->next_payment_date->isPast();
        }

        return $this->payment_status !== 'paid';
    }

    /**
     * Check if the institution is expired.
     */
    public function isExpired(): bool
    {
        return $this->expires_at && $this->expires_at->isPast();
    }

    /**
     * Check if the institution is owned by a specific user.
     */
    public function isOwnedBy(User $user): bool
    {
        return $this->user_id === $user->id;
    }

    /**
     * Generate a unique slug.
     */
    public static function generateUniqueSlug(string $name): string
    {
        $slug = Str::slug($name);
        $count = static::where('slug', 'like', "{$slug}%")->count();

        return $count > 0 ? "{$slug}-{$count}" : $slug;
    }

    /**
     * Publish the institution.
     */
    public function publish(): void
    {
        $this->update([
            'is_published' => true,
            'listing_status' => 'published',
            'published_at' => now(),
        ]);
    }

    /**
     * Unpublish the institution.
     */
    public function unpublish(): void
    {
        $this->update([
            'is_published' => false,
            'listing_status' => 'paused',
        ]);
    }

    /**
     * Increment view count.
     */
    public function incrementViewCount(): void
    {
        $this->increment('view_count');
    }

    /**
     * Calculate next payment date based on frequency.
     */
    public function calculateNextPaymentDate(string $frequency): \Carbon\Carbon
    {
        $now = now();

        return match ($frequency) {
            'one_time' => $now->addYears(100), // Effectively never expires
            'monthly' => $now->addMonth(),
            'quarterly' => $now->addMonths(3),
            'biannual' => $now->addMonths(6),
            'yearly' => $now->addYear(),
            default => $now->addYear(),
        };
    }

    // =========================================================================
    // STATIC METHODS
    // =========================================================================

    /**
     * Get listing status options.
     */
    public static function getListingStatuses(): array
    {
        return [
            'draft' => 'Draft',
            'pending_payment' => 'Pending Payment',
            'published' => 'Published',
            'paused' => 'Paused',
            'expired' => 'Expired',
            'suspended' => 'Suspended',
        ];
    }

    /**
     * Get payment status options.
     */
    public static function getPaymentStatuses(): array
    {
        return [
            'pending' => 'Pending',
            'paid' => 'Paid',
            'overdue' => 'Overdue',
            'exempt' => 'Exempt',
        ];
    }

    /**
     * Get common services list.
     */
    public static function getCommonServices(): array
    {
        return [
            'General Medicine',
            'Pediatrics',
            'Obstetrics & Gynecology',
            'Surgery',
            'Dental Care',
            'Eye Care',
            'Laboratory Services',
            'Radiology',
            'Pharmacy',
            'Emergency Services',
            'Maternity',
            'Mental Health',
            'Physiotherapy',
            'HIV/AIDS Care',
            'Vaccination',
            'Health Checkups',
            'Specialist Consultations',
        ];
    }
}
