<?php

namespace App\Http\Controllers\Marketplace;

use App\Contracts\InstalledModuleRepositoryContract;
use App\Contracts\ProductOwnerClientContract;
use App\Enums\ModuleStatus;
use App\Http\Controllers\Controller;
use App\Services\Module\ModuleInstallService;
use App\Services\ProductOwner\InstallationSyncService;
use App\Services\Module\ModuleManager;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\View\View;
use RuntimeException;

class MarketplaceController extends Controller
{
    public function __construct(
        private readonly ProductOwnerClientContract $productOwnerClient,
        private readonly InstalledModuleRepositoryContract $installedModules,
        private readonly ModuleInstallService $moduleInstallService,
        private readonly ModuleManager $moduleManager,
        private readonly InstallationSyncService $installationSync,
    ) {}

    public function index(Request $request): View
    {
        $this->authorize('viewAny', MarketplaceController::class);

        $installationId = config('product_owner.installation_id');
        $licenseKey = config('product_owner.license_key');

        $license = null;
        $registrationWarning = null;
        $platformNotice = null;

        if ($licenseKey && $installationId) {
            if (! $this->installationSync->ensureRegistered()) {
                if ($this->installationSync->isPlatformUnavailable()) {
                    $platformNotice = 'Product Owner platform is offline. You can still browse and install modules locally.';
                } else {
                    $registrationWarning = 'This installation is not registered with the Product Owner platform. Check that the Product Owner app is running and your license key is valid.';
                }
            } else {
                $license = $this->productOwnerClient->validateLicense($licenseKey, $installationId);
            }
        }

        $modules = $this->resolveMarketplaceModules();
        $catalogNotice = null;

        if ($modules === [] && $this->moduleManager->discover()->isEmpty()) {
            $catalogNotice = 'No module shells are deployed under apps/admin/modules/. Deploy module shell code (e.g. Finance) so marketplace items can be installed.';
        }

        $installedUuids = $this->installedModules->all()
            ->where('status', ModuleStatus::Installed)
            ->pluck('module_uuid')
            ->all();

        if ($search = $request->string('search')->toString()) {
            $needle = strtolower($search);
            $modules = array_values(array_filter($modules, fn ($m) => str_contains(strtolower($m['name'] ?? ''), $needle)
                || str_contains(strtolower($m['description'] ?? ''), $needle)
                || str_contains(strtolower(strip_tags($m['specs'] ?? '')), $needle)));
        }

        if ($category = $request->string('category')->toString()) {
            $modules = array_values(array_filter($modules, fn ($m) => strtolower((string) ($m['category'] ?? '')) === strtolower($category)
                || strtolower((string) ($m['category_slug'] ?? '')) === strtolower($category)));
        }

        $categories = collect($modules)
            ->pluck('category')
            ->filter()
            ->unique()
            ->sort()
            ->values()
            ->all();

        return view('marketplace.index', [
            'license' => $license,
            'modules' => $modules,
            'categories' => $categories,
            'installedUuids' => $installedUuids,
            'installedModules' => $this->installedModules->all()
                ->where('status', ModuleStatus::Installed)
                ->values(),
            'registrationWarning' => $registrationWarning,
            'platformNotice' => $platformNotice,
            'catalogNotice' => $catalogNotice,
        ]);
    }

    /**
     * @return list<array<string, mixed>>
     */
    private function resolveMarketplaceModules(): array
    {
        $remoteModules = $this->productOwnerClient->listMarketplaceModules();
        $platformUnavailable = $remoteModules === [] && $this->installationSync->isPlatformUnavailable();

        if ($platformUnavailable) {
            return $this->moduleManager->localMarketplaceCatalog();
        }

        $modules = [];

        foreach ($remoteModules as $remoteModule) {
            $definition = $this->moduleManager->findByUuid($remoteModule['uuid'] ?? '');

            if ($definition === null) {
                continue;
            }

            $modules[] = array_merge(
                $this->moduleManager->localMarketplaceCatalogEntry($definition),
                $remoteModule,
            );
        }

        if ($modules !== []) {
            return $modules;
        }

        $localModules = $this->moduleManager->localMarketplaceCatalog();

        if ($localModules === []) {
            return [];
        }

        return array_values(array_map(function (array $localModule) use ($remoteModules) {
            $remote = collect($remoteModules)->firstWhere('uuid', $localModule['uuid'] ?? '');

            return $remote ? array_merge($localModule, $remote) : $localModule;
        }, $localModules));
    }

    public function show(string $moduleUuid): View
    {
        $this->authorize('view', MarketplaceController::class);

        return view('marketplace.show', [
            'moduleUuid' => $moduleUuid,
        ]);
    }

    public function install(string $moduleUuid): RedirectResponse
    {
        $this->authorize('install', MarketplaceController::class);

        try {
            $this->moduleInstallService->install($moduleUuid);
        } catch (RuntimeException $exception) {
            return back()->with('error', $exception->getMessage());
        }

        $message = $this->installationSync->isPlatformUnavailable()
            ? 'Module installed locally. Sync with Product Owner when the platform is online.'
            : 'Module installed successfully.';

        return redirect()->route('marketplace.index')->with('success', $message);
    }
}
