<?php

namespace App\Http\Controllers\Admin;

use App\Http\Controllers\Controller;
use App\Models\Module;
use App\Services\ModuleManager;
use App\Services\SchneespurModuleClient;
use App\Services\SchneespurModuleInstaller;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Illuminate\View\View;

class AdminModuleController extends Controller
{
    public function index(SchneespurModuleClient $client): View
    {
        $installed = Module::all()->keyBy('slug');

        $catalogModules = [];
        $catalogError = null;

        try {
            $catalog = $client->fetchCatalog();
            $catalogModules = $catalog['modules'] ?? [];
        } catch (\Throwable $e) {
            Log::warning('schneespur-modules: catalog fetch failed in admin UI', [
                'error' => $e->getMessage(),
            ]);
            $catalogError = $e->getMessage();
        }

        $modules = [];
        foreach ($catalogModules as $catModule) {
            $slug = $catModule['slug'] ?? null;
            if (! $slug) {
                continue;
            }

            $local = $installed->get($slug);
            $modules[$slug] = [
                'slug' => $slug,
                'name' => SchneespurModuleClient::i18nPick($catModule['name'] ?? [], app()->getLocale()),
                'description' => SchneespurModuleClient::i18nPick($catModule['description'] ?? [], app()->getLocale()),
                'catalog_version' => $catModule['version'] ?? null,
                'category' => $catModule['category'] ?? null,
                'image' => $catModule['image'] ?? null,
                'installed' => $local !== null,
                'enabled' => $local?->enabled ?? false,
                'installed_version' => $local?->version,
                'has_update' => $local !== null && isset($catModule['version']) && version_compare($catModule['version'], $local->version, '>'),
                'is_orphan' => false,
                'download_url' => $catModule['download_url'] ?? null,
                'sha256' => $catModule['sha256'] ?? null,
                'size_bytes' => $catModule['size_bytes'] ?? null,
                'requires_permissions' => $catModule['requires_permissions'] ?? [],
            ];
        }

        foreach ($installed as $slug => $local) {
            if (isset($modules[$slug])) {
                continue;
            }
            $modules[$slug] = [
                'slug' => $slug,
                'name' => $local->name ?? $slug,
                'description' => $local->description ?? '',
                'catalog_version' => null,
                'category' => $local->manifest_json['category'] ?? null,
                'image' => $local->manifest_json['image'] ?? null,
                'installed' => true,
                'enabled' => $local->enabled,
                'installed_version' => $local->version,
                'has_update' => false,
                'is_orphan' => true,
                'download_url' => null,
                'sha256' => null,
                'size_bytes' => null,
                'requires_permissions' => $this->resolveLocalPermissions($slug),
            ];
        }

        return view('admin.settings.modules.index', [
            'modules' => $modules,
            'catalogError' => $catalogError,
        ]);
    }

    public function install(Request $request, string $slug, SchneespurModuleClient $client, SchneespurModuleInstaller $installer): RedirectResponse
    {
        $catalog = null;
        try {
            $catalog = $client->fetchCatalog();
        } catch (\Throwable $e) {
            return redirect()->route('admin.settings.modules.index')
                ->with('error', __('modules.catalog_fetch_failed', ['error' => $e->getMessage()]));
        }

        if ($catalog === null) {
            return redirect()->route('admin.settings.modules.index')
                ->with('error', __('modules.catalog_unavailable'));
        }

        $moduleData = collect($catalog['modules'] ?? [])->firstWhere('slug', $slug);
        if (! $moduleData) {
            return redirect()->route('admin.settings.modules.index')
                ->with('error', __('modules.not_found_in_catalog', ['slug' => $slug]));
        }

        try {
            $zipPath = $client->downloadModule(
                $slug,
                $moduleData['download_url'],
                $moduleData['sha256'],
                $moduleData['size_bytes'],
            );

            $success = $installer->install($zipPath, $slug);
        } catch (\Throwable $e) {
            return redirect()->route('admin.settings.modules.index')
                ->with('error', __('modules.install_failed', ['slug' => $slug, 'error' => $e->getMessage()]));
        } finally {
            if (isset($zipPath)) {
                @unlink($zipPath);
            }
        }

        if (! $success) {
            return redirect()->route('admin.settings.modules.index')
                ->with('error', __('modules.install_failed', ['slug' => $slug, 'error' => __('modules.directory_exists')]));
        }

        Module::updateOrCreate(
            ['slug' => $slug],
            [
                'version' => $moduleData['version'] ?? '0.0.0',
                'enabled' => true,
                'manifest_json' => $moduleData,
                'installed_at' => now(),
            ],
        );

        return redirect()->route('admin.settings.modules.index')
            ->with('success', __('modules.installed', ['slug' => $slug]));
    }

    public function update(Request $request, string $slug, SchneespurModuleClient $client, SchneespurModuleInstaller $installer): RedirectResponse
    {
        $catalog = null;
        try {
            $catalog = $client->fetchCatalog();
        } catch (\Throwable $e) {
            return redirect()->route('admin.settings.modules.index')
                ->with('error', __('modules.catalog_fetch_failed', ['error' => $e->getMessage()]));
        }

        if ($catalog === null) {
            return redirect()->route('admin.settings.modules.index')
                ->with('error', __('modules.catalog_unavailable'));
        }

        $moduleData = collect($catalog['modules'] ?? [])->firstWhere('slug', $slug);
        if (! $moduleData) {
            return redirect()->route('admin.settings.modules.index')
                ->with('error', __('modules.not_found_in_catalog', ['slug' => $slug]));
        }

        try {
            $zipPath = $client->downloadModule(
                $slug,
                $moduleData['download_url'],
                $moduleData['sha256'],
                $moduleData['size_bytes'],
            );

            $success = $installer->update($zipPath, $slug);
        } catch (\Throwable $e) {
            return redirect()->route('admin.settings.modules.index')
                ->with('error', __('modules.update_failed', ['slug' => $slug, 'error' => $e->getMessage()]));
        } finally {
            if (isset($zipPath)) {
                @unlink($zipPath);
            }
        }

        if (! $success) {
            return redirect()->route('admin.settings.modules.index')
                ->with('error', __('modules.update_failed', ['slug' => $slug, 'error' => __('modules.extraction_failed')]));
        }

        Module::where('slug', $slug)->update([
            'version' => $moduleData['version'] ?? '0.0.0',
            'manifest_json' => $moduleData,
        ]);

        return redirect()->route('admin.settings.modules.index')
            ->with('success', __('modules.updated', ['slug' => $slug]));
    }

    public function enable(string $slug): RedirectResponse
    {
        $module = Module::where('slug', $slug)->first();

        if (! $module) {
            return redirect()->route('admin.settings.modules.index')
                ->with('error', __('modules.not_installed', ['slug' => $slug]));
        }

        $module->update(['enabled' => true]);

        return redirect()->route('admin.settings.modules.index')
            ->with('success', __('modules.enabled', ['slug' => $slug]));
    }

    public function disable(string $slug): RedirectResponse
    {
        $module = Module::where('slug', $slug)->first();

        if (! $module) {
            return redirect()->route('admin.settings.modules.index')
                ->with('error', __('modules.not_installed', ['slug' => $slug]));
        }

        $module->update(['enabled' => false]);

        return redirect()->route('admin.settings.modules.index')
            ->with('success', __('modules.disabled', ['slug' => $slug]));
    }

    private function resolveLocalPermissions(string $slug): array
    {
        try {
            $manager = app(ModuleManager::class);
            return $manager->getPermissions($slug);
        } catch (\Throwable) {
            return [];
        }
    }

    public function remove(string $slug, SchneespurModuleInstaller $installer): RedirectResponse
    {
        $module = Module::where('slug', $slug)->first();

        if (! $module) {
            return redirect()->route('admin.settings.modules.index')
                ->with('error', __('modules.not_installed', ['slug' => $slug]));
        }

        $module->update(['enabled' => false]);

        $installer->remove($slug);

        $module->delete();

        return redirect()->route('admin.settings.modules.index')
            ->with('success', __('modules.removed', ['slug' => $slug]));
    }
}
