<?php

namespace Modules\DemoLogin\Http\Controllers;

use App\Business;
use App\User;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Str;
use Modules\SaasSwitcher\Support\ProjectRegistry;
use Spatie\Permission\Models\Permission;
use Spatie\Permission\Models\Role;

/**
 * Demo-only passwordless quick-login. Lists each SaaS project with curated role
 * cards; clicking a role signs you in as a demo user holding that role inside
 * the project's database.
 *
 * Hard-gated by config('demologin.enabled') (env DEMO_LOGIN) — 404s otherwise,
 * so it can never be used on a real deployment. Reuses the SaasSwitcher project
 * registry + the session keys its ResolveProjectConnection middleware reads, so
 * the default DB connection follows the chosen project for the whole session.
 */
class DemoLoginController extends Controller
{
    private function guard(): void
    {
        abort_unless(config('demologin.enabled'), 404);
    }

    /** Landing chooser: one card per project, each linking to its own demo page. */
    public function index()
    {
        $this->guard();

        return view('demologin::index', ['projects' => ProjectRegistry::all()]);
    }

    /** A single project's page: a normal-login button + that project's role cards. */
    public function project(string $project)
    {
        $this->guard();
        abort_unless(ProjectRegistry::exists($project), 404);

        $proj     = ProjectRegistry::get($project);
        $vertical = $proj['vertical'] ?? config('demologin.default_vertical');

        return view('demologin::project', [
            'projectKey' => $project,
            'project'    => $proj,
            'vertical'   => $vertical,
            'roles'      => config("demologin.role_sets.$vertical", []),
        ]);
    }

    /** Sign in as a demo user of {role} inside {project}. */
    public function login(Request $request, string $project, string $role)
    {
        $this->guard();

        abort_unless(ProjectRegistry::exists($project), 404);
        $proj = ProjectRegistry::get($project);
        $conn = $proj['connection'] ?? null;
        abort_unless($conn, 404);

        $vertical = $proj['vertical'] ?? config('demologin.default_vertical');
        $roleDef  = collect(config("demologin.role_sets.$vertical", []))->firstWhere('key', $role);
        abort_unless($roleDef, 404);

        // Operate inside the project's database for the whole sign-in.
        DB::setDefaultConnection($conn);

        $business = Business::on($conn)->orderBy('id')->first();
        abort_unless($business, 404, 'No business in this project.');
        $businessId = (int) $business->id;

        // Ensure the role exists (clinic/vet seeders + UltimatePOS defaults
        // normally provide it; firstOrCreate keeps the page working regardless).
        $roleName = $roleDef['role'] . '#' . $businessId;
        $roleModel = Role::firstOrCreate(
            ['name' => $roleName, 'guard_name' => 'web'],
            ['business_id' => $businessId, 'is_default' => 0, 'is_service_staff' => 0]
        );

        // Grant the card's configured permissions to the role (only those that
        // actually exist in this project DB). Lets new roles like Warehouse /
        // Pharmacist be usable immediately; roles without a `permissions` key
        // rely on the clinic/vet/ERP seeders.
        $perms = $roleDef['permissions'] ?? [];
        if ($perms === '@warehouse') {
            $perms = config('demologin.warehouse_permissions', []);
        }
        foreach ((array) $perms as $pName) {
            $perm = Permission::where('name', $pName)->where('guard_name', 'web')->first();
            if ($perm && ! $roleModel->hasPermissionTo($perm)) {
                try { $roleModel->givePermissionTo($perm); } catch (\Throwable $e) {}
            }
        }
        try {
            app(\Spatie\Permission\PermissionRegistrar::class)->forgetCachedPermissions();
        } catch (\Throwable $e) {
        }

        // Find or lazily create the demo user for this (project, role).
        $username = 'demo_' . $project . '_' . $role;
        $user = User::on($conn)->where('username', $username)->first();
        if (! $user) {
            $user = new User();
            $user->setConnection($conn);
            $user->forceFill([
                'user_type'   => 'user',
                'surname'     => 'Demo',
                'first_name'  => $roleDef['label'],
                'username'    => $username,
                'email'       => $username . '@demo.local',
                'password'    => Hash::make(Str::random(40)),
                'language'    => 'en',
                'business_id' => $businessId,
                'status'      => 'active',
                'allow_login' => 1,
            ])->save();
        } elseif ($user->status !== 'active' || ! $user->allow_login) {
            $user->forceFill(['status' => 'active', 'allow_login' => 1])->save();
        }

        if (! $user->hasRole($roleName)) {
            $user->assignRole($roleModel);
        }

        // Fresh session, then record the active project so SaasSwitcher's
        // ResolveProjectConnection keeps the DB pointed at it for the session.
        $request->session()->invalidate();
        session([
            config('saasswitcher.session_key', 'saas_project')       => $project,
            config('saasswitcher.impersonating_key', 'saas_impersonating') => true,
        ]);

        Auth::login($user);

        return redirect('/home');
    }
}
