<?php

namespace App\Repositories;

use App\Models\EmployeeLeave;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Collection;

class LeaveRepository extends BaseRepository
{
    protected function resolveModel(): Model
    {
        return new EmployeeLeave();
    }

    /**
     * Get leaves with employee details
     */
    public function getWithEmployee(): Collection
    {
        return $this->with(['employee', 'approver'])
            ->orderBy('created_at', 'desc')
            ->all();
    }

    /**
     * Get leaves by employee
     */
    public function getByEmployee(int $employeeId): Collection
    {
        return $this->where('employee_id', $employeeId)
            ->orderBy('leave_from', 'desc')
            ->all();
    }

    /**
     * Get pending leaves
     */
    public function getPending(): Collection
    {
        return $this->where('status', EmployeeLeave::STATUS_PENDING)
            ->with(['employee'])
            ->orderBy('created_at', 'desc')
            ->all();
    }

    /**
     * Get pending leaves by department
     */
    public function getPendingByDepartment(string $department): Collection
    {
        $query = $this->getQuery();
        $query->where('status', EmployeeLeave::STATUS_PENDING)
            ->where('department', $department)
            ->with(['employee'])
            ->orderBy('created_at', 'desc');
        $result = $query->get();
        $this->resetQuery();
        return $result;
    }

    /**
     * Get leaves for date range
     */
    public function getByDateRange(string $start, string $end): Collection
    {
        return $this->whereBetween('leave_from', [$start, $end])
            ->with(['employee'])
            ->orderBy('leave_from', 'asc')
            ->all();
    }

    /**
     * Get leaves for an employee in date range
     */
    public function getEmployeeLeavesInRange(int $employeeId, string $start, string $end): Collection
    {
        $query = $this->getQuery();
        $query->where('employee_id', $employeeId)
            ->where(function ($q) use ($start, $end) {
                $q->whereBetween('leave_from', [$start, $end])
                  ->orWhereBetween('leave_to', [$start, $end]);
            })
            ->orderBy('leave_from', 'asc');
        $result = $query->get();
        $this->resetQuery();
        return $result;
    }

    /**
     * Get leaves by year for an employee
     */
    public function getByYear(int $employeeId, int $year, ?string $leaveType = null): Collection
    {
        $query = $this->getQuery();
        $query->where('employee_id', $employeeId)
            ->whereYear('leave_from', $year);

        if ($leaveType) {
            $query->where('leave_type', $leaveType);
        }

        $query->orderBy('leave_from', 'desc');
        $result = $query->get();
        $this->resetQuery();
        return $result;
    }

    /**
     * Check for overlapping leaves
     */
    public function hasOverlappingLeave(int $employeeId, string $from, string $to, ?int $excludeId = null): bool
    {
        $query = $this->getQuery();
        $query->where('employee_id', $employeeId)
            ->where('status', '!=', EmployeeLeave::STATUS_REJECTED)
            ->where(function ($q) use ($from, $to) {
                $q->whereBetween('leave_from', [$from, $to])
                  ->orWhereBetween('leave_to', [$from, $to])
                  ->orWhere(function ($inner) use ($from, $to) {
                      $inner->where('leave_from', '<=', $from)
                            ->where('leave_to', '>=', $to);
                  });
            });

        if ($excludeId) {
            $query->where('id', '!=', $excludeId);
        }

        $exists = $query->exists();
        $this->resetQuery();
        return $exists;
    }

    /**
     * Get approved and pending CL count for year
     */
    public function getClCountForYear(int $employeeId, int $year): float
    {
        $query = $this->getQuery();
        $result = $query->where('employee_id', $employeeId)
            ->where('leave_type', EmployeeLeave::TYPE_CL)
            ->whereYear('leave_from', $year)
            ->whereIn('status', [EmployeeLeave::STATUS_APPROVED, EmployeeLeave::STATUS_PENDING])
            ->sum('number_of_days');
        $this->resetQuery();
        return (float) $result;
    }
}
