<?php

declare(strict_types=1);

namespace App\Http\Controllers\Install;

use App\Http\Controllers\Controller;
use App\Services\Install\Contracts\WebInstallStepRunnerContract;
use App\Services\Install\DBErpInstallStatus;
use App\Services\Install\WebInstallProgressApiResponse;
use App\Services\Install\WebInstallProgressDisplay;
use App\Services\Install\WebInstallProgressNotFoundException;
use App\Services\Install\WebInstallProgressSessionManager;
use Illuminate\Contracts\View\View;
use Illuminate\Http\JsonResponse;
use InvalidArgumentException;

final class InstallProgressController extends Controller
{
    public function show(
        string $installId,
        WebInstallProgressSessionManager $progressSessionManager,
    ): View {
        try {
            $progress = $progressSessionManager->read($installId);
        } catch (InvalidArgumentException) {
            $progress = null;
        }

        if ($progress === null) {
            return view('install.progress', [
                'missingTask' => true,
                'missingTaskMessage' => WebInstallProgressDisplay::MISSING_TASK_MESSAGE,
            ]);
        }

        return view('install.progress', [
            'missingTask' => false,
            'installId' => $installId,
            'progress' => $progress,
            'headline' => WebInstallProgressDisplay::INSTALL_HEADLINE,
            'stages' => WebInstallProgressDisplay::businessStages(),
            'stateUrl' => route('install.progress.state', ['install_id' => $installId]),
            'runStepUrl' => route('install.progress.run-step', ['install_id' => $installId]),
            'retryStepUrl' => route('install.progress.retry-step', ['install_id' => $installId]),
            'finishedUrl' => route('install.finished'),
        ]);
    }

    public function state(
        string $installId,
        WebInstallProgressSessionManager $progressSessionManager,
        DBErpInstallStatus $installStatus,
    ): JsonResponse {
        try {
            $progress = $progressSessionManager->read($installId);
        } catch (InvalidArgumentException) {
            $progress = null;
        }

        if ($progress === null) {
            return response()->json([
                'message' => WebInstallProgressDisplay::MISSING_TASK_MESSAGE,
            ], 404);
        }

        return response()->json(WebInstallProgressApiResponse::fromState(
            $progress,
            applicationAlreadyInstalled: $installStatus->isInstalled(),
        ));
    }

    public function runStep(
        string $installId,
        WebInstallStepRunnerContract $stepRunner,
        DBErpInstallStatus $installStatus,
    ): JsonResponse {
        try {
            $progress = $stepRunner->runNextStep($installId);
        } catch (WebInstallProgressNotFoundException) {
            return response()->json([
                'message' => WebInstallProgressDisplay::MISSING_TASK_MESSAGE,
            ], 404);
        } catch (InvalidArgumentException) {
            return response()->json([
                'message' => WebInstallProgressDisplay::MISSING_TASK_MESSAGE,
            ], 404);
        }

        return response()->json(WebInstallProgressApiResponse::fromState(
            $progress,
            applicationAlreadyInstalled: $installStatus->isInstalled(),
        ));
    }

    public function retryStep(
        string $installId,
        WebInstallStepRunnerContract $stepRunner,
        DBErpInstallStatus $installStatus,
    ): JsonResponse {
        try {
            $progress = $stepRunner->retryFailedStep($installId);
        } catch (WebInstallProgressNotFoundException) {
            return response()->json([
                'message' => WebInstallProgressDisplay::MISSING_TASK_MESSAGE,
            ], 404);
        } catch (InvalidArgumentException) {
            return response()->json([
                'message' => WebInstallProgressDisplay::MISSING_TASK_MESSAGE,
            ], 404);
        }

        return response()->json(WebInstallProgressApiResponse::fromState(
            $progress,
            applicationAlreadyInstalled: $installStatus->isInstalled(),
        ));
    }
}
