<?php

namespace App\Http\Controllers\Admin\Manage;

use App\Helpers\PasswordHelper;
use App\Http\Controllers\Controller;
use App\Models\User;
use App\Services\Api\API;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Inertia\Inertia;

class UserController extends Controller
{
    protected API $api;

    public function __construct(API $api)
    {
        $this->api = $api;
    }

    public function index(Request $request)
    {
        $search = trim((string) $request->input('search', ''));
        $roleFilter = $request->input('role');

        $isServerOnline = $this->api->online;

        $users = collect();

        if ($search !== '') {
            $query = User::query();

            $query->where(function ($q) use ($search) {
                $q->where('name', 'like', "%{$search}%");

                if (is_numeric($search)) {
                    $q->orWhereRaw('CAST(ID AS CHAR) LIKE ?', ["%{$search}%"]);
                }
            });

            if ($roleFilter) {
                $query->where('role', $roleFilter);
            }

            $users = $query->latest('ID')->get()->map(function ($user) use ($isServerOnline) {
                $cash = 0;
                if ($isServerOnline) {
                    try {
                        $cash = $this->api->getCurrentCash($user->ID);
                    } catch (\Exception $e) {
                        $cash = 0;
                    }
                }

                return [
                    'id' => $user->ID,
                    'name' => $user->name,
                    'email' => $user->email,
                    'role' => $user->role,
                    'original_id' => $user->ID,
                    'current_cash' => $cash,
                ];
            });
        }

        return Inertia::render('admin/manage/users/index', [
            'users' => $users,
            'availableRoles' => ['admin', 'player'],
            'filters' => [
                'search' => $search !== '' ? $search : null,
                'role' => $roleFilter,
            ],
            'serverOnline' => $isServerOnline,
        ]);
    }

    public function store(Request $request)
    {
        $request->validate([
            'name' => 'required|string|max:32|unique:users,name',
            'truename' => 'required|string|max:32',
            'email' => 'required|email|unique:users|max:64',
            'role' => 'required|in:admin,player',
            'password' => 'required|string|min:6|confirmed',
        ]);

        // Use pw.sql adduser stored procedure to create account (handles userid: 1024, 1040, 1056, ...)
        DB::statement(
            'CALL adduser(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)',
            [
                $request->name,
                PasswordHelper::encryptPassword($request->name, $request->password),
                '',
                '',
                $request->truename,
                '',
                $request->email,
                '',
                '',
                '',
                '',
                '',
                '',
                0,
                '2000-01-01',
                '',
                '',
            ]
        );

        // Update Laravel-specific columns
        User::where('name', $request->name)->update([
            'role' => $request->role,
        ]);

        return back()->with('success', 'User created successfully.');
    }

    public function update(Request $request, $userId)
    {
        $user = User::where('ID', $userId)->firstOrFail();
        $oldId = $user->ID;
        $newId = $request->id;

        // Build validation rules dynamically based on what's being sent
        $rules = [];

        if ($request->has('id')) {
            $rules['id'] = 'required|integer|unique:users,ID,'.$oldId.',ID';
        }

        if ($request->has('name')) {
            $rules['name'] = 'required|string|max:32|unique:users,name,'.$oldId.',ID';
        }

        if ($request->has('email')) {
            $rules['email'] = 'required|email|max:64|unique:users,email,'.$oldId.',ID';
        }

        if ($request->has('role')) {
            $rules['role'] = 'required|in:admin,player';
        }

        $request->validate($rules);

        // Build update data based on what's being sent
        $updateData = [];

        if ($request->has('id')) {
            $updateData['ID'] = $newId;
        }

        if ($request->has('name')) {
            $updateData['name'] = $request->name;
        }

        if ($request->has('email')) {
            $updateData['email'] = $request->email;
        }

        if ($request->has('role')) {
            $updateData['role'] = $request->role;
        }

        // Check if updating current logged-in user
        $isCurrentUser = Auth::check() && Auth::id() === (int) $userId;

        // If ID is being changed, use raw SQL to update the primary key
        if (isset($updateData['ID']) && $newId != $oldId && $newId !== null) {
            DB::table('users')
                ->where('ID', $oldId)
                ->update($updateData);

            // If updating current user, redirect to page (full reload) to handle session refresh
            if ($isCurrentUser) {
                // Set flash message in session
                session()->flash('success', "Your user ID has been changed from {$oldId} to {$newId}. You have been logged out. Please login again.");

                // Use redirect()->to() to force full page reload
                return to_route('admin.manage-users');
            }

            return back()->with('success', "User ID changed from {$oldId} to {$newId} successfully. Refreshing the page...");
        }

        // If ID is not changed, use normal update
        if (! empty($updateData)) {
            $user->update($updateData);
        }

        return back()->with('success', 'User updated successfully.');
    }

    public function destroy(User $user)
    {
        if (Auth::id() === $user->ID) {
            return back()->with('error', 'You cannot delete yourself.');
        }

        $user->delete();

        return back()->with('success', 'User deleted successfully.');
    }

    public function ban(Request $request, int $userId): JsonResponse
    {
        // Check if server is online
        if (! $this->api->online) {
            return response()->json([
                'error' => 'Cannot perform this action while server is offline',
            ], 503);
        }

        $validated = $request->validate([
            'duration' => 'required|integer|min:0',
            'reason' => 'nullable|string|max:255',
            'action' => 'required|string|in:mute_role,mute_acc,forbid_role,forbid_acc',
            'role_id' => 'nullable|integer',
        ]);

        $reason = $validated['reason'] ?? 'Action by admin';
        $action = $validated['action'];
        $roleId = $validated['role_id'] ?? null;

        try {
            // Execute based on action type
            switch ($action) {
                case 'mute_role':
                    if (! $roleId) {
                        return response()->json(['error' => 'Role ID required for mute role'], 400);
                    }
                    $this->api->muteRole($roleId, $validated['duration'], $reason);
                    $actionText = 'Chat muted (role)';
                    break;
                case 'mute_acc':
                    $this->api->muteAcc($userId, $validated['duration'], $reason);
                    $actionText = 'Chat muted (account)';
                    break;
                case 'forbid_role':
                    if (! $roleId) {
                        return response()->json(['error' => 'Role ID required for ban role'], 400);
                    }
                    $this->api->forbidRole($roleId, $validated['duration'], $reason);
                    $actionText = 'Role banned';
                    break;
                case 'forbid_acc':
                default:
                    $this->api->forbidAcc($userId, $validated['duration'], $reason);
                    $actionText = 'Account banned';
            }

            $durationText = $validated['duration'] === 0 ? 'permanently' : 'for '.$this->formatDuration($validated['duration']);

            return response()->json([
                'success' => true,
                'message' => "{$actionText} {$durationText}",
            ]);
        } catch (\Exception $e) {
            return response()->json([
                'error' => 'Failed to execute action: '.$e->getMessage(),
            ], 500);
        }
    }

    protected function formatDuration(int $seconds): string
    {
        if ($seconds >= 86400) {
            $days = floor($seconds / 86400);

            return $days.' day'.($days > 1 ? 's' : '');
        }
        if ($seconds >= 3600) {
            $hours = floor($seconds / 3600);

            return $hours.' hour'.($hours > 1 ? 's' : '');
        }
        $minutes = floor($seconds / 60);

        return $minutes.' minute'.($minutes > 1 ? 's' : '');
    }

    public function addGold(Request $request, int $userId): JsonResponse
    {
        $validated = $request->validate([
            'gold' => 'required|integer|min:1',
        ]);

        $goldAmount = $validated['gold'];
        $goldAmountDB = $goldAmount * 100;

        try {
            DB::statement('CALL usecash(?, ?, ?, ?, ?, ?, ?, @error)', [
                $userId,
                1,
                0,
                1,
                0,
                $goldAmountDB,
                1,
            ]);

            return response()->json([
                'success' => true,
                'message' => "Successfully added {$goldAmount} gold to user ID {$userId}",
            ]);
        } catch (\Exception $e) {
            return response()->json([
                'error' => 'Failed to add gold: '.$e->getMessage(),
            ], 500);
        }
    }

    public function getUserRoles(int $userId): JsonResponse
    {
        try {
            $rolesData = $this->api->getRoles($userId);
            $roles = [];

            foreach ($rolesData['roles'] ?? [] as $role) {
                try {
                    $base = $this->api->getRoleBase($role['id']);
                    if ($base) {
                        $roles[] = [
                            'id' => $role['id'],
                            'name' => $base['name'] ?? 'Unknown',
                            'level' => $base['level'] ?? 0,
                            'cls' => $base['cls'] ?? 0,
                        ];
                    } else {
                        // If base data not available, show basic info
                        $roles[] = [
                            'id' => $role['id'],
                            'name' => $role['name'] ?? 'Unknown',
                            'level' => 0,
                            'cls' => 0,
                        ];
                    }
                } catch (\Exception $e) {
                    // If error occurs, show basic info from roles data
                    $roles[] = [
                        'id' => $role['id'],
                        'name' => $role['name'] ?? 'Unknown',
                        'level' => 0,
                        'cls' => 0,
                    ];
                }
            }

            return response()->json([
                'success' => true,
                'roles' => $roles,
            ]);
        } catch (\Exception $e) {
            return response()->json([
                'error' => 'Failed to get roles: '.$e->getMessage(),
                'roles' => [],
            ], 500);
        }
    }
}
