<?php

namespace App\Services;

use App\Enums\CommitmentStatus;
use App\Models\AuditLog;
use App\Models\Commitment;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;

class CommitmentService
{
    /**
     * Get all commitments for a project with owner and acties.
     */
    public function getForProject(int $projectId): Collection
    {
        return Commitment::with(['eigenaar', 'acties'])
            ->where('project_id', $projectId)
            ->orderBy('deadline')
            ->get();
    }

    /**
     * Create a new commitment with audit log.
     */
    public function create(array $data): Commitment
    {
        return DB::transaction(function () use ($data) {
            $commitment = Commitment::create([
                'project_id'  => $data['project_id'],
                'beschrijving' => $data['beschrijving'],
                'eigenaar_id' => $data['eigenaar_id'],
                'deadline'    => $data['deadline'],
                'status'      => CommitmentStatus::Open,
                'bron'        => $data['bron'] ?? null,
                'besluit_id'  => $data['besluit_id'] ?? null,
            ]);

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

            return $commitment;
        });
    }

    /**
     * Update a commitment with audit log.
     */
    public function update(Commitment $commitment, array $data): Commitment
    {
        return DB::transaction(function () use ($commitment, $data) {
            $commitment->update(array_filter([
                'beschrijving' => $data['beschrijving'] ?? null,
                'eigenaar_id'  => $data['eigenaar_id'] ?? null,
                'deadline'     => $data['deadline'] ?? null,
                'status'       => $data['status'] ?? null,
                'bron'         => $data['bron'] ?? null,
            ], fn ($v) => $v !== null));

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

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

    /**
     * Mark a commitment as afgerond with audit log.
     */
    public function markComplete(Commitment $commitment): Commitment
    {
        return DB::transaction(function () use ($commitment) {
            $commitment->update(['status' => CommitmentStatus::Afgerond]);

            $this->audit('completed', $commitment);

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

    /**
     * Get all commitments past their deadline that are not afgerond.
     */
    public function getOverdue(): Collection
    {
        return Commitment::with(['eigenaar', 'project'])
            ->where('deadline', '<', now()->toDateString())
            ->where('status', '!=', CommitmentStatus::Afgerond)
            ->orderBy('deadline')
            ->get();
    }

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