<?php

namespace Modules\ClinicLab\Http\Controllers;

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

/**
 * Install / update the ClinicLab lab-upgrade (SIFA P4-T4).
 *
 * ClinicLab historically installed with NO version gate — its provider just
 * auto-loaded views + migrations, and route/menu visibility rode on the
 * SaasSwitcher `module_entitled('ClinicLab')` entitlement. But the ERP's
 * ModuleUtil::getModuleData() (which surfaces user_permissions() and
 * modifyAdminMenu() from a module's DataController) gates on
 * isModuleInstalled() → System::getProperty('cliniclab_version'). So to make
 * the new Catalog/Specimens/Reviews/Outreach menu + permissions appear, the
 * lowercase `cliniclab_version` system property MUST be set. This controller
 * writes it, following the LabCore InstallController convention verbatim.
 */
class InstallController extends Controller
{
    private $module_name;
    private $app_version;

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

    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(strtolower($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]);
            Artisan::call('module:seed', ['module' => $this->module_name]);
            System::addProperty(strtolower($this->module_name) . '_version', $this->app_version);
            $this->assignPermissionsToAdmin();
        }

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

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

    public function install()
    {
        if (!auth()->user()->can('superadmin')) {
            abort(403, 'Unauthorized action.');
        }

        try {
            $is_installed = System::getProperty(strtolower($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(strtolower($this->module_name) . '_version', $this->app_version);
            // Seed the catalog/outreach demo (env-guarded in the seeder, so this is
            // a no-op in production). Mirrors index()'s install path.
            Artisan::call('module:seed', ['module' => $this->module_name]);
            $this->assignPermissionsToAdmin();

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

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

    public function update()
    {
        if (!auth()->user()->can('superadmin')) {
            abort(403, 'Unauthorized action.');
        }

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

            Artisan::call('module:migrate', ['module' => $this->module_name]);
            System::setProperty(strtolower($this->module_name) . '_version', $this->app_version);
            $this->assignPermissionsToAdmin();

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

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

    public function uninstall()
    {
        if (!auth()->user()->can('superadmin')) {
            abort(403, 'Unauthorized action.');
        }

        try {
            System::removeProperty(strtolower($this->module_name) . '_version');
            $output = ['success' => 1, 'msg' => 'ClinicLab module uninstalled successfully'];
        } catch (\Exception $e) {
            \Log::emergency('File:' . $e->getFile() . ' Line:' . $e->getLine() . ' Message:' . $e->getMessage());
            $output = ['success' => 0, 'msg' => $e->getMessage()];
        }

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

    /**
     * Re-run migrations to repair a partially installed module.
     */
    public function repair()
    {
        if (!auth()->user()->can('superadmin')) {
            abort(403, 'Unauthorized action.');
        }

        ini_set('max_execution_time', 0);
        Artisan::call('module:migrate', ['module' => $this->module_name]);
        // Re-seed the catalog/outreach demo (env-guarded + idempotent) so a
        // repair restores demo data. No-op in production.
        Artisan::call('module:seed', ['module' => $this->module_name]);
        $this->assignPermissionsToAdmin();

        $output = ['success' => 1, 'msg' => 'ClinicLab module repaired'];

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

    /**
     * Grant every ClinicLab lab-upgrade permission to the current business
     * Admin role (Admin#{business_id}), matching the LabCore convention.
     */
    private function assignPermissionsToAdmin(): void
    {
        $permissions = [
            'cliniclab.catalog.manage',
            'cliniclab.specimen.manage',
            'cliniclab.result.review',
            'cliniclab.result.verify',
            'cliniclab.outreach.manage',
        ];

        foreach ($permissions as $permission) {
            Permission::firstOrCreate(['name' => $permission, 'guard_name' => 'web']);
        }

        $business_id = request()->session()->get('user.business_id');
        if (!empty($business_id)) {
            $role = Role::where('name', 'Admin#' . $business_id)->first();
            if ($role) {
                $role->givePermissionTo($permissions);
            }
        }
    }
}
