<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Attributes\Scope;
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\Database\Eloquent\Relations\HasManyThrough;
use Illuminate\Support\Facades\Auth;
use Monzer\FilamentWorkflows\Traits\TrackWorkflowModelEvents;
use Spatie\Activitylog\LogOptions;
use Spatie\Activitylog\Traits\LogsActivity;

class ProjectCharter extends Model
{
    use HasFactory, LogsActivity, TrackWorkflowModelEvents;

    const STATUS_DRAFT = 'draft';

    const STATUS_AWAITING_APPROVAL = 'awaiting_approval';

    const STATUS_APPROVED = 'approved';

    const STATUS_REJECTED = 'rejected';

    const STATUS_COMPLETED = 'completed';

    const STATUS_CANCELED = 'canceled';

    const STATUS_SUSPENDED = 'suspended';

    protected $fillable = [
        'name',
        'description',
        'start_date',
        'expected_end_date',
        'estimated_cost',
        'total_cost',
        'status',
        'initiative_project_id',
        'order_id',
        'created_by',
        'service_provider_id',
    ];

    protected $casts = [
        'start_date' => 'date',
        'expected_end_date' => 'date',
        'estimated_cost' => 'float',
        'total_cost' => 'float',
    ];

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

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

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

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

    public function performanceCardResults(): BelongsToMany
    {
        return $this->belongsToMany(PerformanceCardResult::class, 'project_charter_performance_card_result');
    }

    public function tasks(): HasManyThrough
    {
        return $this->hasManyThrough(ProjectCharterTask::class, ProjectCharterDeliverable::class);
    }

    public function riskRegisters(): HasMany
    {
        return $this->hasMany(RiskRegister::class, 'charter_id');
    }

    public function projectGovernances(): HasMany
    {
        return $this->hasMany(ProjectGovernance::class, 'charter_id');
    }

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

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

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

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

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

    #[Scope]
    protected function ownScope(Builder $builder): void
    {
        $user = Auth::user();
        if (! $user) {
            $builder->whereRaw('1 = 0');
        } elseif (! $user->can('view_all_performance::card')) {
            $builder->where('created_by', $user->id);
        }
    }

    /**
     * Get performance card results available for this charter's initiative
     */
    public function availablePerformanceCardResults(): BelongsToMany
    {
        return $this->performanceCardResults()
            ->whereHas('initiativeResults', function ($query) {
                $query->where('initiative_id', $this->initiativeProject->initiative_id);
            });
    }

    /**
     * Get available statuses
     */
    public static function getStatuses(): array
    {
        return [
            self::STATUS_DRAFT => __('project_charter.draft'),
            self::STATUS_AWAITING_APPROVAL => __('project_charter.awaiting_approval'),
            self::STATUS_APPROVED => __('project_charter.approved'),
            self::STATUS_REJECTED => __('project_charter.rejected'),
            self::STATUS_COMPLETED => __('project_charter.completed'),
            self::STATUS_CANCELED => __('project_charter.canceled'),
            self::STATUS_SUSPENDED => __('project_charter.suspended'),
        ];
    }

    public function getProjectProgressAttribute(): float
    {
        $deliverables = $this->deliverables;

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

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

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

    /**
     * Get the total value of all approved exchange requests for this charter
     */
    public function getTotalApprovedExchangeRequestsAttribute(): float
    {
        return $this->deliverables()
            ->with(['completionReports.exchangeRequest'])
            ->get()
            ->pluck('completionReports')
            ->flatten()
            ->pluck('exchangeRequest')
            ->filter(function ($exchangeRequest) {
                return $exchangeRequest && $exchangeRequest->status === \App\Models\ExchangeRequest::STATUS_APPROVED;
            })
            ->sum(function ($exchangeRequest) {
                return $exchangeRequest->completionReport->value ?? 0;
            });
    }

    /**
     * Get the financial progress percentage based on approved exchange requests vs estimated cost
     */
    public function getFinancialProgressAttribute(): float
    {
        if (! $this->estimated_cost || $this->estimated_cost <= 0) {
            return 0;
        }

        $approvedValue = $this->total_approved_exchange_requests;

        return min(100, ($approvedValue / $this->estimated_cost) * 100);
    }

    /**
     * Get the remaining cost (estimated_cost - total_approved_exchange_requests)
     */
    public function getRemainingCostAttribute(): float
    {
        if (! $this->estimated_cost) {
            return 0;
        }

        return $this->estimated_cost - $this->total_approved_exchange_requests;
    }

    /**
     * Get the project charter status based on related tasks
     */
    public function getProjectStatusAttribute(): string
    {
        $tasks = $this->tasks;

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

        $allDone = $tasks->every(fn ($task) => $task->status === 'done');
        $allNotStarted = $tasks->every(fn ($task) => $task->status === 'not_started');
        $hasIncompleteTasks = $tasks->some(fn ($task) => $task->status !== 'done');

        if ($allDone) {
            return 'done';
        }

        if ($allNotStarted) {
            return 'not_started';
        }

        if ($hasIncompleteTasks) {
            // Count how many tasks are late
            $lateTasks = $tasks->filter(fn ($task) => $task->status === 'late');

            // Check if project is late:
            // 1. If there are 2 or more late tasks, OR
            // 2. If project is in progress but past expected end date
            if (
                $lateTasks->count() >= 2 ||
                ($this->expected_end_date && now()->toDateString() > $this->expected_end_date)
            ) {
                return 'late';
            }

            return 'in_progress';
        }

        return 'not_started'; // fallback
    }

    /**
     * Get the project status color for display
     */
    public function getProjectStatusColorAttribute(): string
    {
        return match ($this->project_status) {
            'not_started' => 'gray',
            'in_progress' => 'blue',
            'late' => 'danger',
            'done' => 'success',
            default => 'gray',
        };
    }

    /**
     * Get the project phase based on status (similar to ProjectStatusChart grouping)
     */
    public function getProjectPhaseAttribute(): string
    {
        return match (true) {
            in_array($this->status, [
                self::STATUS_DRAFT,
                self::STATUS_AWAITING_APPROVAL,
            ]) => __('project_charter.initiation'),

            $this->status === self::STATUS_APPROVED => __('project_charter.execution'),

            in_array($this->status, [
                self::STATUS_COMPLETED,
                self::STATUS_CANCELED,
                self::STATUS_REJECTED,
                self::STATUS_SUSPENDED,
            ]) => __('project_charter.closure'),

            default => $this->status,
        };
    }

    /**
     * Get the color for the project phase badge
     */
    public function getProjectPhaseColorAttribute(): string
    {
        return match (true) {
            in_array($this->status, [
                self::STATUS_DRAFT,
                self::STATUS_AWAITING_APPROVAL,
            ]) => 'warning', // Yellow for initiation

            $this->status === self::STATUS_APPROVED => 'success', // Green for execution

            in_array($this->status, [
                self::STATUS_COMPLETED,
                self::STATUS_CANCELED,
                self::STATUS_REJECTED,
                self::STATUS_SUSPENDED,
            ]) => 'danger', // Red for closure

            default => 'gray',
        };
    }

    /**
     * Get available project statuses
     */
    public static function getProjectStatuses(): array
    {
        return [
            'not_started' => __('project_charter.project_status_not_started'),
            'in_progress' => __('project_charter.project_status_in_progress'),
            'late' => __('project_charter.project_status_late'),
            'done' => __('project_charter.project_status_done'),
        ];
    }

    /**
     * Get available project phases
     */
    public static function getProjectPhases(): array
    {
        return [
            'initiation' => __('project_charter.initiation'),
            'execution' => __('project_charter.execution'),
            'closure' => __('project_charter.closure'),
        ];
    }

    /**
     * Get the estimated progress percentage based on timeline
     */
    public function getEstimatedProgressPercentageAttribute(): float
    {
        if (! $this->start_date || ! $this->expected_end_date) {
            return 0;
        }

        $startDate = \Carbon\Carbon::parse($this->start_date);
        $endDate = \Carbon\Carbon::parse($this->expected_end_date);
        $currentDate = \Carbon\Carbon::now();

        if ($currentDate <= $startDate) {
            return 0;
        }

        if ($currentDate >= $endDate) {
            return 100;
        }

        $totalDays = $startDate->diffInDays($endDate);
        $elapsedDays = $startDate->diffInDays($currentDate);

        return ($elapsedDays / $totalDays) * 100;
    }

    /**
     * Get the progress deviation (actual - estimated)
     */
    public function getProgressDeviationAttribute(): float
    {
        return $this->project_progress - $this->estimated_progress_percentage;
    }

    /**
     * Get the project manner from the related performance card
     * This accessor bypasses global scopes to ensure visibility for all users
     */
    public function getProjectMannerAttribute(): ?string
    {
        // Load the initiative project with relationships, bypassing global scopes
        $initiativeProject = $this->initiativeProject()
            ->with([
                'initiative' => function ($query) {
                    $query->withoutGlobalScopes()->with([
                        'performanceCard' => function ($q) {
                            $q->withoutGlobalScopes();
                        },
                    ]);
                },
            ])
            ->first();

        return $initiativeProject
            ?->initiative
            ?->performanceCard
            ?->project_manner;
    }

    /**
     * Get a comma-separated string of performance card assignees' emails
     */
    public function getPerformanceCardAssigneesEmailsAttribute(): string
    {
        // Get the performance card through the relationship chain
        $performanceCard = $this->initiativeProject
            ?->initiative
            ?->performanceWallet
            ?->performanceCard;

        if (! $performanceCard) {
            return '';
        }

        // Get all assignees with emails and return as comma-separated string
        return $performanceCard->assignees()
            ->whereNotNull('email')
            ->pluck('email')
            ->filter()
            ->implode(',');
    }

    /**
     * Get the color for estimated progress display
     */
    public function getEstimatedProgressColorAttribute(): string
    {
        $deviation = $this->progress_deviation;

        return match (true) {
            $deviation >= 10 => 'success',  // Ahead of schedule
            $deviation >= 0 => 'info',     // On track
            $deviation >= -10 => 'warning', // Slightly behind
            default => 'danger',           // Significantly behind
        };
    }

    /**
     * Get the color for progress deviation display
     */
    public function getProgressDeviationColorAttribute(): string
    {
        $deviation = $this->progress_deviation;

        return match (true) {
            $deviation >= 10 => 'success',  // Significantly ahead
            $deviation >= 0 => 'info',     // On track or slightly ahead
            $deviation >= -10 => 'warning', // Slightly behind
            default => 'danger',           // Significantly behind
        };
    }

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

    /**
     * Check if charter can be submitted for approval
     */
    public function canSubmitForApproval(): bool
    {
        return $this->status === self::STATUS_DRAFT;
    }

    /**
     * Check if charter can be approved
     */
    public function canApprove(): bool
    {
        return $this->status === self::STATUS_AWAITING_APPROVAL;
    }

    /**
     * Check if charter can be rejected
     */
    public function canReject(): bool
    {
        return $this->status === self::STATUS_AWAITING_APPROVAL;
    }

    /**
     * Check if charter can be sent back to draft
     */
    public function canSendBackToDraft(): bool
    {
        return $this->status === self::STATUS_AWAITING_APPROVAL;
    }

    /**
     * Check if charter can be edited
     */
    public function canEdit(): bool
    {
        return $this->status === self::STATUS_DRAFT;
    }

    /**
     * Check if charter can request closure
     */
    public function canRequestClosure(): bool
    {
        return $this->status === self::STATUS_APPROVED;
    }

    /**
     * Submit charter for approval
     */
    public function submitForApproval(string $notes = ''): bool
    {
        if (! $this->canSubmitForApproval()) {
            return false;
        }

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

        if ($result) {
            activity()
                ->performedOn($this)
                ->causedBy(Auth::user())
                ->event('submitted_for_approval')
                ->withProperties([
                    'old_status' => $oldStatus,
                    'new_status' => $this->status,
                    'notes' => $notes,
                ])
                ->log('Charter submitted for approval');
        }

        return $result;
    }

    /**
     * Approve charter
     */
    public function approve(string $notes = ''): 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,
                    'notes' => $notes,
                ])
                ->log('Charter approved');
        }

        return $result;
    }

    /**
     * Reject charter
     */
    public function reject(string $notes): 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,
                    'notes' => $notes,
                ])
                ->log('Charter rejected');
        }

        return $result;
    }

    /**
     * Send charter back to draft
     */
    public function sendBackToDraft(string $notes = ''): bool
    {
        if (! $this->canSendBackToDraft()) {
            return false;
        }

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

        if ($result) {
            activity()
                ->performedOn($this)
                ->causedBy(Auth::user())
                ->event('sent_back_to_draft')
                ->withProperties([
                    'old_status' => $oldStatus,
                    'new_status' => $this->status,
                    'notes' => $notes,
                ])
                ->log('Charter sent back to draft');
        }

        return $result;
    }

    /**
     * Validate that the estimated cost doesn't exceed the initiative's expected cost
     */
    public function validateEstimatedCostAgainstInitiative(float $newEstimatedCost): array
    {
        $initiative = $this->initiativeProject?->initiative;
        if (! $initiative || ! $initiative->expected_cost) {
            return [
                'success' => true,
                'message' => null,
                'data' => [
                    'initiative_expected_cost' => 0,
                    'current_estimated_cost' => $newEstimatedCost,
                    'remaining_budget' => 0,
                ],
            ];
        }

        $initiativeExpectedCost = $initiative->expected_cost;

        // Get sum of other project charters' estimated costs in this initiative (excluding current if editing)
        $otherChartersSum = $initiative->projects()
            ->with('projectCharter')
            ->get()
            ->filter(function ($project) {
                return $project->projectCharter &&
                    ($this->exists ? $project->projectCharter->id !== $this->id : true);
            })
            ->sum(function ($project) {
                return $project->projectCharter->estimated_cost ?? 0;
            });

        $totalEstimatedCost = $otherChartersSum + $newEstimatedCost;
        $remainingBudget = $initiativeExpectedCost - $otherChartersSum;

        if ($totalEstimatedCost > $initiativeExpectedCost) {
            return [
                'success' => false,
                'message' => __('project_charter.estimated_cost_exceeds_initiative_budget', [
                    'estimated_cost' => number_format($newEstimatedCost, 2),
                    'initiative_expected_cost' => number_format($initiativeExpectedCost, 2),
                    'remaining_budget' => number_format($remainingBudget, 2),
                ]),
                'data' => [
                    'initiative_expected_cost' => $initiativeExpectedCost,
                    'current_estimated_cost' => $newEstimatedCost,
                    'other_charters_sum' => $otherChartersSum,
                    'total_estimated_cost' => $totalEstimatedCost,
                    'remaining_budget' => $remainingBudget,
                ],
            ];
        }

        return [
            'success' => true,
            'message' => null,
            'data' => [
                'initiative_expected_cost' => $initiativeExpectedCost,
                'current_estimated_cost' => $newEstimatedCost,
                'other_charters_sum' => $otherChartersSum,
                'total_estimated_cost' => $totalEstimatedCost,
                'remaining_budget' => $remainingBudget,
            ],
        ];
    }

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

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