<?php

namespace App\Modules\Company\Whiteboard\ReassignWorker\ConflictChecker;

use App\Models\AssignedWorkers;
use App\Models\Availabilities;
use App\Models\BorrowApproved;

class UnavailableSchedulesConflictChecker
{
    public function checkConflictForUnavailableSchedules($companyId, $workerId, $workerType, $userInputStartDate, $userInputEndDate)
    {
        $conflictingAvailabilitiesData = Availabilities::select(
            'availabilities.min_availability_date as date_from',
            'availabilities.max_availability_date as date_to')
            ->where(function ($query) use ($userInputStartDate, $userInputEndDate) {
                $query->where('availabilities.min_availability_date', $userInputStartDate)
                    ->orWhere('availabilities.max_availability_date', $userInputEndDate)
                    ->orWhereBetween('availabilities.min_availability_date', [$userInputStartDate, $userInputEndDate])
                    ->orWhereBetween('availabilities.max_availability_date', [$userInputStartDate, $userInputEndDate])
                    ->orWhereRaw('? BETWEEN availabilities.min_availability_date and availabilities.max_availability_date', [$userInputStartDate])
                    ->orWhereRaw('? BETWEEN availabilities.min_availability_date and availabilities.max_availability_date', [$userInputEndDate]);
            })
            ->where('availabilities.worker_id', $workerId)
            ->where('availabilities.company_id', '!=', $companyId)
            ->when($workerType == 'inhouse', function ($query) {
                return $query->where('availabilities.worker_type', 'borrowed');
            })
            ->when($workerType == 'borrowed', function ($query) {
                return $query->where('availabilities.worker_type', 'inhouse');
            })
            ->orderBy('availabilities.min_availability_date', 'ASC')
            ->orderBy('availabilities.max_availability_date', 'ASC')
            ->get();

        $conflictingAssignWorkerData = AssignedWorkers::select(
            'assigned_availability.start_date as date_from',
            'assigned_availability.end_date as date_to')
            ->join('assigned_availability', 'assigned_availability.assigned_worker_id', '=', 'assigned_workers.id')
            ->join('projects', 'projects.id', '=', 'assigned_workers.project_id')
            ->where('assigned_workers.worker_id', $workerId)
            ->where('projects.company_id', '!=', $companyId)
            ->when($workerType == 'inhouse', function ($query) {
                return $query->where('assigned_availability.worker_type', 'borrowed');
            })
            ->when($workerType == 'borrowed', function ($query) {
                return $query->where('assigned_availability.worker_type', 'inhouse');
            })
            ->where(function ($query) use ($userInputStartDate, $userInputEndDate) {
                $query->where('assigned_availability.start_date', $userInputStartDate)
                    ->orWhere('assigned_availability.end_date', $userInputEndDate)
                    ->orWhereBetween('assigned_availability.start_date', [$userInputStartDate, $userInputEndDate])
                    ->orWhereBetween('assigned_availability.end_date', [$userInputStartDate, $userInputEndDate])
                    ->orWhereRaw('? BETWEEN assigned_availability.start_date and assigned_availability.end_date', [$userInputStartDate])
                    ->orWhereRaw('? BETWEEN assigned_availability.start_date and assigned_availability.end_date', [$userInputEndDate]);
            })
            ->get();

        if (count($conflictingAvailabilitiesData) > 0 || count($conflictingAssignWorkerData) > 0) {
            $fetchConflictingSchedules = $this->fetchConflictingSchedules($companyId, $workerId, $workerType, $userInputStartDate, $userInputEndDate);
            if ($workerType == 'inhouse') {
                return response()->json([
                    'error' => 'Schedule unavailable due to the worker is being borrowed on the selected dates.',
                    'conflicting_schedule' => $fetchConflictingSchedules,
                    'allow_override' => false,
                ])->setStatusCode(201);
            } else if ($workerType == 'borrowed') {
                return response()->json([
                    'error' => 'Schedule unavailable due to the worker is not being borrowed on the selected dates.',
                    'suggested_dates' => $fetchConflictingSchedules,
                    'allow_override' => false,
                ])->setStatusCode(201);
            }
        }

        return 'no conflict';
    }

    public function fetchConflictingSchedules($companyId, $workerId, $workerType, $userInputStartDate, $userInputEndDate)
    {
        return BorrowApproved::select(
            'borrow_approved_histories.date_from',
            'borrow_approved_histories.date_to')
            ->where('borrow_approved_histories.worker_id', $workerId)
            ->when($workerType == 'inhouse', function ($query) use ($companyId, $userInputStartDate, $userInputEndDate) {
                return $query->where('borrow_approved_histories.loaner_company_id', $companyId)
                    ->where(function ($query) use ($userInputStartDate, $userInputEndDate) {
                        $query->where('borrow_approved_histories.date_from', $userInputStartDate)
                            ->orWhere('borrow_approved_histories.date_to', $userInputEndDate)
                            ->orWhereBetween('borrow_approved_histories.date_from', [$userInputStartDate, $userInputEndDate])
                            ->orWhereBetween('borrow_approved_histories.date_to', [$userInputStartDate, $userInputEndDate])
                            ->orWhereRaw('? BETWEEN borrow_approved_histories.date_from and borrow_approved_histories.date_to', [$userInputStartDate])
                            ->orWhereRaw('? BETWEEN borrow_approved_histories.date_from and borrow_approved_histories.date_to', [$userInputEndDate]);
                    });
            })
            ->when($workerType == 'borrowed', function ($query) use ($companyId, $userInputStartDate, $userInputEndDate) {
                return $query->where('borrow_approved_histories.borrower_company_id', $companyId)
                    ->where(function ($query) use ($userInputStartDate, $userInputEndDate) {
                        $query->where('borrow_approved_histories.date_from', '!=', $userInputStartDate)
                            ->orWhere('borrow_approved_histories.date_to', '!=', $userInputEndDate)
                            ->orWhereNotBetween('borrow_approved_histories.date_from', [$userInputStartDate, $userInputEndDate])
                            ->orWhereNotBetween('borrow_approved_histories.date_to', [$userInputStartDate, $userInputEndDate])
                            ->orWhereRaw('? NOT BETWEEN borrow_approved_histories.date_from and borrow_approved_histories.date_to', [$userInputStartDate])
                            ->orWhereRaw('? NOT BETWEEN borrow_approved_histories.date_from and borrow_approved_histories.date_to', [$userInputEndDate]);
                    });
            })
            ->limit(10)
            ->get();
    }
}
