<?php

namespace App\Modules\HR\Core\Http\Controllers;

use App\Http\Controllers\Controller;
use App\Modules\HR\Core\Models\Employee;
use App\Modules\HR\Core\Models\EmployeeDynamicAttributeValue;
use App\Modules\HR\Core\Models\DynamicAttribute;
use App\Modules\PLATFORM\Settings\Models\Company;
use App\Modules\PLATFORM\Settings\Models\Branch;
use App\Modules\HR\Core\Models\Department;
use App\Modules\HR\Core\Models\Designation;
use App\Modules\HR\Core\Models\Grade;
use App\Modules\HR\Core\Models\EmploymentType;
use App\Modules\HR\Core\Models\Shift;
use App\Modules\HR\Core\Models\Gender;
use App\Modules\HR\Core\Models\MaritalStatus;
use App\Modules\HR\Core\Models\BloodGroup;
use App\Modules\PLATFORM\Settings\Models\Country;
use App\Modules\PLATFORM\Settings\Models\City;
use App\Modules\PLATFORM\Settings\Models\Bank;
use App\Modules\PLATFORM\Settings\Models\BankBranch;
use App\Modules\HR\Core\Models\EmployeeLeave;
use App\Modules\PLATFORM\Settings\Models\PaymentMethod;
use App\Modules\HR\Core\Models\IdentificationType;
use App\Modules\HR\Core\Models\Illness;
use App\Modules\HR\Core\Models\LeaveType;
use App\Modules\HR\Core\Models\RelationshipType;
use App\Modules\HR\Core\Models\ShiftSegment;
use App\Modules\HR\Core\Models\Team;
use App\Modules\HR\Payroll\Models\Addition;
use App\Modules\HR\Payroll\Models\Deduction;
use App\Modules\HR\Payroll\Models\PayrollGroup;
use App\Modules\PLATFORM\Settings\Models\DocumentType;
use App\Modules\PLATFORM\Settings\Models\Religion;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Yajra\DataTables\Facades\DataTables;
use Carbon\Carbon;

class EmployeeController extends Controller
{
    /* ==========================================================
     | INDEX
     ========================================================== */

    public function index(Request $request)
    {
        if ($request->ajax()) {

            $query = Employee::with([
                'branch',
                'department',
                'designation',
            ]);

            return DataTables::of($query)
                ->addIndexColumn()

                ->addColumn('employee', fn ($row) =>
                    $row->employee_code . ' - ' .
                    $row->first_name . ' ' . $row->last_name
                )

                ->filterColumn('employee', function ($query, $keyword) {
                    $query->where(function ($q) use ($keyword) {
                        $q->where('employee_code', 'like', "%{$keyword}%")
                          ->orWhere('first_name', 'like', "%{$keyword}%")
                          ->orWhere('last_name', 'like', "%{$keyword}%");
                    });
                })

                ->addColumn('branch', fn ($row) => $row->branch?->name ?? '-')
                ->addColumn('department', fn ($row) => $row->department->name)
                ->addColumn('designation', fn ($row) => $row->designation->name)

                ->addColumn('age', function ($row) {
                    if (!$row->date_of_birth) return '-';
                    $diff = Carbon::parse($row->date_of_birth)->diff(now());
                    return "{$diff->y}y {$diff->m}m {$diff->d}d";
                })

                ->addColumn('service_period', function ($row) {
                    if (!$row->date_of_joining) return '-';
                    $diff = Carbon::parse($row->date_of_joining)->diff(now());
                    return "{$diff->y}y {$diff->m}m {$diff->d}d";
                })

                ->editColumn('status', fn ($row) =>
                    $row->status === 'active'
                        ? '<span class="badge bg-success">Active</span>'
                        : '<span class="badge bg-secondary">Inactive</span>'
                )

                ->addColumn('action', function ($row) {
                    return view('core::employees/partials/actions', compact('row'))->render();
                })

                ->rawColumns(['status', 'action'])
                ->make(true);
        }

        return view('core::employees/index');
    }

    /* ==========================================================
     | CREATE
     ========================================================== */

    public function create()
    {
        
        return view('core::employees/create', $this->masterData());
    }

    /* ==========================================================
     | STORE
     ========================================================== */

       public function store(Request $request)
    {
        $branchId = session('branch_id');

       if($branchId){

       }else{
            $branchId = $request->branch_id;
       }

        DB::transaction(function () use ($request, $branchId) {

            /* ================= EMPLOYEE ================= */
            $employee = Employee::create(
                array_merge(
                    $request->except([
                        'family',
                        'illness',
                        'documents',
                        'dynamic_attributes',
                        'branch_id',
                        'profile_picture' // Exclude from initial create
                    ]),
                    [
                        'branch_id' => $branchId
                    ]
                )
            );

            // Handle Profile Picture Upload
            if ($request->hasFile('profile_picture')) {

                $file = $request->file('profile_picture');
                $filename = time().'_'.$file->getClientOriginalName();

                $file->move(public_path('storage/employees'), $filename);

                $employee->profile_picture = 'employees/'.$filename;
            }


            /* ================= DYNAMIC ATTRIBUTES ================= */
            $this->saveDynamicAttributes($employee, $request);

            /* ================= FAMILY ================= */
            if ($request->filled('family')) {
                foreach ($request->family as $row) {
                    $employee->familyMembers()->create([
                        'name'                 => $row['name'],
                        'relationship_type_id' => $row['relationship_type_id'],
                        'date_of_birth'        => $row['date_of_birth'] ?? null,
                        'gender_id'            => $row['gender_id'] ?? null,
                        'is_dependent'         => isset($row['is_dependent']),
                        'is_nominee'           => isset($row['is_nominee']),
                        'phone'                => $row['phone'] ?? null,
                    ]);
                }
            }

            /* ================= ILLNESS ================= */
            if ($request->filled('illness')) {
                foreach ($request->illness as $row) {
                    $employee->illnesses()->create([
                        'illness_id' => $row['illness_id'],
                        'diagnosed_on' => $row['diagnosed_on'] ?? null,
                        'chronic' => isset($row['chronic']),
                        'active' => isset($row['active']),
                        'notes' => $row['notes'] ?? null,
                    ]);
                }
            }

            if ($request->filled('additions')) {
                foreach ($request->additions as $row) {
                    $employee->additions()->create([
                        'addition_id'       => $row['addition_id'],
                        'calculation_type'  => $row['calculation_type'],
                        'amount'            => $row['amount'] ?? 0,
                        'status'            => $row['status'] ?? 1,
                    ]);
                }
            }

            if ($request->filled('deductions')) {
                foreach ($request->deductions as $row) {
                    $employee->deductions()->create([
                        'deduction_id'      => $row['deduction_id'],
                        'calculation_type'  => $row['calculation_type'],
                        'amount'            => $row['amount'] ?? 0,
                        'status'            => $row['status'] ?? 1,
                    ]);
                }
            }

            if ($request->filled('leaves')) {
                foreach ($request->leaves as $row) {
                    $employee->leaves()->create([
                        'year'             => $request->leave_year,
                        'leave_type_id'    => $row['leave_type_id'],
                        'number_of_days'   => $row['days'],
                    ]);
                }
            }



            /* ================= DOCUMENTS ================= */
            if ($request->has('documents')) {
                foreach ($request->documents as $index => $row) {

                    if (!isset($row['document_type_id'])) {
                        continue;
                    }

                    $path = null;

                    if ($request->hasFile("documents.$index.file")) {
                        $path = $request->file("documents.$index.file")
                            ->store("employees/{$employee->id}/documents", 'public');
                    }

                    $employee->documents()->create([
                        'document_type_id' => $row['document_type_id'],
                        'document_number' => $row['document_number'] ?? null,
                        'issue_date' => $row['issue_date'] ?? null,
                        'expiry_date' => $row['expiry_date'] ?? null,
                        'file_path' => $path,
                    ]);
                }
            }
        });

        return response()->json([
            'status' => true,
            'message' => 'Employee created successfully'
        ]);
    }


    public function edit(Employee $employee)
    {
        
         return view('core::employees/edit',$this->masterData(), [
            'employee' => $employee,
            
        ]);
    }

    /* =====================================================
     | UPDATE
     ===================================================== */
    public function update(Request $request, Employee $employee)
    {
        
        DB::transaction(function () use ($request, $employee) {

            $data = $request->except([
                'family',
                'illness',
                'documents',
                'dynamic_attributes',
                'branch_id',
                'profile_picture'
            ]);

            // Handle Profile Picture
            if ($request->hasFile('profile_picture')) {

                $file = $request->file('profile_picture');
                $filename = time().'_'.$file->getClientOriginalName();

                $file->move(public_path('storage/employees'), $filename);

                $data['profile_picture'] = 'employees/'.$filename;
            }
            /* ================= EMPLOYEE ================= */
            $employee->update($data);

            /* ================= RESET SUB TABLES ================= */
            $employee->familyMembers()->delete();
            $employee->illnesses()->delete();
            $employee->documents()->delete();

            /* ================= DYNAMIC ATTRIBUTES ================= */
            $this->saveDynamicAttributes($employee, $request);

            /* ================= FAMILY ================= */
            if ($request->filled('family')) {
                foreach ($request->family as $row) {
                    $employee->familyMembers()->create([
                        'name'                 => $row['name'],
                        'relationship_type_id' => $row['relationship_type_id'],
                        'date_of_birth'        => $row['date_of_birth'] ?? null,
                        'gender_id'            => $row['gender_id'] ?? null,
                        'is_dependent'         => isset($row['is_dependent']),
                        'is_nominee'           => isset($row['is_nominee']),
                        'phone'                => $row['phone'] ?? null,
                    ]);
                }
            }

            /* ================= ILLNESS ================= */
            if ($request->filled('illness')) {
                foreach ($request->illness as $row) {
                    $employee->illnesses()->create([
                        'illness_id' => $row['illness_id'],
                        'diagnosed_on' => $row['diagnosed_on'] ?? null,
                        'chronic' => isset($row['chronic']),
                        'active' => isset($row['active']),
                        'notes' => $row['notes'] ?? null,
                    ]);
                }
            }

            /* ================= DOCUMENTS ================= */
            if ($request->filled('documents')) {
                foreach ($request->documents as $index => $row) {

                    if (!isset($row['document_type_id'])) {
                        continue;
                    }

                    $path = null;

                    if ($request->hasFile("documents.$index.file")) {
                        $path = $request->file("documents.$index.file")
                            ->store("employees/{$employee->id}/documents", 'public');
                    }

                    $employee->documents()->create([
                        'document_type_id' => $row['document_type_id'],
                        'document_number' => $row['document_number'] ?? null,
                        'issue_date' => $row['issue_date'] ?? null,
                        'expiry_date' => $row['expiry_date'] ?? null,
                        'file_path' => $path,
                    ]);
                }
            }
        });

        return response()->json([
            'status' => true,
            'message' => 'Employee updated successfully'
        ]);
    }


    /* ==========================================================
     | DELETE
     ========================================================== */

    public function destroy(Employee $employee)
    {
        $employee->delete();

        return response()->json([
            'status'  => true,
            'message' => 'Employee deleted successfully',
        ]);
    }

    /* ==========================================================
     | STATUS TOGGLE
     ========================================================== */

    public function status(Employee $employee)
    {
        $employee->update([
            'status' => $employee->status === 'active'
                ? 'inactive'
                : 'active'
        ]);

        return response()->json([
            'status'  => true,
            'message' => 'Employee status updated',
        ]);
    }

    /* ==========================================================
     | 🔒 DYNAMIC ATTRIBUTE SAVE LOGIC (FINAL)
     ========================================================== */

    private function saveDynamicAttributes(Employee $employee, Request $request): void
    {
        if (! $request->filled('dynamic_attributes')) {
            return;
        }

        $attributes = DynamicAttribute::where('entity_type', 'Employee')
            ->where('status', true)
            ->get()
            ->keyBy('id');

        foreach ($request->dynamic_attributes as $attributeId => $value) {

            if (! isset($attributes[$attributeId])) {
                continue;
            }

            $attribute = $attributes[$attributeId];

            /** Mandatory validation */
            if ($attribute->mandatory && ($value === null || $value === '')) {
                throw new \Exception(
                    "{$attribute->name} is mandatory"
                );
            }

            /** Save / Update value */
            EmployeeDynamicAttributeValue::updateOrCreate(
                [
                    'employee_id'          => $employee->id,
                    'dynamic_attribute_id' => $attributeId,
                ],
                [
                    'value' => is_array($value)
                        ? json_encode($value)
                        : $value,
                ]
            );
        }
    }

    /* ==========================================================
     | VALIDATION
     ========================================================== */

    private function validateEmployee(Request $request, ?int $employeeId = null): void
    {
        $rules = [
            'company_id'          => 'required|exists:companies,id',
            'employee_code'       => 'required|string|max:50',
            'epf_no'              => 'required|string|max:50',
            'first_name'          => 'required|string|max:150',
            'last_name'           => 'required|string|max:150',
            'gender_id'           => 'required|exists:genders,id',
            'nationality_id'      => 'required|exists:countries,id',
            'marital_status_id'   => 'required|exists:marital_statuses,id',

            'department_id'       => 'required|exists:departments,id',
            'designation_id'      => 'required|exists:designations,id',
            'grade_id'            => 'required|exists:grades,id',
            'employment_type_id'  => 'required|exists:employment_types,id',
            'shift_id'            => 'required|exists:shifts,id',

            'date_of_joining'     => 'required|date',
        ];

        $request->validate($rules);
    }

    /* ==========================================================
     | MASTER DATA (LOCKED)
     ========================================================== */

    private function masterData(): array
    {
        return [
            'companies'          => Company::orderBy('display_name')->get(),
            'branches'           => Branch::where('status', true)->get(),
            'departments'        => Department::where('status', true)->get(),
            'designations'       => Designation::where('status', true)->get(),
            'teams'              => Team::where('status', true)->get(),
            'grades'             => Grade::where('status', true)->get(),
            'payrollGroups'      => PayrollGroup::where('status', true)->get(),
            'employmentTypes'    => EmploymentType::where('status', true)->get(),
            'shifts'             => ShiftSegment::where('status', true)->get(),

            'countries'          => Country::where('status', true)->get(),
            'cities'             => City::where('status', true)->get(),

            'banks'              => Bank::where('status', true)->get(),
            'bankBranches'       => BankBranch::where('status', true)->get(),
            'paymentMethods'     => PaymentMethod::where('status', true)->get(),
            'identificationTypes'=> IdentificationType::where('status', true)->get(),
            'relationshipTypes'  => RelationshipType::where('status', true)->get(),
            'documentTypes'      => DocumentType::where('status', true)->get(),
            'illnesses'          => Illness::where('status', true)->get(),
            /** Dynamic Attributes */
            'dynamicAttributes'  => DynamicAttribute::where('entity_type', 'Employee')
                                        ->where('status', true)
                                        ->orderBy('name')
                                        ->get(),
            'additions'          => Addition::where('status', true)->get(),
            'deductions'         => Deduction::where('status', true)->get(),
            'years'              => EmployeeController::yearRange(1990),
            'leaveTypes'         => LeaveType::where('status', true)->get(),
            'genders'            => Gender::get(),
            'marital_status'     => MaritalStatus::get(),
            'blood_groups'       => BloodGroup::get(),
            'religions'          => Religion::get(),
        ];
    }

    public static function yearRange($startYear = 1990)
    {
        $currentYear = Carbon::now()->year;

        return range($startYear, $currentYear + 1);
    }


    public function getAdditionDetails($id)
    {
        $addition = Addition::findOrFail($id);

        return response()->json([
            'calculation_type' => $addition->calculation_type,
            'amount'           => $addition->amount ?? 0,
        ]);
    }

    public function getDeductionDetails($id)
    {
        $deduction = Deduction::findOrFail($id);

        return response()->json([
            'calculation_type' => $deduction->calculation_type,
            'amount'           => $deduction->amount ?? 0,
        ]);
    }

    public function getEmployeeLeavesByYear(Employee $employee, $year)
    {
        $leaves = EmployeeLeave::with('leaveType')
            ->where('employee_id', $employee->id)
            ->where('year', $year)
            ->get();

        return response()->json($leaves);
    }
}
