<?php

namespace App\Services\HrPayroll;

use App\Constants\Common;
use App\Constants\Status;
use App\Filters\EmployeeFilter;
use App\Models\Academic\Branch;
use App\Models\Academic\Shift;
use App\Models\HrPayroll\Designation;
use App\Models\HrPayroll\Employee;
use App\Models\HrPayroll\EmployeeEducation;
use App\Models\HrPayroll\EmployeeSalary;
use App\Models\HrPayroll\EmployeeType;
use App\Models\HrPayroll\HrDepartment;
use App\Models\HrPayroll\MonthlySalary;
use App\Models\HrPayroll\SalaryGrade;
use App\Models\HrPayroll\SalaryHead;
use App\Models\User;
use App\Services\FileUploadService;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;
use Spatie\Permission\Models\Role;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\Hash;

class EmployeeService
{

    protected $fileUploadService;

    public function __construct(FileUploadService $fileUploadService)
    {
        $this->fileUploadService = $fileUploadService;
    }

    public function getEmployee(array $queryParams = [])
    {
        $queryBuilder = Employee::with(['branch', 'shift'])->latest();

        $employees = resolve(EmployeeFilter::class)->getResults([
            'builder' => $queryBuilder,
            'params' => $queryParams
        ]);

        return $employees->get();
    }

    public function getSingleEmployeeData($id)
    {
        $employee = Employee::with('employee_education', 'user', 'salaryGrade.salaryGradeRules.salaryHead')
                    ->where('id', '=', $id)
                    ->first();
        return $employee;
    }

    public function store(Request $request)
    {
        $this->validateRequest($request);

        return DB::transaction(function () use ($request) {
            Cache::forget('total_employees');
            $profileImage = $this->handleProfileImage($request);
            $user = $this->createUser($request, $profileImage);
            $user->syncRoles($request->roles);
            $employee = $this->createEmployee($request, $user->id, $profileImage);
            $this->storeEducationInfo($request->education_infos, $employee->id);
            $this->storeEmployeeSalary($request, $employee->id);

            return $user;
        });
    }

    public function update(Request $request, $employee)
    {
        $this->validateRequest($request);

        return DB::transaction(function () use ($request, $employee) {
            Cache::forget('total_employees');
            $user = User::where('id', $employee->user_id)->first();
            $profileImage = $this->handleProfileImage($request);
            $this->updateUser($user, $request, $profileImage);
            $user->syncRoles($request->roles);
            if ($employee) {
                $this->updateEmployee($employee, $request, $profileImage);
            }

            // Handle education info update
            $this->updateEducationInfo($request->education_infos, $employee->id);
            $this->storeEmployeeSalary($request, $employee->id);
            return $user;
        });
    }

    private function validateRequest(Request $request)
    {
        $request->validate([
            'first_name' => 'required',
            'last_name' => 'required',
            'gender' => 'required',
            'mobile_number' => 'required',
            // 'email' => 'required',
            // 'date_of_birth' => 'required',
            'religion' => 'required',
            // 'father_name' => 'required',
            // 'mother_name' => 'required',
            // 'marital_status' => 'required',
            // 'present_address' => 'required',
            // 'permanent_address' => 'required',
            // 'emergency_number' => 'required',
            // 'identity_type' => 'required',
            // 'identity_no' => 'required',

        ]);
    }

    private function handleProfileImage(Request $request, $existingFile='')
    {
        if ($request->hasFile('profile_image')) {
            $file = $request->file('profile_image');
            return $this->fileUploadService->upload($file, 'uploads/employee', $existingFile);
        }
        return "";
    }

    private function createUser(Request $request, $profileImage)
    {
        return User::create([
            'first_name' => $request->first_name,
            'last_name' => $request->last_name,
            'name' => $request->first_name . ' ' . $request->last_name,
            'slug' => Str::slug($request->first_name . ' ' . $request->last_name),
            'user_type' => $request->user_type,
            'branch_id' => auth()->user()->branch_id,
            'phone_number' => $request->mobile_no,
            'email' => $request->mobile_no,
            'profile_image_path' => $profileImage,
            'status' => 1,
            'password' => Hash::make('12345678'),
        ]);
    }

    private function updateUser(User $user, Request $request, $profileImage)
    {
        $user->update([
            'first_name' => $request->first_name,
            'last_name' => $request->last_name,
            'name' => $request->first_name . ' ' . $request->last_name,
            'slug' => Str::slug($request->first_name . ' ' . $request->last_name),
            'phone_number' => $request->mobile_no,
            'email' => $request->mobile_no,
            'profile_image_path' => $profileImage ? $profileImage : $user->profile_image_path,
        ]);
    }

    private function createEmployee(Request $request, $user_id, $profileImage)
    {
        return Employee::create([
            'user_id' => $user_id,
            'user_type' => $request->user_type,
            'first_name' => $request->first_name,
            'last_name' => $request->last_name,
            'name' => $request->first_name . ' ' . $request->last_name,
            'gender' => $request->gender,
            'date_of_birth' => $request->date_of_birth,
            'blood_group' => $request->blood_group,
            'religion' => $request->religion,
            'father_name' => $request->father_name,
            'mother_name' => $request->mother_name,
            'marital_status' => $request->marital_status,
            'spaous_name' => $request->spaous_name,
            'present_address' => $request->present_address,
            'permanent_address' => $request->permanent_address,
            'mobile_number' => $request->mobile_number,
            'emergency_number' => $request->emergency_number,
            'email' => $request->email,
            'identity_type' => $request->identity_type,
            'identity_no' => $request->identity_no,

            'bank_name' => $request->bank_name,
            'branch_name' => $request->branch_name,
            'account_no' => $request->account_no,
            'account_type' => $request->account_type,
            'bank_branch_code' => $request->bank_branch_code,

            'employee_photo' => $profileImage,
            'employee_type_id' => $request->employee_type,
            'branch_id' => $request->branch_id,
            'shift_id' => $request->shift_id,
            'designation_id' => $request->designation_id,
            'department_id' => $request->department_id,
            'joining_date' => $request->joining_date,
            'salary_grade_id' => $request->salary_grade,
            'salary' => $request->salary,

            'created_by' => auth()->user()->id,
        ]);
    }

    private function updateEmployee(Employee $employee, Request $request, $profileImage)
    {
        $employee->update([
            'first_name' => $request->first_name,
            'last_name' => $request->last_name,
            'name' => $request->first_name . ' ' . $request->last_name,
            'gender' => $request->gender,
            'date_of_birth' => $request->date_of_birth,
            'blood_group' => $request->blood_group,
            'religion' => $request->religion,
            'father_name' => $request->father_name,
            'mother_name' => $request->mother_name,
            'marital_status' => $request->marital_status,
            'spaous_name' => $request->spaous_name,
            'present_address' => $request->present_address,
            'permanent_address' => $request->permanent_address,
            'mobile_number' => $request->mobile_number,
            'emergency_number' => $request->emergency_number,
            'email' => $request->email,
            'identity_type' => $request->identity_type,
            'identity_no' => $request->identity_no,

            'bank_name' => $request->bank_name,
            'branch_name' => $request->branch_name,
            'account_no' => $request->account_no,
            'account_type' => $request->account_type,
            'bank_branch_code' => $request->bank_branch_code,

            'employee_photo' => $profileImage ? $profileImage : $employee->employee_photo,
            'employee_type_id' => $request->employee_type,
            'branch_id' => $request->branch_id,
            'shift_id' => $request->shift_id,
            'designation_id' => $request->designation_id,
            'department_id' => $request->department_id,
            'joining_date' => $request->joining_date,
            'salary_grade_id' => $request->salary_grade,
            'salary' => $request->salary,

            'updated_by' => auth()->user()->id,
        ]);
    }


    private function storeEducationInfo($educationInfos, $employeeId)
    {
        $education_data = [];
        if($educationInfos && $educationInfos[0]['exam_name'] != null && $educationInfos[0]['institute'] != null){
            foreach ($educationInfos as $education) {
                $education_data[] = [
                    'employee_id' => $employeeId,
                    'exam_name' => $education['exam_name'],
                    'institute' => $education['institute'],
                    'group_department' => $education['group_department'],
                    'education_board' => $education['education_board'],
                    'passing_year' => $education['passing_year'],
                    'result' => $education['result'],
                ];
            }
        }
        EmployeeEducation::insert($education_data);
    }

    private function updateEducationInfo($educationInfos, $employeeId)
    {
        EmployeeEducation::where('employee_id', $employeeId)->delete();
        $this->storeEducationInfo($educationInfos, $employeeId);
    }


    private function storeEmployeeSalary($request, $employee_id)
    {
        $from_date = date('Y-m-1');
        $to_date = date('Y-m-t');

        if ($request->salary && $request->salary_grade && $employee_id) {

            $employee_salary = EmployeeSalary::where('employee_id', $employee_id)
                ->whereBetween('created_at', [$from_date,  $to_date])
                ->where('salary_grade_id', $request->salary_grade)
                ->where('status', Status::ACTIVE)
                ->first();

            $monthly_salary = MonthlySalary::where('employee_id', $employee_id)
                ->whereBetween('process_date', [$from_date,  $to_date])
                ->where('salary_grade_id', $request->salary_grade)
                ->where('status', Status::PAID)->first();

            if (!empty($employee_salary) && empty($monthly_salary)) {
                //update employee salary
                $employee_salary->update([
                    'employee_id' => $employee_id,
                    'status' => Status::ACTIVE,
                    'salary_grade_id' => $request->salary_grade,
                    'amount' => $request->salary,
                ]);
            } else {
                //insert employee salary
                EmployeeSalary::where('employee_id', $employee_id)->update(['status' => Status::INACTIVE]);
                EmployeeSalary::create([
                    'employee_id' => $employee_id,
                    'status' => Status::ACTIVE,
                    'salary_grade_id' => $request->salary_grade,
                    'amount' => $request->salary,
                ]);
            }
        }
    }


    public function delete($id)
    {
        $employee = Employee::findOrFail($id);
        $employee->user->delete();
        $employee->delete();
    }

    public function getRelatedData()
    {
        return [
            'branches' => Branch::pluck('branch_name','id'),
            'shifts' => Shift::pluck('shift_name', 'id'),
            'departments' => HrDepartment::pluck('name', 'id'),
            'designations' => Designation::pluck('name', 'id'),
            'roles' => Role::pluck('display_name', 'name'),
            'employee_types' => EmployeeType::pluck('emp_type', 'id'),
            'exam_names' => Common::EXAM_NAMES,
            'marital_status' => Status::MARITAL_STATUS,
            'identity_types' => Common::IDENTITY_TYPE,
            'salary_grades' => SalaryGrade::pluck('title','id'),
            'salary_heads' => SalaryHead::get(),
        ];
    }

    public function getFormdData()
    {
        return [
            'branches' => Branch::pluck('branch_name','id'),
            'shifts' => Shift::pluck('shift_name', 'id'),
            'departments' => HrDepartment::pluck('name', 'id'),
            'designations' => Designation::pluck('name', 'id'),
            'employee_types' => EmployeeType::pluck('emp_type', 'id'),
        ];
    }

    public function searchEmployee($query)
    {
        $students = Employee::where('employee_code', 'LIKE', "%{$query}%")
            ->orWhere('mobile_number', 'LIKE', "%{$query}%")
            ->take(15)
            ->get(['employee_code', 'mobile_number', 'first_name', 'last_name']);

        return $students;
    }

}
