<?php

declare(strict_types=1);

namespace Maestro\Core\Http\Controllers\Superadmin;

use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
use Maestro\Core\Http\Controllers\Controller;
use Maestro\Core\Models\MaestroModule;
use Maestro\Core\Services\InstallationHealthService;
use Maestro\Core\Support\ModuleDependencyMap;

class MaestroModuleController extends Controller
{
    public function index(): JsonResponse
    {
        $health = new InstallationHealthService();

        $modules = [];
        foreach (ModuleDependencyMap::allSlugs() as $slug) {
            $row = MaestroModule::query()->where('slug', $slug)->first();
            $moduleHealth = $health->moduleReport($slug);
            $installLocked = $this->isInstallLocked($moduleHealth);
            $isInstallEnabled = (bool) ($row?->is_install_enabled ?? false) || $installLocked;

            $modules[] = [
                'slug' => $slug,
                'label' => $row?->label ?? ucfirst($slug),
                // Backward compatibility for existing UI bindings:
                'is_enabled' => (bool) ($row?->is_enabled ?? false),
                'is_runtime_enabled' => (bool) ($row?->is_enabled ?? false),
                'is_install_enabled' => $isInstallEnabled,
                'install_locked' => $installLocked,
                'dependencies' => ModuleDependencyMap::dependenciesFor($slug),
                'dependents' => ModuleDependencyMap::dependentsOf($slug),
                'health' => $moduleHealth,
            ];
        }

        return response()->json([
            'checked_at' => now()->toIso8601String(),
            'modules'    => $modules,
        ]);
    }

    public function activate(string $slug): JsonResponse
    {
        $request = Request::create('', 'PATCH', ['is_enabled' => true]);

        return $this->setRuntimeState($request, $slug);
    }

    public function setInstallationState(Request $request, string $slug): JsonResponse
    {
        $request->validate(['is_enabled' => ['required', 'boolean']]);

        $row = $this->moduleRowOrResponse($slug);
        if (! ($row instanceof MaestroModule)) {
            return $row;
        }

        $desired = (bool) $request->boolean('is_enabled');
        $health = (new InstallationHealthService())->moduleReport($slug);
        $installLocked = $this->isInstallLocked($health);

        if (! $desired && $installLocked) {
            return response()->json([
                'message' => 'Cannot disable installation toggle after database migrations created module tables.',
                'health' => $health,
            ], 422);
        }

        if ($desired && $health['config']['status'] === 'fail') {
            return response()->json([
                'message' => 'Cannot enable installation toggle: config check is failing.',
                'health' => $health,
            ], 422);
        }

        $row->update(['is_install_enabled' => $desired]);

        return response()->json([
            'data' => [
                'slug' => $row->slug,
                'label' => $row->label,
                'is_install_enabled' => $desired,
                'install_locked' => $installLocked,
            ],
        ]);
    }

    public function setRuntimeState(Request $request, string $slug): JsonResponse
    {
        $request->validate(['is_enabled' => ['required', 'boolean']]);

        $row = $this->moduleRowOrResponse($slug);
        if (! ($row instanceof MaestroModule)) {
            return $row;
        }

        $desired = (bool) $request->boolean('is_enabled');
        $health = (new InstallationHealthService())->moduleReport($slug);
        $installLocked = $this->isInstallLocked($health);
        $isInstallEnabled = (bool) $row->is_install_enabled || $installLocked;

        if ($desired) {
            if ($health['config']['status'] === 'fail') {
                return response()->json([
                    'message' => 'Cannot enable runtime toggle: config check is failing.',
                    'health' => $health,
                ], 422);
            }

            if (! $isInstallEnabled) {
                return response()->json([
                    'message' => 'Enable installation toggle first and run migrations/seeders before enabling runtime.',
                    'health' => $health,
                ], 422);
            }

            $ready = $health['database']['status'] === 'ok'
                && $health['seeder']['status'] === 'ok';
            if (! $ready) {
                return response()->json([
                    'message' => 'Cannot enable runtime yet: database and seeder checks must be green first.',
                    'health' => $health,
                ], 422);
            }
        }

        $row->update(['is_enabled' => $desired]);
        Cache::forget('maestro_module:'.$slug);

        return response()->json([
            'data' => [
                'slug' => $row->slug,
                'label' => $row->label,
                'is_runtime_enabled' => $desired,
                'is_enabled' => $desired,
                'is_install_enabled' => $isInstallEnabled,
                'install_locked' => $installLocked,
            ],
        ]);
    }

    private function moduleRowOrResponse(string $slug): MaestroModule|JsonResponse
    {
        if (! in_array($slug, ModuleDependencyMap::allSlugs(), true)) {
            return response()->json(['message' => 'Unknown module.'], 404);
        }

        $row = MaestroModule::query()->where('slug', $slug)->first();
        if (! $row) {
            return response()->json([
                'message' => 'Module registry row not found. Run the seeders first.',
            ], 422);
        }

        return $row;
    }

    /**
     * @param  array{config:array<string,mixed>,database:array<string,mixed>,seeder:array<string,mixed>,routes:array<string,mixed>,overall:string}  $health
     */
    private function isInstallLocked(array $health): bool
    {
        if ($health['database']['status'] === 'ok') {
            return true;
        }

        return false;
    }
}
