<?php

namespace Modules\LandedCost\Http\Controllers;

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

class InstallController extends Controller
{
    /** @var string */
    private $module_name;

    /** @var string */
    private $app_version;

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

    /**
     * Install (entry point used by the module-management page).
     *
     * @return RedirectResponse
     */
    public function index()
    {
        if (!auth()->user()->can('superadmin')) {
            abort(403, 'Unauthorized action.');
        }

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

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

        $is_installed = System::getProperty($this->module_name . '_version');
        if (empty($is_installed)) {
            // DDL auto-commits in MySQL — run outside any transaction.
            DB::statement('SET default_storage_engine=INNODB;');
            // Migrations are all guarded (hasTable/hasColumn) so this is safe even if
            // the tables were already created manually.
            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' => 'Landed Cost module installed successfully'];

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

    /**
     * Installing module (POST entry).
     *
     * @return RedirectResponse
     */
    public function install()
    {
        if (!auth()->user()->can('superadmin')) {
            abort(403, 'Unauthorized action.');
        }

        try {
            $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();

            $output = ['success' => 1, 'msg' => 'Landed Cost module installed successfully'];
        } catch (\Exception $e) {
            \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);
    }

    /**
     * Update — migrations are idempotent, so just re-run and bump the version.
     *
     * @return RedirectResponse
     */
    public function update()
    {
        if (!auth()->user()->can('superadmin')) {
            abort(403, 'Unauthorized action.');
        }

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

            $installed = System::getProperty($this->module_name . '_version');
            if (!empty($installed) && !Comparator::greaterThan($this->app_version, $installed)) {
                abort(404);
            }

            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();

            $output = ['success' => 1, 'msg' => 'Landed Cost module updated to version ' . $this->app_version . '!'];
        } catch (\Exception $e) {
            \Log::emergency('File:' . $e->getFile() . ' Line:' . $e->getLine() . ' Message:' . $e->getMessage());
            $output = ['success' => false, 'msg' => $e->getMessage()];
        }

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

    /**
     * Repair — force re-run all module migrations and re-assign permissions.
     *
     * @return RedirectResponse
     */
    public function repair()
    {
        if (!auth()->user()->can('superadmin')) {
            abort(403, 'Unauthorized action.');
        }

        try {
            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();

            $output = ['success' => 1, 'msg' => 'Landed Cost module repaired successfully!'];
        } catch (\Exception $e) {
            \Log::emergency('File:' . $e->getFile() . ' Line:' . $e->getLine() . ' Message:' . $e->getMessage());
            $output = ['success' => false, 'msg' => $e->getMessage()];
        }

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

    /**
     * Uninstall — just remove the version flag (keeps data; module can be re-installed).
     *
     * @return RedirectResponse
     */
    public function uninstall()
    {
        if (!auth()->user()->can('superadmin')) {
            abort(403, 'Unauthorized action.');
        }

        try {
            System::removeProperty($this->module_name . '_version');
            $output = ['success' => true, 'msg' => __('lang_v1.success')];
        } catch (\Exception $e) {
            $output = ['success' => false, 'msg' => $e->getMessage()];
        }

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

    /**
     * Grant the landed_cost.manage permission to Admin role(s).
     */
    private function assignPermissionsToAdmin()
    {
        try {
            $permissions = [
                Permission::findOrCreate('landed_cost.manage', 'web'),
                Permission::findOrCreate('landed_cost.apply', 'web'),
            ];

            $adminRoles = Role::where('name', 'like', 'Admin%')->get();
            foreach ($adminRoles as $adminRole) {
                foreach ($permissions as $permission) {
                    if (!$adminRole->hasPermissionTo($permission)) {
                        $adminRole->givePermissionTo($permission);
                    }
                }
            }
        } catch (\Exception $e) {
            \Log::warning('Could not assign landed_cost permissions to Admin role: ' . $e->getMessage());
        }
    }
}
