<?php

namespace App\Services;

use App\Models\Project;
use App\Models\AuditLog;
use App\Enums\ProjectStatus;
use App\Enums\FaseType;
use App\Enums\FaseStatus;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;

class ProjectService
{
    /**
     * Get all projects with their relationships for the metro map.
     */
    public function getAllForMap(): Collection
    {
        return Project::with(['eigenaar', 'speerpunt.thema', 'fases', 'risicos', 'commitments'])
            ->withCount(['documents', 'commitments', 'risicos'])
            ->get();
    }

    /**
     * Get a single project with full details.
     */
    public function getWithDetails(int $id): Project
    {
        return Project::with([
            'eigenaar',
            'speerpunt.thema',
            'fases',
            'risicos',
            'commitments.acties',
            'commitments.eigenaar',
            'documents',
            'besluiten',
            'teamleden',
            'afhankelijkheden.afhankelijkVan',
            'overdrachtsplannen.criteria',
        ])->findOrFail($id);
    }

    /**
     * Create a new project with initial phase.
     */
    public function create(array $data): Project
    {
        return DB::transaction(function () use ($data) {
            $project = Project::create([
                'naam' => $data['naam'],
                'beschrijving' => $data['beschrijving'] ?? '',
                'eigenaar_id' => $data['eigenaar_id'] ?? Auth::id(),
                'speerpunt_id' => $data['speerpunt_id'] ?? null,
                'status' => ProjectStatus::Signaal,
                'prioriteit' => $data['prioriteit'] ?? \App\Enums\Prioriteit::Midden,
                'startdatum' => $data['startdatum'] ?? now(),
                'streef_einddatum' => $data['streef_einddatum'] ?? null,
            ]);

            // Create initial "signaal" phase
            $project->fases()->create([
                'type' => FaseType::Signaal,
                'status' => FaseStatus::Actief,
                'startdatum' => now(),
            ]);

            // Assign creator as project owner
            $project->teamleden()->attach(Auth::id(), ['rol' => \App\Enums\ProjectRol::Eigenaar]);

            $this->audit('created', $project);

            return $project;
        });
    }

    /**
     * Update project details.
     */
    public function update(Project $project, array $data): Project
    {
        $project->update(array_filter([
            'naam' => $data['naam'] ?? null,
            'beschrijving' => $data['beschrijving'] ?? null,
            'prioriteit' => $data['prioriteit'] ?? null,
            'speerpunt_id' => $data['speerpunt_id'] ?? null,
            'streef_einddatum' => $data['streef_einddatum'] ?? null,
        ], fn ($v) => $v !== null));

        $this->audit('updated', $project);

        return $project->fresh();
    }

    /**
     * Transition a project to the next phase.
     */
    public function transitionPhase(Project $project, ProjectStatus $newStatus): Project
    {
        return DB::transaction(function () use ($project, $newStatus) {
            $oldStatus = $project->status;

            // Close current active phase
            $project->fases()
                ->where('status', FaseStatus::Actief)
                ->update([
                    'status' => FaseStatus::Afgerond->value,
                    'einddatum' => now(),
                ]);

            // Create new phase (if it maps to a FaseType)
            $faseType = FaseType::tryFrom($newStatus->value);
            if ($faseType) {
                $project->fases()->create([
                    'type' => $faseType,
                    'status' => FaseStatus::Actief,
                    'startdatum' => now(),
                ]);
            }

            // Update project status
            $project->update(['status' => $newStatus]);

            $this->audit('phase_transition', $project, [
                'from' => $oldStatus->value,
                'to' => $newStatus->value,
            ]);

            return $project->fresh(['fases']);
        });
    }

    /**
     * Park a project (temporarily halt).
     */
    public function park(Project $project, string $reason = ''): Project
    {
        return $this->transitionToSpecialStatus($project, ProjectStatus::Geparkeerd, $reason);
    }

    /**
     * Stop a project permanently.
     */
    public function stop(Project $project, string $reason = ''): Project
    {
        return $this->transitionToSpecialStatus($project, ProjectStatus::Gestopt, $reason);
    }

    private function transitionToSpecialStatus(Project $project, ProjectStatus $status, string $reason): Project
    {
        return DB::transaction(function () use ($project, $status, $reason) {
            $oldStatus = $project->status;

            $project->fases()
                ->where('status', FaseStatus::Actief)
                ->update([
                    'status' => FaseStatus::Afgerond->value,
                    'einddatum' => now(),
                    'opmerkingen' => $reason,
                ]);

            $project->update(['status' => $status]);

            $this->audit('status_change', $project, [
                'from' => $oldStatus->value,
                'to' => $status->value,
                'reason' => $reason,
            ]);

            return $project->fresh();
        });
    }

    private function audit(string $action, Project $project, ?array $extra = null): void
    {
        AuditLog::create([
            'user_id' => Auth::id(),
            'action' => "project.{$action}",
            'entity_type' => 'project',
            'entity_id' => $project->id,
            'payload' => $extra,
        ]);
    }
}
