<?php

namespace App\Services\Module;

use App\Contracts\InstalledModuleRepositoryContract;
use App\Enums\ModuleStatus;
use App\Models\InstalledModule;
use App\Services\Audit\AuditLogService;
use App\Services\Permission\PermissionRegistry;
use Illuminate\Support\Facades\Artisan;
use RuntimeException;

class ModuleUninstallService
{
    public function __construct(
        private readonly InstalledModuleRepositoryContract $installedModules,
        private readonly ModuleManager $moduleManager,
        private readonly PermissionRegistry $permissionRegistry,
        private readonly AuditLogService $auditLog,
    ) {}

    public function uninstall(InstalledModule $module): void
    {
        if ($module->status !== ModuleStatus::Installed) {
            throw new RuntimeException('This module is not currently installed.');
        }

        $this->performUninstall($module);
    }

    public function uninstallAll(bool $force = false): int
    {
        $uninstalled = 0;

        foreach ($this->installedModules->all() as $module) {
            if ($module->status !== ModuleStatus::Installed) {
                continue;
            }

            try {
                $this->performUninstall($module);
            } catch (\Throwable $exception) {
                if (! $force) {
                    throw $exception;
                }

                $this->installedModules->delete($module);
            }

            $uninstalled++;
        }

        return $uninstalled;
    }

    private function performUninstall(InstalledModule $module): void
    {
        $definition = $this->moduleManager->findByUuid($module->module_uuid);

        if ($definition && ! $definition->isShell()) {
            $this->rollbackMigrations($definition);
        }

        if ($definition) {
            $this->permissionRegistry->revokeModulePermissions(array_keys($definition->permissions()));
        }

        $this->installedModules->delete($module);

        $this->auditLog->log('module.uninstalled', null, [
            'module_uuid' => $module->module_uuid,
            'module_name' => $module->name,
            'module_version' => $module->version,
        ]);
    }

    private function rollbackMigrations(ModuleDefinition $definition): void
    {
        $absolutePath = $definition->path.'/database/migrations';

        if (! is_dir($absolutePath)) {
            return;
        }

        $relativePath = str_replace(base_path().DIRECTORY_SEPARATOR, '', $absolutePath);

        Artisan::call('migrate:rollback', [
            '--path' => $relativePath,
            '--force' => true,
        ]);
    }
}
