<?php

declare(strict_types=1);

namespace Maestro\Core\Services;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use Maestro\Core\Models\MaestroAppSetting;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;

final class PublicPageHealthService
{
    /**
     * @return array{
     *   route:string,
     *   status:'ok'|'warn'|'fail',
     *   status_detail:string,
     *   checks:list<array{id:string,label:string,status:'ok'|'warn'|'fail',detail:string,commands:list<string>}>
     * }
     */
    public function report(): array
    {
        $row = MaestroAppSetting::instance();
        $settings = is_array($row->public_page) ? $row->public_page : [];
        $enabled = (bool) ($settings['enabled'] ?? false);
        $mode = isset($settings['mode']) && is_string($settings['mode'])
            ? $settings['mode']
            : 'core_default';

        $checks = [
            $this->rootRouteCheck($enabled),
            $this->namedRouteCheck(),
            $this->viewCheck(),
            $this->viteEntryCheck(),
            $this->customerOverrideCheck($mode),
        ];

        $status = $this->overallFromChecks($checks);
        $statusDetail = match ($status) {
            'ok' => 'Public homepage looks correctly wired.',
            'warn' => 'Public homepage is partially configured.',
            default => 'Public homepage is misconfigured for current settings.',
        };

        return [
            'route' => '/',
            'status' => $status,
            'status_detail' => $statusDetail,
            'checks' => $checks,
        ];
    }

    /**
     * @return array{id:string,label:string,status:'ok'|'warn'|'fail',detail:string,commands:list<string>}
     */
    private function rootRouteCheck(bool $enabled): array
    {
        try {
            $route = Route::getRoutes()->match(Request::create('/', 'GET'));
        } catch (NotFoundHttpException) {
            return $this->result(
                'root-route-explicit',
                'Explicit `/` route before SPA catch-all',
                $enabled ? 'fail' : 'warn',
                'No GET route for `/` was found in the host application.',
                ['Add Route::view("/", "public-home")->name("public.home"); in routes/web.php'],
            );
        }
        $uri = $route->uri();

        if ($uri === '{any?}') {
            return $this->result(
                'root-route-explicit',
                'Explicit `/` route before SPA catch-all',
                $enabled ? 'fail' : 'warn',
                'Root URL resolves to the SPA catch-all instead of a dedicated public route.',
                ['Add Route::view("/", "public-home")->name("public.home"); above the catch-all in routes/web.php'],
            );
        }

        return $this->result(
            'root-route-explicit',
            'Explicit `/` route before SPA catch-all',
            'ok',
            sprintf('Root route resolves to `%s`.', $uri),
            [],
        );
    }

    /**
     * @return array{id:string,label:string,status:'ok'|'warn'|'fail',detail:string,commands:list<string>}
     */
    private function namedRouteCheck(): array
    {
        if (! Route::has('public.home')) {
            return $this->result(
                'public-home-name',
                'Named route `public.home`',
                'warn',
                'No named route `public.home` found.',
                ['php artisan route:list | rg public.home'],
            );
        }

        $named = Route::getRoutes()->getByName('public.home');
        if ($named === null || $named->uri() !== '/') {
            return $this->result(
                'public-home-name',
                'Named route `public.home`',
                'warn',
                'Named route exists but does not point to `/`.',
                ['php artisan route:list | rg public.home'],
            );
        }

        return $this->result(
            'public-home-name',
            'Named route `public.home`',
            'ok',
            'Route `public.home` points to `/`.',
            [],
        );
    }

    /**
     * @return array{id:string,label:string,status:'ok'|'warn'|'fail',detail:string,commands:list<string>}
     */
    private function viewCheck(): array
    {
        if (! view()->exists('public-home')) {
            return $this->result(
                'public-home-view',
                'Blade host view `public-home`',
                'warn',
                'The host view `resources/views/public-home.blade.php` was not found.',
                ['Create resources/views/public-home.blade.php with #public-app mount target'],
            );
        }

        return $this->result(
            'public-home-view',
            'Blade host view `public-home`',
            'ok',
            'Blade view `public-home` is available.',
            [],
        );
    }

    /**
     * @return array{id:string,label:string,status:'ok'|'warn'|'fail',detail:string,commands:list<string>}
     */
    private function viteEntryCheck(): array
    {
        if (! is_readable(resource_path('js/public-home.js'))) {
            return $this->result(
                'public-home-vite-entry',
                'Vite entry `resources/js/public-home.js`',
                'warn',
                'Public Vue entry file is missing.',
                ['Create resources/js/public-home.js and mount @maestro/core mountPublicHome()'],
            );
        }

        return $this->result(
            'public-home-vite-entry',
            'Vite entry `resources/js/public-home.js`',
            'ok',
            'Public Vue entry file is present.',
            [],
        );
    }

    /**
     * @return array{id:string,label:string,status:'ok'|'warn'|'fail',detail:string,commands:list<string>}
     */
    private function customerOverrideCheck(string $mode): array
    {
        if ($mode !== 'customer_override') {
            return $this->result(
                'public-home-override',
                'Customer override component',
                'ok',
                'Mode is `core_default`; customer override is optional.',
                [],
            );
        }

        if (! is_readable(resource_path('js/public/PublicHome.vue'))) {
            return $this->result(
                'public-home-override',
                'Customer override component',
                'fail',
                'Mode is `customer_override` but `resources/js/public/PublicHome.vue` is missing.',
                ['Create resources/js/public/PublicHome.vue and import it in resources/js/public-home.js'],
            );
        }

        return $this->result(
            'public-home-override',
            'Customer override component',
            'ok',
            'Customer override component is present.',
            [],
        );
    }

    /**
     * @param  list<array{id:string,label:string,status:'ok'|'warn'|'fail',detail:string,commands:list<string>}>  $checks
     * @return 'ok'|'warn'|'fail'
     */
    private function overallFromChecks(array $checks): string
    {
        $status = 'ok';
        foreach ($checks as $check) {
            if ($check['status'] === 'fail') {
                return 'fail';
            }
            if ($check['status'] === 'warn') {
                $status = 'warn';
            }
        }

        return $status;
    }

    /**
     * @return array{id:string,label:string,status:'ok'|'warn'|'fail',detail:string,commands:list<string>}
     */
    private function result(
        string $id,
        string $label,
        string $status,
        string $detail,
        array $commands,
    ): array {
        return [
            'id' => $id,
            'label' => $label,
            'status' => $status,
            'detail' => $detail,
            'commands' => $commands,
        ];
    }
}
