<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Log;
use Monzer\FilamentWorkflows\Traits\TrackWorkflowModelEvents;
use Spatie\MediaLibrary\HasMedia;
use Spatie\MediaLibrary\InteractsWithMedia;
use Spatie\MediaLibrary\MediaCollections\Models\Media;

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

    protected $fillable = [
        'name',
        'description',
        'expected_delivery_date',
        'weight',
        'payment_number',
        'estimated_cost',
        'project_charter_id',
        'file_status',
        'approved_by',
        'approved_at',
        'rejection_reason',
        'created_by',
    ];

    protected $casts = [
        'expected_delivery_date' => 'date',
        'weight' => 'float',
        'estimated_cost' => 'decimal:2',
        'approved_at' => 'datetime',
    ];

    // File status constants
    const FILE_STATUS_NONE = null;

    const FILE_STATUS_PENDING = 'pending';

    const FILE_STATUS_APPROVED = 'approved';

    const FILE_STATUS_REJECTED = 'rejected';

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

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

        // Listen for media changes to automatically set file status
        static::saved(function ($deliverable) {
            // Check if media was just added to the deliverable_files collection
            if ($deliverable->hasFile() && $deliverable->file_status === null) {
                $deliverable->update(['file_status' => self::FILE_STATUS_PENDING]);
            }
        });
    }

    public function projectCharter(): BelongsTo
    {
        return $this->belongsTo(ProjectCharter::class);
    }

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

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

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

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

    // Calculate overall progress based on tasks
    public function getProgressPercentageAttribute(): float
    {
        $tasks = $this->tasks;

        if ($tasks->isEmpty()) {
            return 0;
        }

        $totalProgress = $tasks->sum('progress_percentage');

        return $totalProgress / $tasks->count();
    }

    // Get completion status based on tasks
    public function getCompletionStatusAttribute(): string // not used
    {
        $tasks = $this->tasks;

        if ($tasks->isEmpty()) {
            return 'no_tasks';
        }

        Log::debug('Calculating completion status for deliverable: '.$this->id);
        // count of tasks
        Log::debug('Total tasks: '.$tasks->count());

        $completedTasks = $tasks->where('progress_percentage', 100)->count();
        $totalTasks = $tasks->count();

        if ($completedTasks === 0) {
            return 'not_started';
        } elseif ($completedTasks === $totalTasks) {
            return 'completed';
        } else {
            return 'in_progress';
        }
    }

    /**
     * Register media collections
     */
    public function registerMediaCollections(): void
    {
        $this->addMediaCollection('deliverable_files')
            ->acceptsMimeTypes(['application/pdf'])
            ->singleFile();
    }

    /**
     * Register media conversions
     */
    public function registerMediaConversions(?Media $media = null): void
    {
        // Add any media conversions if needed
    }

    /**
     * Check if deliverable has a file
     */
    public function hasFile(): bool
    {
        return $this->getFirstMedia('deliverable_files') !== null;
    }

    /**
     * Check if the deliverable can have completion reports
     */
    public function canHaveCompletionReports(): bool
    {
        return $this->file_status === self::FILE_STATUS_APPROVED;
    }

    /**
     * Check if the file can be overwritten
     */
    public function canOverwriteFile(): bool
    {
        return in_array($this->file_status, [self::FILE_STATUS_NONE, self::FILE_STATUS_PENDING, self::FILE_STATUS_REJECTED]);
    }

    /**
     * Get available file statuses
     */
    public static function getFileStatuses(): array
    {
        return [
            self::FILE_STATUS_PENDING => __('project_charter_deliverable.file_status_pending'),
            self::FILE_STATUS_APPROVED => __('project_charter_deliverable.file_status_approved'),
            self::FILE_STATUS_REJECTED => __('project_charter_deliverable.file_status_rejected'),
        ];
    }

    /**
     * Approve the deliverable file
     */
    public function approveFile(int $approvedBy): bool
    {
        if ($this->file_status !== self::FILE_STATUS_PENDING) {
            return false;
        }

        $this->file_status = self::FILE_STATUS_APPROVED;
        $this->approved_by = $approvedBy;
        $this->approved_at = now();
        $this->rejection_reason = null;

        return $this->save();
    }

    /**
     * Reject the deliverable file
     */
    public function rejectFile(int $rejectedBy, string $reason): bool
    {
        if ($this->file_status !== self::FILE_STATUS_PENDING) {
            return false;
        }

        $this->file_status = self::FILE_STATUS_REJECTED;
        $this->approved_by = $rejectedBy;
        $this->approved_at = now();
        $this->rejection_reason = $reason;

        return $this->save();
    }

    /**
     * Validate that the estimated cost doesn't exceed the project charter budget
     */
    public function validateEstimatedCostLimit(float $newEstimatedCost): array
    {
        $charter = $this->projectCharter;
        if (! $charter || ! $charter->estimated_cost) {
            return ['valid' => true];
        }

        // Calculate current total excluding this deliverable (if it exists)
        $currentTotal = $charter->deliverables()
            ->when($this->exists, fn ($query) => $query->where('id', '!=', $this->id))
            ->sum('estimated_cost');

        $newTotal = $currentTotal + $newEstimatedCost;
        $charterBudget = $charter->estimated_cost;

        if ($newTotal > $charterBudget) {
            return [
                'valid' => false,
                'charter_budget' => $charterBudget,
                'current_total' => $currentTotal,
                'available' => max(0, $charterBudget - $currentTotal),
                'requested' => $newEstimatedCost,
                'would_exceed_by' => $newTotal - $charterBudget,
            ];
        }

        return ['valid' => true];
    }
}
