<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\User;
use App\Models\Language;
use App\Models\Contact;
use App\Models\AccessType;
use App\Models\UserAccess;
use App\Models\Team;
use Spatie\Permission\Models\Role;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use Illuminate\Validation\Rule;

class UserRoleController extends Controller
{
    public function __construct()
    {
        $this->middleware('auth');
        // $this->middleware('permission:manage_users')->except(['index', 'show']);

        $this->middleware('permission:list_user')->only(['index']);
        $this->middleware('permission:list_user')->only(['show']);
        $this->middleware('permission:create_user')->only(['create', 'store']);
        $this->middleware('permission:update_user')->only(['edit', 'update']);
        $this->middleware('permission:delete_user')->only(['destroy']);
    }

    public function index(Request $request)
    {
        $request->validate([
            'q' => ['nullable', 'string', 'max:100'],
            'status' => ['nullable', 'in:active,inactive'],
            'role_id' => ['nullable', 'integer'],
            'team_name' => ['nullable', 'string', 'max:100'],
            'reporting_manager_id' => ['nullable', 'integer'],
        ]);
        $users = User::with(['roles', 'accessTypes', 'reportingManager'])
            ->where('business_id', auth()->user()->business_id)
            ->when($request->filled('q'), function ($query) use ($request) {
                $term = '%'.addcslashes($request->string('q')->trim()->value(), '%_').'%';
                $query->where(fn ($q) => $q->where('name', 'like', $term)->orWhere('email', 'like', $term));
            })
            ->when($request->status === 'active', fn ($q) => $q->whereNotNull('email_verified_at'))
            ->when($request->status === 'inactive', fn ($q) => $q->whereNull('email_verified_at'))
            ->when($request->filled('role_id'), fn ($q) => $q->whereHas('roles', fn ($roleQuery) => $roleQuery->where('roles.id', $request->integer('role_id'))))
            ->when($request->filled('team_name'), fn ($q) => $q->where('team_name', $request->team_name))
            ->when($request->filled('reporting_manager_id'), fn ($q) => $q->where('reporting_manager_id', $request->integer('reporting_manager_id')))
            ->latest('id')->paginate(25)->withQueryString();
        $roles = Role::orderBy('name')->get(['id', 'name']);
        $teams = User::where('business_id', auth()->user()->business_id)->whereNotNull('team_name')->distinct()->orderBy('team_name')->pluck('team_name');
        $managers = User::where('business_id', auth()->user()->business_id)->orderBy('name')->get(['id', 'name']);

        return view('user-roles.index', compact('users', 'roles', 'teams', 'managers'));
    }

    public function create()
    {
        $languages = Language::all();
        $contacts = Contact::all();
        $users = User::where('business_id', auth()->user()->business_id)->get();
        $roles = Role::all();
        $accessTypes = AccessType::all();
        $teams = Team::where('business_id', auth()->user()->business_id)->where('status', 'active')->orderBy('name')->get(['id', 'name', 'code', 'manager_id']);

        return view('user-roles.create', compact('languages', 'contacts', 'users', 'roles', 'accessTypes', 'teams'));
    }


    public function store(Request $request)
    {
        // Validate the incoming request
        $request->validate([
            'user_name' => 'required|string|max:255',
            'email' => 'required|string|email|max:255|unique:users',
            'password' => 'required|string|min:8|confirmed',
            'roles' => 'array',
            'roles.*' => 'exists:roles,id',
            'access_type' => 'required|exists:access_types,id',
            'specific_user' => 'required_if:access_type,3|array|nullable',
            'specific_user.*' => 'exists:users,id',
            'team_id' => ['nullable', 'integer', Rule::exists('teams', 'id')->where(fn ($query) => $query
                ->where('business_id', auth()->user()->business_id)->where('status', 'active')->whereNull('deleted_at'))],
            'reporting_manager_id' => 'nullable|exists:users,id',
        ]);

        try {
            // Start database transaction
            \DB::beginTransaction();

            // Check if admin role is selected
            $isAdmin = 0;
            if ($request->has('roles') && !empty($request->roles)) {
                // Get the admin role ID (assuming role name is 'admin')
                $adminRole = Role::where('name', 'admin')->first();
                if ($adminRole && in_array($adminRole->id, $request->roles)) {
                    $isAdmin = 1;
                }
            }

            $selectedTeam = $request->filled('team_id')
                ? Team::where('business_id', auth()->user()->business_id)->findOrFail($request->integer('team_id'))
                : null;

            // Create the user (only basic info)
            $user = User::create([
                'business_id' => auth()->user()->business_id,
                'name' => $request->user_name,
                'email' => $request->email,
                'password' => \Hash::make($request->password),
                'parent_user_id' => auth()->id(),
                'is_admin' => $isAdmin,
                'team_name' => $selectedTeam?->name,
                'reporting_manager_id' => $request->reporting_manager_id ?: $selectedTeam?->manager_id,
            ]);
            $user->teams()->sync($selectedTeam ? [$selectedTeam->id] : []);

            // Handle access control based on access type
            $accessTypeId = (int)$request->access_type;
            
            switch ($accessTypeId) {
                case 1: // PUBLIC - All owners of data can access this user
                case 2: // PRIVATE - Only who owner of data can access this user
                    // For Public and Private, create records with roles only
                    if ($request->has('roles') && !empty($request->roles)) {
                        foreach ($request->roles as $roleId) {
                            UserAccess::create([
                                'user_id' => $user->id,
                                'access_type_id' => $accessTypeId,
                                'role_id' => $roleId,
                            ]);
                        }
                    } else {
                        // Create basic access record without roles
                        UserAccess::create([
                            'user_id' => $user->id,
                            'access_type_id' => $accessTypeId,
                        ]);
                    }
                    break;

                case 3: // SPECIFIC USERS - Specific owner of the data can access this user
                    if ($request->has('specific_user') && !empty($request->specific_user)) {
                        foreach ($request->specific_user as $specificUserId) {
                            if ($request->has('roles') && !empty($request->roles)) {
                                // Create record for each combination of role and specific user
                                foreach ($request->roles as $roleId) {
                                    UserAccess::create([
                                        'user_id' => $user->id,
                                        'access_type_id' => $accessTypeId,
                                        'role_id' => $roleId,
                                        'specific_user_id' => $specificUserId,
                                    ]);
                                }
                            } else {
                                // Create record with just specific user (no roles)
                                UserAccess::create([
                                    'user_id' => $user->id,
                                    'access_type_id' => $accessTypeId,
                                    'specific_user_id' => $specificUserId,
                                ]);
                            }
                        }
                    } else {
                        // If no specific users selected but access type is 3, create basic record
                        if ($request->has('roles') && !empty($request->roles)) {
                            foreach ($request->roles as $roleId) {
                                UserAccess::create([
                                    'user_id' => $user->id,
                                    'access_type_id' => $accessTypeId,
                                    'role_id' => $roleId,
                                ]);
                            }
                        } else {
                            UserAccess::create([
                                'user_id' => $user->id,
                                'access_type_id' => $accessTypeId,
                            ]);
                        }
                    }
                    break;

                default:
                    throw new \Exception('Invalid access type selected.');
            }

            // Assign Spatie roles
            if ($request->has('roles') && !empty($request->roles)) {
                $roles = Role::whereIn('id', $request->roles)->pluck('name');
                $user->syncRoles($roles);
            } else {
                $user->syncRoles([]);
            }

            // Commit the transaction
            \DB::commit();

            return redirect()->route('user-roles.index')
                ->with('success', 'User created successfully with assigned roles and access permissions.');

        } catch (\Exception $e) {
            // Rollback the transaction in case of error
            \DB::rollback();
            
            return redirect()->back()
                ->withInput()
                ->with('error', 'Failed to create user: ' . $e->getMessage());
        }
    }

    public function edit(int $user)
    {
        $user = $this->businessUser($user);
        $roles = Role::all();
        $userRoles = $user->roles->pluck('id')->toArray();
        $accessTypes = AccessType::all();

        // Get the first UserAccess for this user
        $userAccess = UserAccess::where('user_id', $user->id)->first();

        // If access type is 3, get specific users
        $specificUsers = [];
        if ($userAccess && $userAccess->access_type_id == 3) {
            $specificUsers = UserAccess::where('user_id', $user->id)
                ->where('access_type_id', 3)
                ->pluck('specific_user_id')
                ->filter()
                ->toArray();
        }

        $users = User::where('business_id', auth()->user()->business_id)
            ->where('id', '!=', $user->id)
            ->get();
        $teams = Team::where('business_id', auth()->user()->business_id)->where('status', 'active')->orderBy('name')->get(['id', 'name', 'code', 'manager_id']);
        $selectedTeamId = $user->teams()->value('teams.id');

        return view('user-roles.edit', compact(
            'user', 'roles', 'userRoles', 'accessTypes', 'userAccess', 'specificUsers', 'users', 'teams', 'selectedTeamId'
        ));
    }

    public function update(Request $request, int $user)
    {
        $user = $this->businessUser($user);
        $request->validate([
            'user_name' => 'required|string|max:255',
            'email' => 'required|string|email|max:255|unique:users,email,' . $user->id,
            'roles' => 'array',
            'roles.*' => 'exists:roles,id',
            'access_type' => 'required|exists:access_types,id',
            'specific_user' => 'required_if:access_type,3|array|nullable',
            'specific_user.*' => 'exists:users,id',
            'status' => 'required|in:0,1',
            'team_id' => ['nullable', 'integer', Rule::exists('teams', 'id')->where(fn ($query) => $query
                ->where('business_id', auth()->user()->business_id)->where('status', 'active')->whereNull('deleted_at'))],
            'reporting_manager_id' => 'nullable|exists:users,id|not_in:' . $user->id,
        ]);

        try {
            \DB::beginTransaction();

            // Check if admin role is selected
            $isAdmin = 0;
            if ($request->has('roles') && !empty($request->roles)) {
                $adminRole = Role::where('name', 'admin')->first();
                if ($adminRole && in_array($adminRole->id, $request->roles)) {
                    $isAdmin = 1;
                }
            }

            $selectedTeam = $request->filled('team_id')
                ? Team::where('business_id', auth()->user()->business_id)->findOrFail($request->integer('team_id'))
                : null;

            // Update user basic info
            $user->update([
                'name' => $request->user_name,
                'email' => $request->email,
                'is_admin' => $isAdmin,
                'status' => $request->status,
                'team_name' => $selectedTeam?->name,
                'reporting_manager_id' => $request->reporting_manager_id ?: $selectedTeam?->manager_id,
            ]);
            $user->teams()->sync($selectedTeam ? [$selectedTeam->id] : []);

            // Remove old access records
            UserAccess::where('user_id', $user->id)->delete();

            // Handle access control
            $accessTypeId = (int) $request->access_type;

            switch ($accessTypeId) {
                case 1: // PUBLIC
                case 2: // PRIVATE
                    if ($request->has('roles') && !empty($request->roles)) {
                        foreach ($request->roles as $roleId) {
                            UserAccess::create([
                                'user_id' => $user->id,
                                'access_type_id' => $accessTypeId,
                                'role_id' => $roleId,
                            ]);
                        }
                    } else {
                        UserAccess::create([
                            'user_id' => $user->id,
                            'access_type_id' => $accessTypeId,
                        ]);
                    }
                    break;

                case 3: // SPECIFIC USERS
                    if ($request->has('specific_user') && !empty($request->specific_user)) {
                        foreach ($request->specific_user as $specificUserId) {
                            if ($request->has('roles') && !empty($request->roles)) {
                                foreach ($request->roles as $roleId) {
                                    UserAccess::create([
                                        'user_id' => $user->id,
                                        'access_type_id' => $accessTypeId,
                                        'role_id' => $roleId,
                                        'specific_user_id' => $specificUserId,
                                    ]);
                                }
                            } else {
                                UserAccess::create([
                                    'user_id' => $user->id,
                                    'access_type_id' => $accessTypeId,
                                    'specific_user_id' => $specificUserId,
                                ]);
                            }
                        }
                    } else {
                        if ($request->has('roles') && !empty($request->roles)) {
                            foreach ($request->roles as $roleId) {
                                UserAccess::create([
                                    'user_id' => $user->id,
                                    'access_type_id' => $accessTypeId,
                                    'role_id' => $roleId,
                                ]);
                            }
                        } else {
                            UserAccess::create([
                                'user_id' => $user->id,
                                'access_type_id' => $accessTypeId,
                            ]);
                        }
                    }
                    break;

                default:
                    throw new \Exception('Invalid access type selected.');
            }

            // Sync roles
            if ($request->has('roles') && !empty($request->roles)) {
                $roles = Role::whereIn('id', $request->roles)->pluck('name');
                $user->syncRoles($roles);
            } else {
                $user->syncRoles([]);
            }

            \DB::commit();

            return redirect()->route('user-roles.index')
                ->with('success', 'User updated successfully with roles and access permissions.');

        } catch (\Exception $e) {
            \DB::rollback();

            return redirect()->back()
                ->withInput()
                ->with('error', 'Failed to update user: ' . $e->getMessage());
        }
    }
    
    public function destroy(int $user)
    {
        $user = $this->businessUser($user);
        try {
            \DB::beginTransaction();

            // Prevent deleting yourself
            if ($user->id === auth()->id()) {
                return redirect()->back()
                    ->with('error', 'You cannot delete your own account.');
            }

            // Remove role assignments
            $user->syncRoles([]);

            // Delete access permissions
            UserAccess::where('user_id', $user->id)->delete();

            // Finally delete the user
            $user->delete();

            \DB::commit();

            return redirect()->route('user-roles.index')
                ->with('success', 'User deleted successfully.');

        } catch (\Exception $e) {
            \DB::rollback();

            return redirect()->back()
                ->with('error', 'Failed to delete user: ' . $e->getMessage());
        }
    }

    private function businessUser(int $id): User
    {
        return User::where('business_id', auth()->user()->business_id)->findOrFail($id);
    }
}
