<?php

namespace App\Http\Controllers\HRM;

use App\Http\Controllers\Controller;
use App\Models\Department;
use App\Models\Employee;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Validator;

class DepartmentController extends Controller
{
    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function index(Request $request)
    {
        $companyId = $request->session()->get('company_id');
        $query = Department::where('company_id', $companyId);

        // Apply filters if provided
        if ($request->has('status') && $request->status != '') {
            $query->where('status', $request->status);
        }

        if ($request->has('search') && $request->search != '') {
            $search = $request->search;
            $query->where(function ($q) use ($search) {
                $q->where('name', 'like', "%{$search}%")
                    ->orWhere('name_en', 'like', "%{$search}%")
                    ->orWhere('code', 'like', "%{$search}%");
            });
        }

        $departments = $query->with(['manager', 'employees'])
            ->withCount('employees')
            ->orderBy('name')
            ->paginate(10);

        return view('hrm.departments.index', compact('departments'));
    }

    /**
     * Show the form for creating a new resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function create(Request $request)
    {
        $companyId = $request->session()->get('company_id');

        // Get all departments for parent selection
        $departments = Department::where('company_id', $companyId)
            ->orderBy('name')
            ->get();

        // Get all active employees for manager selection
        $managers = Employee::where('company_id', $companyId)
            ->where('status', 'active')
            ->orderBy('first_name')
            ->get();

        return view('hrm.departments.create', compact('departments', 'managers'));
    }

    /**
     * Store a newly created resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function store(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'name' => 'required|string|max:255',
            'name_en' => 'nullable|string|max:255',
            'code' => 'nullable|string|max:50',
            'description' => 'nullable|string',
            'manager_id' => 'nullable|exists:employees,id',
            'parent_id' => 'nullable|exists:departments,id',
            'status' => 'required|in:active,inactive',
        ]);

        if ($validator->fails()) {
            return redirect()->back()
                ->withErrors($validator)
                ->withInput();
        }

        $companyId = $request->session()->get('company_id');

        // Check if manager belongs to the company
        if ($request->manager_id) {
            $manager = Employee::findOrFail($request->manager_id);
            if ($manager->company_id != $companyId) {
                return redirect()->back()
                    ->with('error', 'Selected manager does not belong to your company.')
                    ->withInput();
            }
        }

        // Check if parent department belongs to the company
        if ($request->parent_id) {
            $parentDepartment = Department::findOrFail($request->parent_id);
            if ($parentDepartment->company_id != $companyId) {
                return redirect()->back()
                    ->with('error', 'Selected parent department does not belong to your company.')
                    ->withInput();
            }
        }

        $department = new Department();
        $department->company_id = $companyId;
        $department->name = $request->name;
        $department->name_en = $request->name_en;
        $department->code = $request->code;
        $department->description = $request->description;
        $department->manager_id = $request->manager_id;
        $department->parent_id = $request->parent_id;
        $department->status = $request->status;
        $department->created_by = Auth::id();
        $department->save();

        return redirect()->route('hrm.departments.index')
            ->with('success', 'Department created successfully.');
    }

    /**
     * Display the specified resource.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function show($id)
    {
        $department = Department::with(['manager', 'parent', 'children.manager', 'children.employees'])
            ->withCount('employees')
            ->findOrFail($id);

        // Check if department belongs to the current company
        $companyId = session('company_id');
        if ($department->company_id != $companyId) {
            abort(403, 'Unauthorized action.');
        }

        // Get employees in this department
        $employees = Employee::where('department_id', $id)
            ->where('company_id', $companyId)
            ->paginate(10);

        return view('hrm.departments.show', compact('department', 'employees'));
    }

    /**
     * Show the form for editing the specified resource.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function edit(Request $request, $id)
    {
        $companyId = $request->session()->get('company_id');
        $department = Department::findOrFail($id);

        // Check if department belongs to the current company
        if ($department->company_id != $companyId) {
            abort(403, 'Unauthorized action.');
        }

        // Get all active employees for manager selection
        $managers = Employee::where('company_id', $companyId)
            ->where('status', 'active')
            ->orderBy('first_name')
            ->get();

        // Get all departments except this one for parent selection
        $departments = Department::where('company_id', $companyId)
            ->where('id', '!=', $id)
            ->orderBy('name')
            ->get();

        return view('hrm.departments.edit', compact('department', 'managers', 'departments'));
    }

    /**
     * Update the specified resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function update(Request $request, $id)
    {
        $department = Department::findOrFail($id);

        // Check if department belongs to the current company
        $companyId = $request->session()->get('company_id');
        if ($department->company_id != $companyId) {
            abort(403, 'Unauthorized action.');
        }

        $validator = Validator::make($request->all(), [
            'name' => 'required|string|max:255',
            'name_en' => 'nullable|string|max:255',
            'code' => 'nullable|string|max:50',
            'description' => 'nullable|string',
            'manager_id' => 'nullable|exists:employees,id',
            'parent_id' => 'nullable|exists:departments,id',
            'status' => 'required|in:active,inactive',
        ]);

        if ($validator->fails()) {
            return redirect()->back()
                ->withErrors($validator)
                ->withInput();
        }

        // Check if manager belongs to the company
        if ($request->manager_id) {
            $manager = Employee::findOrFail($request->manager_id);
            if ($manager->company_id != $companyId) {
                return redirect()->back()
                    ->with('error', 'Selected manager does not belong to your company.')
                    ->withInput();
            }
        }

        // Check if parent department belongs to the company
        if ($request->parent_id) {
            // Prevent circular reference
            if ($request->parent_id == $id) {
                return redirect()->back()
                    ->with('error', 'Department cannot be its own parent.')
                    ->withInput();
            }

            $parentDepartment = Department::findOrFail($request->parent_id);
            if ($parentDepartment->company_id != $companyId) {
                return redirect()->back()
                    ->with('error', 'Selected parent department does not belong to your company.')
                    ->withInput();
            }

            // Check if the selected parent is not a child of this department
            $childDepartments = $this->getAllChildDepartments($id);
            if (in_array($request->parent_id, $childDepartments)) {
                return redirect()->back()
                    ->with('error', 'Cannot select a child department as parent.')
                    ->withInput();
            }
        }

        $department->name = $request->name;
        $department->name_en = $request->name_en;
        $department->code = $request->code;
        $department->description = $request->description;
        $department->manager_id = $request->manager_id;
        $department->parent_id = $request->parent_id;
        $department->status = $request->status;
        $department->updated_by = Auth::id();
        $department->save();

        return redirect()->route('hrm.departments.index')
            ->with('success', 'Department updated successfully.');
    }

    /**
     * Remove the specified resource from storage.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function destroy(Request $request, $id)
    {
        $department = Department::findOrFail($id);

        // Check if department belongs to the current company
        $companyId = $request->session()->get('company_id');
        if ($department->company_id != $companyId) {
            abort(403, 'Unauthorized action.');
        }

        // Check if department has employees
        $hasEmployees = Employee::where('department_id', $id)->exists();
        if ($hasEmployees) {
            return redirect()->route('hrm.departments.index')
                ->with('error', 'Cannot delete department as it has employees assigned to it.');
        }

        // Check if department has child departments
        $hasChildren = Department::where('parent_id', $id)->exists();
        if ($hasChildren) {
            return redirect()->route('hrm.departments.index')
                ->with('error', 'Cannot delete department as it has child departments.');
        }

        $department->delete();

        return redirect()->route('hrm.departments.index')
            ->with('success', 'Department deleted successfully.');
    }

    /**
     * Get all employees for a department.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function employees(Request $request, $id)
    {
        $department = Department::findOrFail($id);

        // Check if department belongs to the current company
        $companyId = $request->session()->get('company_id');
        if ($department->company_id != $companyId) {
            abort(403, 'Unauthorized action.');
        }

        $employees = Employee::where('department_id', $id)
            ->where('company_id', $companyId)
            ->paginate(15);

        return view('hrm.departments.employees', compact('department', 'employees'));
    }

    /**
     * Get department hierarchy.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function hierarchy(Request $request)
    {
        $companyId = $request->session()->get('company_id');

        // Get all root departments (no parent)
        $rootDepartments = Department::with(['manager', 'children'])
            ->where('company_id', $companyId)
            ->whereNull('parent_id')
            ->orderBy('name')
            ->get();

        return view('hrm.departments.hierarchy', compact('rootDepartments'));
    }

    /**
     * Get all child departments recursively.
     *
     * @param  int  $departmentId
     * @return array
     */
    private function getAllChildDepartments($departmentId)
    {
        $childIds = [];
        $children = Department::where('parent_id', $departmentId)->get();

        foreach ($children as $child) {
            $childIds[] = $child->id;
            $childIds = array_merge($childIds, $this->getAllChildDepartments($child->id));
        }

        return $childIds;
    }

    /**
     * Assign employees to department.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function assignEmployees(Request $request, $id)
    {
        $department = Department::findOrFail($id);

        // Check if department belongs to the current company
        $companyId = $request->session()->get('company_id');
        if ($department->company_id != $companyId) {
            abort(403, 'Unauthorized action.');
        }

        $validator = Validator::make($request->all(), [
            'employee_ids' => 'required|array',
            'employee_ids.*' => 'exists:employees,id',
        ]);

        if ($validator->fails()) {
            return redirect()->back()
                ->withErrors($validator)
                ->withInput();
        }

        foreach ($request->employee_ids as $employeeId) {
            $employee = Employee::findOrFail($employeeId);

            // Check if employee belongs to the company
            if ($employee->company_id != $companyId) {
                continue; // Skip this employee
            }

            $employee->department_id = $id;
            $employee->updated_by = Auth::id();
            $employee->save();
        }

        return redirect()->route('hrm.departments.show', $id)
            ->with('success', 'Employees assigned to department successfully.');
    }
}
