<?php

namespace App\Models;

use App\Support\JobText;
use Database\Factories\ImportedJobFactory;
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\HasMany;

class ImportedJob extends Model
{
    /** @use HasFactory<ImportedJobFactory> */
    use HasFactory;

    public const STATUS_ACTIVE = 'active';

    public const STATUS_INACTIVE = 'inactive';

    public const STATUS_EXPIRED = 'expired';

    /**
     * The attributes that are mass assignable.
     *
     * @var list<string>
     */
    protected $fillable = [
        'job_source_id',
        'external_id',
        'title',
        'company',
        'category',
        'employment_type',
        'experience_level',
        'location_type',
        'country_code',
        'timezone',
        'salary_currency',
        'salary_min',
        'salary_max',
        'summary',
        'description',
        'skills',
        'tags',
        'source_url',
        'apply_url',
        'source_attribution',
        'status',
        'is_featured',
        'posted_at',
        'expires_at',
        'last_seen_at',
        'raw_payload',
    ];

    /**
     * @return BelongsTo<JobSource, $this>
     */
    public function source(): BelongsTo
    {
        return $this->belongsTo(JobSource::class, 'job_source_id');
    }

    /**
     * @return HasMany<SavedJob, $this>
     */
    public function savedJobs(): HasMany
    {
        return $this->hasMany(SavedJob::class);
    }

    /**
     * @return HasMany<Application, $this>
     */
    public function applications(): HasMany
    {
        return $this->hasMany(Application::class);
    }

    /**
     * @return HasMany<JobInterest, $this>
     */
    public function interests(): HasMany
    {
        return $this->hasMany(JobInterest::class);
    }

    /**
     * @return HasMany<JobAiAssistance, $this>
     */
    public function aiAssistances(): HasMany
    {
        return $this->hasMany(JobAiAssistance::class);
    }

    /**
     * @return HasMany<JobNote, $this>
     */
    public function notes(): HasMany
    {
        return $this->hasMany(JobNote::class);
    }

    /**
     * @param  Builder<ImportedJob>  $query
     * @return Builder<ImportedJob>
     */
    public function scopeActive(Builder $query): Builder
    {
        return $query
            ->where('status', self::STATUS_ACTIVE)
            ->where(function (Builder $query): void {
                $query->whereNull('expires_at')->orWhere('expires_at', '>', now());
            });
    }

    public function attribution(): string
    {
        return $this->source_attribution
            ?: $this->source?->attribution_text
            ?: $this->source?->name
            ?: 'Original job source';
    }

    public function displaySummary(int $limit = 260): string
    {
        return JobText::excerpt($this->summary ?: $this->description, $limit);
    }

    public function displayDescription(): string
    {
        return JobText::clean($this->description ?: $this->summary);
    }

    /**
     * @return array<int, string>
     */
    public function displayDescriptionParagraphs(): array
    {
        return JobText::paragraphs($this->description ?: $this->summary);
    }

    public function salaryLabel(): ?string
    {
        $salaryMin = $this->salary_min;
        $salaryMax = $this->salary_max;
        $currency = strtoupper($this->salary_currency ?: 'USD');

        if ($salaryMin === null && $salaryMax === null) {
            $parsed = JobText::salaryRange($this->description ?: $this->summary);
            $salaryMin = $parsed['min'];
            $salaryMax = $parsed['max'];
            $currency = strtoupper($parsed['currency'] ?: $currency);
        }

        if ($salaryMin === null && $salaryMax === null) {
            return null;
        }

        $prefix = $currency === 'USD' ? '$' : $currency.' ';
        $min = $salaryMin !== null ? $prefix.number_format($salaryMin) : null;
        $max = $salaryMax !== null ? $prefix.number_format($salaryMax) : null;

        return match (true) {
            $min !== null && $max !== null => "{$min} - {$max}",
            $min !== null => "From {$min}",
            default => "Up to {$max}",
        };
    }

    /**
     * Get the attributes that should be cast.
     *
     * @return array<string, string>
     */
    protected function casts(): array
    {
        return [
            'salary_min' => 'integer',
            'salary_max' => 'integer',
            'skills' => 'array',
            'tags' => 'array',
            'is_featured' => 'boolean',
            'posted_at' => 'datetime',
            'expires_at' => 'datetime',
            'last_seen_at' => 'datetime',
            'raw_payload' => 'array',
        ];
    }
}
