<?php

namespace ViartasThemes\Protera\Providers;

use Illuminate\Pagination\Paginator;
use ViartasCore\Core\Providers\BaseThemeServiceProvider;
use ViartasCore\Themes\ThemeBuilder\ThemeBuilderRegistry;
use ViartasThemes\Protera\Console\Commands\InstallCommand;
use ViartasThemes\Protera\ThemeBuilder\CustomHtmlSection;
use ViartasThemes\Protera\ThemeBuilder\DividerSection;
use ViartasThemes\Protera\ThemeBuilder\ManifestoPullquoteSection;

/**
 * Protera theme service provider — public web storefront customisations.
 *
 * Boot order contract (preserved from legacy themes/Web/Protera/Providers/):
 * The Paginator override MUST win over AppServiceProvider::boot()'s
 * `Paginator::useBootstrapFive()`. As a host app provider (bootstrap/
 * providers.php) Protera used to boot AFTER AppServiceProvider, so a plain
 * boot() override won. As a Composer auto-discovered package provider this no
 * longer holds: PackageManifest providers are spliced AHEAD of the app
 * providers in Application::registerConfiguredProviders(), so this provider
 * now boots BEFORE AppServiceProvider — a plain boot() would be overwritten by
 * useBootstrapFive(). We therefore defer the override to `$this->app->booted()`,
 * whose callbacks fire AFTER every provider's boot() has completed.
 * `Paginator::$defaultView` is a static — last-set wins for the rest of the PHP
 * process lifetime — so the deferred override holds.
 *
 * The `theme::components.pagination` namespaced view resolves per-request
 * through the active theme: ResolveTheme middleware registers `theme::` via
 * `View::addNamespace()` pointing at the active theme's `Resources/views`
 * directory. On web requests Protera is active → renders the brand-styled
 * pagination. On admin requests ViartasDefault is active → renders a thin
 * wrapper that `@include`s `pagination::bootstrap-5`, preserving the existing
 * admin look.
 */
class ThemeServiceProvider extends BaseThemeServiceProvider
{
    protected string $themeName = 'Protera';

    protected string $env = 'web';

    /**
     * Boot the theme — register per-route assets (when active), migrations, the
     * publish targets, and the Protera-specific Paginator override.
     *
     * task-20: parent::boot() now gates asset/view registration on the
     * DB-resolved active theme (Core ViartasCore\Core\Services\Themes\ThemeManager
     * ::active() reads `themes.active.name.web` from the DB). When Protera is the
     * default web theme the gate passes and registers web.css/web.js; when another
     * web theme (e.g. Cleverphant) is activated the gate correctly SKIPS Protera,
     * so its CSS no longer leaks alongside the active theme.
     *
     * The previous UNCONDITIONAL $this->registerAssets() workaround — needed only
     * while the Core gate was config-stuck (its setActive() was never called by
     * the runtime resolver) — is now obsolete and removed, so a DB `is_default`
     * flip is a CLEAN asset switch. Even when the DB is unreachable at boot the
     * gate still passes for Protera, because active() falls back to the config
     * seed which is 'Protera' — the storefront never goes unstyled.
     */
    public function boot(): void
    {
        // Gated asset/view registration — registers Protera's web.* CSS/JS only
        // while Protera is the active web theme (see method docblock).
        parent::boot();

        // Storefront paginator override — see class-level docblock for the
        // boot-order contract. Deferred to app()->booted() so it lands AFTER
        // AppServiceProvider::boot()'s Paginator::useBootstrapFive() (this
        // auto-discovered provider boots BEFORE the host app providers). Both
        // default and simple views route through the active theme's
        // `theme::components.{pagination,simple-pagination}`.
        $this->app->booted(function (): void {
            Paginator::defaultView('theme::components.pagination');
            Paginator::defaultSimpleView('theme::components.simple-pagination');
        });

        // NO Database/Migrations — deliberately, and this theme now has none at all.
        // The task-116c `themes.path` cut-over moved to va-core/themes in
        // PackageStructure/task-22: it writes the `themes` table, and that table is
        // created by va-core/themes (.claude/module-structure.md §5 — a theme may not
        // own migrations, because the table belongs to whoever defines it). The file
        // NAME is unchanged, so the `migrations` ledger still recognises it as ran.

        // Register the `protera::` translation namespace UNCONDITIONALLY so the
        // builder admin (admin env, where ViartasDefault — not Protera — is the
        // active theme) can still resolve our section labels via
        // __('protera::sections.*.label'). parent::boot() only registers it when
        // the (unwired) Core active-theme gate happens to equal 'Protera';
        // registering again here is harmless (duplicate hint paths merge) and
        // guarantees resolution regardless of gate state — cleverphant task-18
        // precedent.
        $langPath = $this->themePath('Resources/lang');
        if (is_dir($langPath)) {
            $this->loadTranslationsFrom($langPath, 'protera');
        }

        // Theme Page Builder — Protera contributes 3 visual-only sections
        // (Divider, Manifesto pullquote, Custom HTML). This shows that a THEME,
        // not only a domain module, can register builder sections; they live in
        // this package (src/ThemeBuilder/) and render through `theme::sections.*`.
        //
        // Wrapped in app()->booted(): as a Composer auto-discovered provider this
        // boots BEFORE the host app providers (task-116a Risk #1), so the
        // 'theme.builder' singleton may not exist yet at boot() time — booted()
        // callbacks fire after every provider has registered. The class_exists
        // guard keeps the theme dependency on the builder foundation SOFT.
        //
        // Registration is unconditional (matches the foundation's process-wide
        // singleton model + the task-2 demo section): the sections are always in
        // the registry, but only RENDER on web where Protera is the active theme
        // (render() resolves views via the `theme::` namespace, which points at
        // Protera only on web requests). The hasSection() guard makes repeated
        // boots (e.g. the test suite) idempotent instead of throwing on the
        // registry's duplicate-key RuntimeException.
        if (class_exists(ThemeBuilderRegistry::class)) {
            $this->app->booted(function (): void {
                $registry = app('theme.builder');

                foreach ([
                    DividerSection::class,
                    ManifestoPullquoteSection::class,
                    CustomHtmlSection::class,
                ] as $sectionClass) {
                    if (! $registry->hasSection((new $sectionClass)->key())) {
                        $registry->registerSection($sectionClass);
                    }
                }
            });
        }

        if ($this->app->runningInConsole()) {
            // Tyre-demo restore + Protera activate helper (task-30). The mirror
            // of cleverphant:install — manual only, drives the existing demo
            // seeders and flips Protera back to the default web theme.
            $this->commands([
                InstallCommand::class,
            ]);

            // Vite build output → public/vendor/va-themes/protera/build/.
            $this->publishes([
                $this->themePath('public/build') => public_path('vendor/va-themes/protera/build'),
            ], 'va-themes-protera-assets');

            // Static images (NOT Vite-built — referenced via asset() in blades).
            $this->publishes([
                $this->themePath('Resources/assets/images') => public_path('vendor/va-themes/protera/images'),
            ], 'va-themes-protera-images');
        }
    }

    /**
     * Per-route asset map — web CSS + JS bundles for every `web.*` route.
     *
     * `file` is relative to public/vendor/{vendor}/ (the @assets() directive
     * prepends `vendor/{vendor}/`), so it points at the published build output.
     *
     * Only web.css + catalog-browsing.css are emitted: search-suggest.css,
     * header-search.css and grid-frontend.css are bundled INTO web.css by the
     * per-package Vite build (web.js imports them transitively — see
     * vite.config.js), mirroring the legacy root @vite() loading.
     *
     * @return array<string, mixed>
     */
    protected function assets(): array
    {
        return [
            'css' => [
                'web.*' => [
                    ['vendor' => 'va-themes/protera', 'file' => 'build/assets/web.css',              'type' => 'script'],
                    ['vendor' => 'va-themes/protera', 'file' => 'build/assets/catalog-browsing.css', 'type' => 'script'],
                ],

                /*
                 | SystemFindings/task-15 — the auth shell, lifted out of
                 | `protera::layouts.auth`'s inline <style>.
                 |
                 | 🔑 TIER `module` (2), NOT `script` (1), AND THAT IS THE WHOLE
                 | POINT. The inline block sat AFTER @cmsAssets('css'), so it won
                 | every specificity tie against web.css — which is what
                 | `.auth-card .form-control` and the rest rely on.
                 | AssetRegistry::orderByType emits script before module, so tier
                 | 2 reproduces that. Same tier for both would leave the winner
                 | to declaration order inside one provider: a coin flip nobody
                 | would notice flipping.
                 |
                 | The glob is `web.*auth.*` rather than `web.*`: this sheet
                 | restyles bare `body` (100vh flex column on a gradient) and has
                 | no business on a catalogue page. `*` spans dots in fnmatch, so
                 | it covers `web.en.auth.login` too.
                 */
                'web.*auth.*' => [
                    ['vendor' => 'va-themes/protera', 'file' => 'build/assets/auth.css', 'type' => 'module'],
                ],
            ],
            'js' => [
                'web.*' => [
                    ['vendor' => 'va-themes/protera', 'file' => 'build/assets/web.js',              'type' => 'module'],
                    ['vendor' => 'va-themes/protera', 'file' => 'build/assets/catalog-browsing.js', 'type' => 'module'],
                ],
            ],
        ];
    }

    /**
     * View override map — populated by task-116c.
     *
     * @return array<string, mixed>
     */
    protected function views(): array
    {
        return [];
    }

    /**
     * Controller override map — populated by task-116c if needed.
     *
     * @return array<string, mixed>
     */
    protected function controllers(): array
    {
        return [];
    }

    /**
     * Absolute path into this package's root directory.
     *
     * @param  string  $relative  Path relative to the package root.
     */
    protected function themePath(string $relative = ''): string
    {
        return __DIR__.'/../../'.ltrim($relative, '/');
    }
}
