<?php

namespace App\Models;

use App\Enums\TenantAnnouncementAudience;
use App\Enums\TenantAnnouncementSegment;
use App\Enums\TenantAnnouncementStatus;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Support\Carbon;

/**
 * @property array<int, string>|null $segments
 */
class TenantAnnouncement extends Model
{
    /** @use HasFactory<\Database\Factories\TenantAnnouncementFactory> */
    use HasFactory;

    protected $fillable = [
        'title',
        'body',
        'cta_label',
        'cta_url',
        'status',
        'audience',
        'segments',
        'starts_at',
        'ends_at',
        'email_enabled',
        'created_by',
        'updated_by',
    ];

    protected function casts(): array
    {
        return [
            'status' => TenantAnnouncementStatus::class,
            'audience' => TenantAnnouncementAudience::class,
            'segments' => 'array',
            'email_enabled' => 'boolean',
            'starts_at' => 'datetime',
            'ends_at' => 'datetime',
        ];
    }

    public function tenants(): BelongsToMany
    {
        return $this->belongsToMany(Tenant::class, 'tenant_announcement_targets')
            ->withTimestamps();
    }

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

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

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

    public function scopeActive(Builder $query): void
    {
        $query->where('status', TenantAnnouncementStatus::ACTIVE->value)
            ->where(function (Builder $builder) {
                $builder->whereNull('starts_at')
                    ->orWhere('starts_at', '<=', Carbon::now());
            })
            ->where(function (Builder $builder) {
                $builder->whereNull('ends_at')
                    ->orWhere('ends_at', '>', Carbon::now());
            });
    }

    /**
     * @param  array<int, TenantAnnouncementSegment|string>  $segments
     */
    public function matchesSegments(Tenant $tenant, array $segments): bool
    {
        if ($segments === []) {
            return true;
        }

        foreach ($segments as $segment) {
            $normalized = $segment instanceof TenantAnnouncementSegment
                ? $segment
                : TenantAnnouncementSegment::tryFrom((string) $segment);

            if (! $normalized) {
                continue;
            }

            if (! $this->matchesSegment($tenant, $normalized)) {
                return false;
            }
        }

        return true;
    }

    private function matchesSegment(Tenant $tenant, TenantAnnouncementSegment $segment): bool
    {
        return match ($segment) {
            TenantAnnouncementSegment::ACTIVE_PACKAGE => $tenant->activeResellerPackage()->exists(),
            TenantAnnouncementSegment::ACTIVE_STATUS => (bool) $tenant->is_active
                && ! (bool) $tenant->is_suspended
                && $tenant->pending_deletion_at === null
                && $tenant->anonymized_at === null,
        };
    }
}
