<?php

namespace App\Http\Controllers\Admin;

use App\Http\Controllers\Controller;
use App\Models\Addon;
use App\Services\Addons\AddonInstaller;
use App\Services\Addons\AddonLicenseService;
use App\Services\Addons\AddonManager;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Illuminate\View\View;

class AddonController extends Controller
{
    public function __construct(
        protected AddonManager $manager,
        protected AddonInstaller $installer,
        protected AddonLicenseService $licenses,
    ) {}

    /**
     * List installed addons + render the upload form. The view also surfaces
     * orphan folders (files on disk that aren't in the DB) so the admin can
     * spot a half-finished install.
     *
     * We attach a `license` payload per addon (or null) so the UI can show
     * "Licensed to {buyer} on {date}" vs an "Enter license code" CTA
     * without each row having to query LicenseStorage independently.
     */
    public function index(): View
    {
        AddonManager::ensureRootExists();
        $addons = Addon::orderByDesc('installed_at')->orderBy('name')->get();

        // Single platform-wide MailTrixy license read — every addon
        // inherits from this, so we look it up once for the whole
        // page render rather than per row.
        $platformLicense = $this->licenses->readPlatformLicense();

        return view('admin.addons.index', [
            'addons'          => $addons,
            'platformLicense' => $platformLicense,
        ]);
    }

    /**
     * Verify the platform-wide MailTrixy Envato purchase code from
     * inside the admin panel. Only needed when a customer upgraded
     * an existing install without going through the new installer
     * (so they never saw the license step) — fresh installs already
     * have the license file from InstallController::verifyLicense.
     *
     * Same EnvatoVerifier call, same persisted file path
     * (`storage/app/licenses/main_app_mailtrixy.json`) — so once
     * this returns success every addon's `isLicensed()` flips true.
     */
    public function verifyPlatformLicense(Request $request): RedirectResponse
    {
        $code = trim((string) $request->input('purchase_code', ''));

        if ($code === '') {
            return redirect()->route('admin.addons.index')
                ->with('error', 'Please paste your MailTrixy Envato purchase code.');
        }

        try {
            $license = $this->licenses->verifyPlatformLicense($code);
        } catch (\Throwable $e) {
            Log::warning('Platform license verification failed', [
                'error' => $e->getMessage(),
            ]);
            return redirect()->route('admin.addons.index')
                ->with('error', 'Could not verify license: ' . $e->getMessage());
        }

        $buyer = $license['envato_buyer'] ?: 'Envato buyer';
        return redirect()->route('admin.addons.index')
            ->with('success', "MailTrixy licensed to {$buyer}. All addons are now unlockable.");
    }

    /**
     * Accept the uploaded ZIP, hand it to AddonInstaller, redirect with a
     * status message. Errors are caught and shown as flash messages so the
     * admin sees the actual cause instead of a 500 page.
     */
    public function upload(Request $request): RedirectResponse
    {
        // License gate — refuse to install any new addon ZIP until
        // the platform Envato purchase code has been verified. The UI
        // hides the upload form behind the banner, but a crafted POST
        // could still hit this method; this is the server-side check.
        if (!$this->licenses->isLicensed()) {
            return redirect()->route('admin.addons.index')
                ->with('error', 'Verify your MailTrixy Envato purchase code first — addon installs are locked until then.');
        }

        $request->validate([
            'addon_zip' => 'required|file|mimes:zip|max:51200', // 50 MB cap
        ]);

        try {
            $addon = $this->installer->installFromZip($request->file('addon_zip'));
            return redirect()
                ->route('admin.addons.index')
                ->with('success', "Installed {$addon->name} v{$addon->version}. Click Activate to enable it.");
        } catch (\Throwable $e) {
            Log::warning('Addon install failed', ['error' => $e->getMessage()]);
            return redirect()
                ->route('admin.addons.index')
                ->with('error', 'Install failed: ' . $e->getMessage());
        }
    }

    /**
     * Flip status=active, run the addon's migrations, boot it into the
     * current request so it's usable immediately.
     */
    public function activate(Addon $addon): RedirectResponse
    {
        // License gate — refuse to activate an addon that hasn't had a
        // valid Envato purchase code verified for it. The UI hides the
        // Activate button entirely until a license is on file, but a
        // crafted POST could still reach this method; this is the hard
        // server-side check that pairs with the UI affordance.
        if (!$this->licenses->isLicensed($addon)) {
            return redirect()
                ->route('admin.addons.index')
                ->with('error', "Enter the Envato purchase code for {$addon->name} before activating.");
        }

        try {
            $this->manager->activate($addon);
            return redirect()
                ->route('admin.addons.index')
                ->with('success', "Activated {$addon->name}.");
        } catch (\Throwable $e) {
            Log::error('Addon activate failed', ['slug' => $addon->slug, 'error' => $e->getMessage()]);
            return redirect()
                ->route('admin.addons.index')
                ->with('error', "Could not activate {$addon->name}: " . $e->getMessage());
        }
    }

    public function deactivate(Addon $addon): RedirectResponse
    {
        $this->manager->deactivate($addon);
        return redirect()
            ->route('admin.addons.index')
            ->with('success', "Deactivated {$addon->name}.");
    }

    /**
     * Wipe the addon's folder + DB row. Migrations are intentionally left
     * in place — see AddonManager::uninstall() docblock.
     */
    public function uninstall(Addon $addon): RedirectResponse
    {
        $name = $addon->name;
        try {
            $this->manager->uninstall($addon);
            return redirect()
                ->route('admin.addons.index')
                ->with('success', "Uninstalled {$name}. Database tables created by the addon were left in place — drop them manually if you no longer need the data.");
        } catch (\Throwable $e) {
            Log::error('Addon uninstall failed', ['slug' => $addon->slug, 'error' => $e->getMessage()]);
            return redirect()
                ->route('admin.addons.index')
                ->with('error', "Could not uninstall {$name}: " . $e->getMessage());
        }
    }
}
