<?php

namespace Modules\ActivityLog\Http\Controllers;

use App\Http\Controllers\Controller;
use App\System;
use Composer\Semver\Comparator;
use Illuminate\Http\RedirectResponse;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\DB;
use Spatie\Permission\Models\Permission;
use Spatie\Permission\Models\Role;

class InstallController extends Controller
{
    private string $module_name;
    private string $app_version;

    public function __construct()
    {
        $this->module_name = config('activitylog.name');
        $this->app_version = config('activitylog.module_version');
    }

    /**
     * Show install page / trigger install on first visit.
     */
    public function index(): RedirectResponse
    {
        if (!auth()->user()->can('superadmin')) {
            abort(403, 'Unauthorized action.');
        }

        ini_set('max_execution_time', 0);
        ini_set('memory_limit', '512M');

        $this->installSettings();

        $is_installed = System::getProperty($this->module_name . '_version');

        if (empty($is_installed)) {
            DB::statement('SET default_storage_engine=INNODB;');
            Artisan::call('module:migrate', ['module' => $this->module_name]);
            Artisan::call('module:publish', ['module' => $this->module_name]);
            System::addProperty($this->module_name . '_version', $this->app_version);
            $this->assignPermissionsToAdmin();
        }

        $output = [
            'success' => 1,
            'msg'     => 'Activity Log module installed successfully',
        ];

        return redirect()
            ->action('\App\Http\Controllers\Install\ModulesController@index')
            ->with('status', $output);
    }

    /**
     * Full install with DB transaction (called via POST from install page).
     */
    public function install(): RedirectResponse
    {
        if (!auth()->user()->can('superadmin')) {
            abort(403, 'Unauthorized action.');
        }

        try {
            DB::beginTransaction();

            $is_installed = System::getProperty($this->module_name . '_version');
            if (!empty($is_installed)) {
                abort(404);
            }

            ini_set('max_execution_time', 0);
            ini_set('memory_limit', '512M');

            DB::statement('SET default_storage_engine=INNODB;');
            Artisan::call('module:migrate', ['module' => $this->module_name]);
            Artisan::call('module:publish', ['module' => $this->module_name]);
            System::addProperty($this->module_name . '_version', $this->app_version);
            $this->assignPermissionsToAdmin();

            DB::commit();

            $output = [
                'success' => 1,
                'msg'     => 'Activity Log module installed successfully',
            ];
        } catch (\Exception $e) {
            DB::rollBack();
            \Log::emergency('File:' . $e->getFile() . ' Line:' . $e->getLine() . ' Message:' . $e->getMessage());

            $output = [
                'success' => false,
                'msg'     => $e->getMessage(),
            ];
        }

        return redirect()
            ->action('\App\Http\Controllers\Install\ModulesController@index')
            ->with('status', $output);
    }

    /**
     * Uninstall: remove version record (does not drop tables).
     */
    public function uninstall(): RedirectResponse
    {
        if (!auth()->user()->can('superadmin')) {
            abort(403, 'Unauthorized action.');
        }

        try {
            System::removeProperty($this->module_name . '_version');

            $output = [
                'success' => true,
                'msg'     => 'Activity Log module uninstalled successfully',
            ];
        } catch (\Exception $e) {
            $output = [
                'success' => false,
                'msg'     => $e->getMessage(),
            ];
        }

        return redirect()->back()->with(['status' => $output]);
    }

    /**
     * Update: run new migrations if a newer version is available.
     */
    public function update(): RedirectResponse
    {
        if (!auth()->user()->can('superadmin')) {
            abort(403, 'Unauthorized action.');
        }

        try {
            DB::beginTransaction();

            $installed_version = System::getProperty($this->module_name . '_version');

            if (Comparator::greaterThan($this->app_version, $installed_version)) {
                ini_set('max_execution_time', 0);
                ini_set('memory_limit', '512M');

                config(['app.debug' => true]);
                Artisan::call('config:clear');
                Artisan::call('cache:clear');

                DB::statement('SET default_storage_engine=INNODB;');
                Artisan::call('module:migrate', ['module' => $this->module_name]);
                Artisan::call('module:publish', ['module' => $this->module_name]);
                System::setProperty($this->module_name . '_version', $this->app_version);
                $this->assignPermissionsToAdmin();
            } else {
                abort(404);
            }

            DB::commit();

            $output = [
                'success' => 1,
                'msg'     => 'Activity Log module updated successfully to version ' . $this->app_version . '!',
            ];

            return redirect()->back()->with(['status' => $output]);
        } catch (\Exception $e) {
            DB::rollBack();
            \Log::emergency('File:' . $e->getFile() . ' Line:' . $e->getLine() . ' Message:' . $e->getMessage());

            $output = [
                'success' => false,
                'msg'     => $e->getMessage(),
            ];

            return redirect()->back()->with(['status' => $output]);
        }
    }

    /**
     * Assign all activity_log.* permissions to every Admin role in the system.
     * Uses LIKE 'Admin#%' to cover all business-specific admin roles.
     */
    private function assignPermissionsToAdmin(): void
    {
        try {
            $permissions = Permission::where('name', 'LIKE', 'activity_log.%')->get();

            if ($permissions->isEmpty()) {
                return;
            }

            // Cover all business-specific admin roles: Admin#1, Admin#2, etc.
            $adminRoles = Role::where('name', 'LIKE', 'Admin#%')->get();

            foreach ($adminRoles as $role) {
                foreach ($permissions as $permission) {
                    if (!$role->hasPermissionTo($permission)) {
                        $role->givePermissionTo($permission);
                    }
                }
            }
        } catch (\Exception $e) {
            \Log::warning('Could not assign activity_log permissions to Admin roles: ' . $e->getMessage());
        }
    }

    private function installSettings(): void
    {
        config(['app.debug' => true]);
        Artisan::call('config:clear');
    }
}
