<?php

namespace Modules\Employee\Services;

use Modules\Employee\Repositories\EmpHolidayGroupRepository;
use Modules\Employee\DTO\EmployeeSettingFilter;
use Illuminate\Support\Facades\DB;
use Carbon\Carbon;
use Modules\Core\Enums\StatusEnum;
use Modules\Core\Exceptions\ApiValidationException;
use Modules\Employee\Models\EmployeeHolidayGroup;

class EmpHolidayGroupService
{

    public function __construct(protected EmpHolidayGroupRepository $empHolidayGroupRepo) {}

    public function list(EmployeeSettingFilter $filter)
    {
        $columns = ['id', 'employee_id', 'holiday_group_id', 'status', 'assigned_from', 'assigned_to'];
        $relations = ['employee:id,name', 'holidayGroup:id,name'];

        return $this->empHolidayGroupRepo->all($filter, $columns, $relations);
    }

    public function show($id)
    {
        $relations = ['employee:id,name', 'holidayGroup.holidays'];
        return $this->empHolidayGroupRepo->find($id)->load($relations);
    }


    public function assign(array $data)
    {
        $employeeId = $data['employee_id'];
        $requestedFrom = Carbon::parse($data['assigned_from']);
        $requestedTo = isset($data['assigned_to']) ? Carbon::parse($data['assigned_to']) : null;

        $isOverlapping = EmployeeHolidayGroup::where('employee_id', $employeeId)
            ->where('status', StatusEnum::ACTIVE)
            ->where(function ($query) use ($requestedFrom, $requestedTo) {
                $query->where(function ($q) use ($requestedFrom) {
                    $q->where('assigned_from', '<=', $requestedFrom)
                        ->where(function ($sub) use ($requestedFrom) {
                            $sub->whereNull('assigned_to')
                                ->orWhere('assigned_to', '>=', $requestedFrom);
                        });
                })
                    ->orWhere(function ($q) use ($requestedTo) {
                        if ($requestedTo) {
                            $q->where('assigned_from', '<=', $requestedTo)
                                ->where(function ($sub) use ($requestedTo) {
                                    $sub->whereNull('assigned_to')
                                        ->orWhere('assigned_to', '>=', $requestedTo);
                                });
                        } else {
                            $q->whereNull('assigned_to')
                                ->orWhere('assigned_to', '>=', Carbon::now());
                        }
                    });
            })
            ->exists();

        if ($isOverlapping) {
            ApiValidationException::errors([
                'assigned_from' => ['This employee already has an active holiday group during this period. Please transfer or close the previous group first.']
            ]);
        }

        return DB::transaction(function () use ($data) {
            return $this->empHolidayGroupRepo->assign($data);
        });
    }

    public function transfer(array $data)
    {
        return DB::transaction(function () use ($data) {
            $employeeId = $data['employee_id'];
            $newGroupId = $data['new_holiday_group_id'];
            $effectiveDate = Carbon::parse($data['effective_date']);

            $currentGroup = EmployeeHolidayGroup::where('employee_id', $employeeId)
                ->where('status', StatusEnum::Active->value)
                ->whereNull('assigned_to')
                ->first();

            if ($currentGroup) {
                // ভ্যালিডেশন: কার্যকর তারিখটি যেন বর্তমান গ্রুপের শুরুর তারিখের আগের বা সমান না হয়
                if ($effectiveDate->lessThanOrEqualTo(Carbon::parse($currentGroup->assigned_from))) {
                    ApiValidationException::errors([
                        'effective_date' => ['The effective date must be after the current group start date (' . $currentGroup->assigned_from . ').']
                    ]);
                }
                // পুরনো সক্রিয় রেকর্ডের শেষ তারিখ আপডেট করা (নতুন কার্যকর তারিখের ঠিক আগের দিন)
                $currentGroup->update([
                    'assigned_to' => $effectiveDate->copy()->subDay()->format('Y-m-d'),
                    'status' => StatusEnum::Inactive->value,
                ]);
            }

            // ২. রিপোজিটরির মাধ্যমে নতুন গ্রুপে কর্মচারীর অ্যাসাইনমেন্ট রেকর্ড তৈরি করা
            // এখানে রিপোজিটরিতে ডাটা পাঠানোর জন্য অ্যারে ফরম্যাট করা হচ্ছে
            $transferData = [
                'employee_id'      => $employeeId,
                'holiday_group_id' => $newGroupId,
                'assigned_from'    => $effectiveDate->format('Y-m-d'),
                'assigned_to'      => null, // নতুন রেকর্ডটি ওপেন-এন্ডেড হিসেবে শুরু হবে
                'status'           => $data['status'] ?? StatusEnum::Active->value,
            ];

            return $this->empHolidayGroupRepo->assign($transferData);
        });
    }
}
