<?php

namespace App\Models;

use Carbon\Carbon;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasOne;
use Illuminate\Support\Facades\Auth;
use Monzer\FilamentWorkflows\Traits\TrackWorkflowModelEvents;
use Spatie\Activitylog\LogOptions;
use Spatie\Activitylog\Traits\LogsActivity;
use Spatie\MediaLibrary\HasMedia;
use Spatie\MediaLibrary\InteractsWithMedia;
use Spatie\MediaLibrary\MediaCollections\Models\Media;

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

    const STATUS_PENDING = 'pending';

    const STATUS_APPROVED = 'approved';

    const STATUS_REJECTED = 'rejected';

    protected $fillable = [
        'description',
        'value',
        'delivery_date',
        'status',
        'project_charter_deliverable_id',
        'created_by',
    ];

    protected $casts = [
        'delivery_date' => 'date',
        'value' => 'decimal:2',
        'created_at' => 'datetime',
        'updated_at' => 'datetime',
    ];

    protected $attributes = [
        'status' => self::STATUS_PENDING,
    ];

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

    public function exchangeRequest(): HasOne
    {
        return $this->hasOne(ExchangeRequest::class);
    }

    /**
     * Get all exchange requests for this completion report (including rejected ones)
     */
    public function exchangeRequests(): \Illuminate\Database\Eloquent\Relations\HasMany
    {
        return $this->hasMany(ExchangeRequest::class);
    }

    /**
     * Get the active (non-rejected) exchange request for this completion report
     */
    public function activeExchangeRequest(): HasOne
    {
        return $this->hasOne(ExchangeRequest::class)
            ->where('status', '!=', ExchangeRequest::STATUS_REJECTED);
    }

    /**
     * Check if completion report has an active exchange request
     */
    public function hasActiveExchangeRequest(): bool
    {
        return $this->activeExchangeRequest()->exists();
    }

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

    /**
     * Get all activities for this model
     */
    public function activities()
    {
        return \Spatie\Activitylog\Models\Activity::forSubject($this);
    }

    /**
     * Get available statuses
     */
    public static function getStatuses(): array
    {
        return [
            self::STATUS_PENDING => __('completion_report.status_pending'),
            self::STATUS_APPROVED => __('completion_report.status_approved'),
            self::STATUS_REJECTED => __('completion_report.status_rejected'),
        ];
    }

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

        $this->addMediaCollection('cr_files')
            ->acceptsMimeTypes([
                'application/pdf',
                'image/jpeg',
                'image/png',
                'image/jpg',
            ]);

        // Additional files collection (multiple files for creation)
        $this->addMediaCollection('er_files')
            ->acceptsMimeTypes([
                'application/pdf',
                'image/jpeg',
                'image/png',
                'image/jpg',
            ]);
    }

    /**
     * Get the PDF file
     */
    public function getPdfFile(): ?Media
    {
        return $this->getFirstMedia('pdf_file');
    }

    /**
     * Get the PDF file URL
     */
    public function getPdfFileUrlAttribute(): ?string
    {
        $media = $this->getFirstMedia('pdf_file');

        return $media ? $media->getTemporaryUrl(Carbon::now()->addMinutes(5)) : null;
    }

    /**
     * Get cr additional files
     */
    public function getCrFiles()
    {
        return $this->getMedia('cr_files');
    }

    /**
     * Check if completion report has additional files
     */
    public function hasCrFiles(): bool
    {
        return $this->getMedia('cr_files')->count() > 0;
    }

    /**
     * Get er additional files
     */
    public function getErFiles()
    {
        return $this->getMedia('er_files');
    }

    /**
     * Check if exchange request has additional files
     */
    public function hasErFiles(): bool
    {
        return $this->getMedia('er_files')->count() > 0;
    }

    /**
     * Get the approved at date
     */
    public function getApprovedAtAttribute(): ?Carbon
    {
        if ($this->status !== self::STATUS_APPROVED) {
            return null;
        }

        $approvalActivity = $this->activities()
            ->where('event', 'approved')
            ->latest()
            ->first();

        return $approvalActivity ? $approvalActivity->created_at : null;
    }

    /**
     * Get the approved by user
     */
    public function getApprovedByAttribute(): ?User
    {
        if ($this->status !== self::STATUS_APPROVED) {
            return null;
        }

        $approvalActivity = $this->activities()
            ->where('event', 'approved')
            ->latest()
            ->first();

        return $approvalActivity ? $approvalActivity->causer : null;
    }

    /**
     * Check if completion report can be approved
     */
    public function canApprove(): bool
    {
        return $this->status === self::STATUS_PENDING
            && Auth::user()->can('approve_completion_report_completion::report');
    }

    /**
     * Check if completion report can be rejected
     */
    public function canReject(): bool
    {
        return $this->status === self::STATUS_PENDING
            && Auth::user()->can('reject_completion_report_completion::report');
    }

    /**
     * Validate that the completion report value doesn't exceed the deliverable estimated cost
     */
    public function validateValueAgainstDeliverableEstimatedCost(): array
    {
        $deliverable = $this->projectCharterDeliverable;

        if (! $deliverable || ! $deliverable->estimated_cost) {
            return [
                'success' => true,
                'message' => null,
                'data' => [
                    'deliverable_estimated_cost' => 0,
                    'current_value' => $this->value ?? 0,
                    'remaining_budget' => 0,
                ],
            ];
        }

        $deliverableEstimatedCost = $deliverable->estimated_cost;
        $currentValue = $this->value ?? 0;

        // Get sum of other completion reports for this deliverable (excluding current if editing)
        $otherReportsSum = $deliverable->completionReports()
            ->when($this->exists, function ($query) {
                return $query->where('id', '!=', $this->id);
            })
            ->sum('value');

        $totalValue = $otherReportsSum + $currentValue;
        $remainingBudget = $deliverableEstimatedCost - $otherReportsSum;

        if ($totalValue > $deliverableEstimatedCost) {
            return [
                'success' => false,
                'message' => __('completion_report.value_exceeds_deliverable_budget', [
                    'value' => number_format($currentValue, 2),
                    'deliverable_estimated_cost' => number_format($deliverableEstimatedCost, 2),
                    'remaining_budget' => number_format($remainingBudget, 2),
                ]),
                'data' => [
                    'deliverable_estimated_cost' => $deliverableEstimatedCost,
                    'current_value' => $currentValue,
                    'other_reports_sum' => $otherReportsSum,
                    'total_value' => $totalValue,
                    'remaining_budget' => $remainingBudget,
                ],
            ];
        }

        return [
            'success' => true,
            'message' => null,
            'data' => [
                'deliverable_estimated_cost' => $deliverableEstimatedCost,
                'current_value' => $currentValue,
                'other_reports_sum' => $otherReportsSum,
                'total_value' => $totalValue,
                'remaining_budget' => $remainingBudget,
            ],
        ];
    }

    /**
     * Approve completion report
     */
    public function approve(): bool
    {
        if (! $this->canApprove()) {
            return false;
        }

        $oldStatus = $this->status;
        $this->status = self::STATUS_APPROVED;
        $result = $this->save();

        if ($result) {
            activity()
                ->performedOn($this)
                ->causedBy(Auth::user())
                ->event('approved')
                ->withProperties([
                    'old_status' => $oldStatus,
                    'new_status' => $this->status,
                ])
                ->log('Completion report approved');
        }

        return $result;
    }

    /**
     * Reject completion report
     */
    public function reject(): bool
    {
        if (! $this->canReject()) {
            return false;
        }

        $oldStatus = $this->status;
        $this->status = self::STATUS_REJECTED;
        $result = $this->save();

        if ($result) {
            activity()
                ->performedOn($this)
                ->causedBy(Auth::user())
                ->event('rejected')
                ->withProperties([
                    'old_status' => $oldStatus,
                    'new_status' => $this->status,
                ])
                ->log('Completion report rejected');
        }

        return $result;
    }

    /**
     * Configure activity logging
     */
    public function getActivitylogOptions(): LogOptions
    {
        return LogOptions::defaults()
            ->logOnly(['status', 'value', 'delivery_date'])
            ->logOnlyDirty()
            ->dontSubmitEmptyLogs();
    }

    /**
     * Boot the model
     */
    protected static function boot()
    {
        parent::boot();

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