<?php

namespace App\Domain\Website\Services;

use App\Domain\Identity\Models\User;
use App\Domain\Recruitment\Enums\JobDemandStatus;
use App\Domain\Recruitment\Models\JobDemand;
use App\Domain\Website\Models\JobCategory;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use Illuminate\Validation\ValidationException;

/**
 * Publishes an approved job demand to the public website (§162).
 *
 * Publishing is a separate, permissioned act from approving the demand: what an
 * employer agreed internally and what the agency advertises publicly are not
 * the same decision.
 */
class JobPublishingService
{
    /**
     * @param  array<string, mixed>  $attributes
     *
     * @throws ValidationException
     */
    public function publish(JobDemand $demand, array $attributes, ?User $actor = null): JobDemand
    {
        // Only an open demand may be advertised; a draft or paused one would
        // invite applications the agency cannot act on.
        if ($demand->status !== JobDemandStatus::Open) {
            throw ValidationException::withMessages([
                'status' => ["Only an open demand can be published. This one is {$demand->status->label()}."],
            ]);
        }

        return DB::transaction(function () use ($demand, $attributes, $actor) {
            $demand->fill([
                'is_public' => true,
                'public_slug' => $demand->public_slug ?: $this->generateSlug($demand),
                'publish_at' => $attributes['publish_at'] ?? now(),
                'unpublish_at' => $attributes['unpublish_at'] ?? $demand->application_deadline?->endOfDay(),
                // These columns are NOT NULL with a database default, so a model
                // that never loaded them must fall back to false rather than null.
                'is_featured' => $attributes['is_featured'] ?? $demand->is_featured ?? false,
                'is_urgent' => $attributes['is_urgent'] ?? $demand->is_urgent ?? false,
                'show_employer_publicly' => $attributes['show_employer_publicly'] ?? false,
                'public_summary' => $attributes['public_summary'] ?? $demand->public_summary,
                'public_responsibilities' => $attributes['public_responsibilities'] ?? $demand->public_responsibilities,
                'seo_title' => $attributes['seo_title'] ?? $demand->seo_title,
                'seo_description' => $attributes['seo_description'] ?? $demand->seo_description,
                'job_category_id' => $this->resolveCategory($attributes['job_category_id'] ?? null) ?? $demand->job_category_id,
                'updated_by' => $actor?->getKey(),
            ])->save();

            return $demand;
        });
    }

    public function unpublish(JobDemand $demand, ?User $actor = null): JobDemand
    {
        // The slug is kept so an old link resolves to "no longer available"
        // rather than being reused by a different job.
        $demand->fill([
            'is_public' => false,
            'unpublish_at' => now(),
            'updated_by' => $actor?->getKey(),
        ])->save();

        return $demand;
    }

    /** Slugs stay unique per company and never change once assigned. */
    public function generateSlug(JobDemand $demand): string
    {
        $base = Str::slug("{$demand->job_title} {$demand->country}");
        $slug = $base;
        $suffix = 2;

        while (JobDemand::where('company_id', $demand->company_id)
            ->where('public_slug', $slug)
            ->whereKeyNot($demand->getKey())
            ->exists()) {
            $slug = "{$base}-{$suffix}";
            $suffix++;
        }

        return $slug;
    }

    private function resolveCategory(?string $uuid): ?int
    {
        return $uuid === null ? null : JobCategory::where('uuid', $uuid)->value('id');
    }
}
