<?php

namespace App\Http\Controllers\Api\V1\Workflow;

use App\Domain\Applicants\Models\Applicant;
use App\Domain\Workflow\Models\Pipeline;
use App\Domain\Workflow\Models\PipelineStage;
use App\Domain\Workflow\Services\PipelineService;
use App\Http\Controllers\Controller;
use App\Http\Requests\Workflow\MoveApplicantStageRequest;
use App\Http\Resources\ApplicantResource;
use App\Http\Resources\PipelineStageResource;
use App\Http\Resources\StageHistoryResource;
use App\Support\ApiResponse;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;

class ApplicantStageController extends Controller
{
    public function __construct(private readonly PipelineService $pipelines) {}

    /** Where the applicant is, where they can go, and what is blocking each option. */
    public function show(Request $request, Applicant $applicant): JsonResponse
    {
        $this->authorize('view', $applicant);

        $applicant->load(['pipeline', 'currentStage', 'stageHistories.fromStage', 'stageHistories.toStage', 'stageHistories.changedBy']);

        $options = $this->pipelines->availableTransitions($applicant, $request->user());

        return ApiResponse::success([
            'pipeline' => $applicant->pipeline ? [
                'id' => $applicant->pipeline->uuid,
                'name' => $applicant->pipeline->name,
            ] : null,
            'current_stage' => $applicant->currentStage
                ? new PipelineStageResource($applicant->currentStage)
                : null,
            'stage_entered_at' => $applicant->stage_entered_at?->toIso8601String(),
            'days_in_stage' => $applicant->daysInCurrentStage(),
            'sla_breached' => $applicant->isBreachingStageSla(),
            'available_transitions' => array_map(fn (array $option) => [
                'stage' => new PipelineStageResource($option['stage']),
                'requires_reason' => $option['requires_reason'],
                'allowed_for_user' => $option['allowed_for_user'],
                'unmet_requirements' => $option['unmet_requirements'],
                'can_move' => $option['allowed_for_user'] && $option['unmet_requirements'] === [],
            ], $options),
            'history' => StageHistoryResource::collection($applicant->stageHistories),
            'can_override' => $request->user()->can('applicant.override_stage'),
        ]);
    }

    public function move(MoveApplicantStageRequest $request, Applicant $applicant): JsonResponse
    {
        $this->authorize('changeStage', $applicant);

        $stage = PipelineStage::where('uuid', $request->string('stage_id'))->firstOrFail();

        // Bypassing requirements is its own permission, not a request flag.
        $override = $request->boolean('override') && $request->user()->can('applicant.override_stage');

        $applicant = $this->pipelines->moveTo(
            $applicant,
            $stage,
            $request->user(),
            $request->input('reason'),
            $request->input('notes'),
            $override,
        );

        return ApiResponse::success(
            new ApplicantResource($applicant->fresh()->load(['currentStage', 'agent:id,uuid,name,agent_code'])),
            "Applicant moved to {$stage->name}.",
        );
    }

    /** Places an applicant onto a pipeline at its initial stage. */
    public function assign(Request $request, Applicant $applicant): JsonResponse
    {
        $this->authorize('changeStage', $applicant);

        $validated = $request->validate([
            'pipeline_id' => ['required', 'uuid', 'exists:pipelines,uuid'],
        ]);

        $pipeline = Pipeline::where('uuid', $validated['pipeline_id'])->firstOrFail();

        $applicant = $this->pipelines->assignPipeline($applicant, $pipeline, $request->user());

        return ApiResponse::success(
            new ApplicantResource($applicant->fresh()->load('currentStage')),
            "Applicant placed on {$pipeline->name}.",
        );
    }
}
