<?php

namespace App\Models;

use App\Traits\BelongsToOrg;
use App\Workflows\Traits\HasWorkflow;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasOne;
use Illuminate\Support\Facades\Auth;
use Spatie\Activitylog\LogOptions;
use Spatie\Activitylog\Traits\LogsActivity;
use Spatie\MediaLibrary\HasMedia;
use Spatie\MediaLibrary\InteractsWithMedia;
use Spatie\MediaLibrary\MediaCollections\Models\Media;

class Order extends Model implements HasMedia
{
    use BelongsToOrg, HasWorkflow, InteractsWithMedia, LogsActivity;

    /**
     * The attributes that are mass assignable.
     *
     * @var list<string>
     */
    protected $fillable = [
        'name',
        'idea',
        'grant_area_id',
        'lat',
        'lng',
        'start_date',
        'duration_months',
        'target_group_type',
        'state_id',
        'city_id',
        'beneficiaries_count',
        'goals',
        'strengths',
        'risks',
        'declaration_checked',
        'association_id',
        'created_by',
        'org_id',
    ];

    /**
     * Get the attributes that should be cast.
     *
     * @return array<string, string>
     */
    protected function casts(): array
    {
        return [
            'start_date' => 'date',
            'declaration_checked' => 'boolean',
            'duration_months' => 'integer',
            'beneficiaries_count' => 'integer',
            'lat' => 'decimal:8',
            'lng' => 'decimal:8',
        ];
    }

    /**
     * Get the appended attributes.
     *
     * @return array<string>
     */
    protected $appends = [
        'total_amount',
        'location',
    ];

    /**
     * Get the grant area that this order belongs to.
     */
    public function grantArea(): BelongsTo
    {
        return $this->belongsTo(GrantArea::class);
    }

    /**
     * Get the state that this order belongs to.
     */
    public function state(): BelongsTo
    {
        return $this->belongsTo(State::class);
    }

    /**
     * Get the city that this order belongs to.
     */
    public function city(): BelongsTo
    {
        return $this->belongsTo(City::class);
    }

    /**
     * Get the association that this order belongs to.
     */
    public function association(): BelongsTo
    {
        return $this->belongsTo(Association::class);
    }

    /**
     * Get the user who created this order.
     */
    public function createdBy(): BelongsTo
    {
        return $this->belongsTo(User::class, 'created_by');
    }

    /**
     * Get the deliverables for this order.
     */
    public function deliverables(): HasMany
    {
        return $this->hasMany(OrderDeliverable::class);
    }

    /**
     * Get the requirements for this order.
     */
    public function requirements(): HasMany
    {
        return $this->hasMany(OrderRequirement::class);
    }

    /**
     * Get the agreement for this order.
     */
    public function agreement(): HasOne
    {
        return $this->hasOne(OrderAgreement::class);
    }

    /**
     * Get the finance information for this order.
     */
    public function finance(): HasOne
    {
        return $this->hasOne(OrderFinance::class);
    }

    /**
     * Register media collections for file uploads.
     */
    public function registerMediaCollections(): void
    {
        $this->addMediaCollection('support_letter')
            ->singleFile()
            ->acceptsMimeTypes(['application/pdf', 'image/jpeg', 'image/png']);

        $this->addMediaCollection('project_attachments')
            ->acceptsMimeTypes([
                'application/pdf',
                'application/vnd.ms-excel',
                'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
                'image/jpeg',
                'image/png',
                'image/gif',
                'text/plain',
                'application/msword',
                'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
            ]);
    }

    /**
     * Register media conversions.
     */
    public function registerMediaConversions(?Media $media = null): void
    {
        // Add any image conversions if needed
        $this->addMediaConversion('thumb')
            ->width(300)
            ->height(300)
            ->sharpen(10)
            ->performOnCollections('project_attachments')
            ->nonQueued();
    }

    /**
     * Get the computed total amount from deliverables.
     */
    public function getTotalAmountAttribute(): float
    {
        return $this->deliverables()->sum('amount') ?? 0.00;
    }

    /**
     * Get the computed end date based on start date and duration.
     */
    public function getEndDateAttribute(): ?Carbon
    {
        if (! $this->start_date || ! $this->duration_months) {
            return null;
        }

        return Carbon::parse($this->start_date)->addMonths($this->duration_months);
    }

    /**
     * Validation rules for text field lengths.
     */
    public static function getValidationRules(): array
    {
        return [
            'name' => 'required|string|max:200',
            'idea' => 'required|string|max:5000',
            'grant_area_id' => 'required|exists:grant_areas,id',
            'lat' => 'required|numeric|between:-90,90',
            'lng' => 'required|numeric|between:-180,180',
            'start_date' => 'required|date|after:today',
            'duration_months' => 'required|integer|min:1',
            'target_group_type' => 'required|string|max:120',
            'state_id' => 'required|exists:states,id',
            'city_id' => 'required|exists:cities,id',
            'beneficiaries_count' => 'required|integer|min:1',
            'goals' => 'required|string|max:5000',
            'strengths' => 'required|string|max:5000',
            'risks' => 'required|string|max:5000',
            'declaration_checked' => 'required|accepted',
            'association_id' => 'required|exists:associations,id',
            'created_by' => 'nullable|exists:users,id',
        ];
    }

    /**
     * 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';
    }

    public function getActivitylogOptions(): LogOptions
    {
        return LogOptions::defaults()
            ->useLogName('order');
    }

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

        static::creating(function ($model) {
            if (Auth::check()) {
                $model->created_by = Auth::id();
            }
        });
    }
}
