<?php

namespace Tests\Unit;

use App\Services\EmployeeService;
use PHPUnit\Framework\TestCase;

class EmployeeServiceTest extends TestCase
{
    private $employeeService;

    protected function setUp(): void
    {
        parent::setUp();
        $this->employeeService = new EmployeeService();
    }

    /**
     * @dataProvider salaryGradePointProvider
     */
    public function testCalculatePointBySalaryGrade(array $rules, $salaryGrade, $expected, string $message): void
    {
        $actual = $this->employeeService->calculatePointBySalaryGrade($salaryGrade, collect($rules));
        $this->assertEquals($expected, $actual, $message);
    }

    public function salaryGradePointProvider(): array
    {
        return [
            'empty rules' => [[], 10, 0, 'Empty collection returns 0'],
            'unbounded rule' => [[(object) [
                'salary_grade_from' => null,
                'salary_grade_to' => null,
                'point_value' => 50.0,
            ]], 10, 50.0, 'Unbounded rule matches any grade'],
            'grade in range' => [[
                (object) ['salary_grade_from' => 1, 'salary_grade_to' => 24, 'point_value' => 40.0],
                (object) ['salary_grade_from' => 25, 'salary_grade_to' => 49, 'point_value' => 43.0],
            ], 30, 43.0, 'Grade in range returns matching points'],
            'from only matches above from' => [[(object) [
                'salary_grade_from' => 50,
                'salary_grade_to' => null,
                'point_value' => 45.0,
            ]], 60, 45.0, 'From-only rule matches grades above from'],
            'from only rejects below from' => [[(object) [
                'salary_grade_from' => 50,
                'salary_grade_to' => null,
                'point_value' => 45.0,
            ]], 40, 0, 'From-only rule rejects grades below from'],
            'to only matches below to' => [[(object) [
                'salary_grade_from' => null,
                'salary_grade_to' => 24,
                'point_value' => 40.0,
            ]], 20, 40.0, 'To-only rule matches grades below to'],
            'to only rejects above to' => [[(object) [
                'salary_grade_from' => null,
                'salary_grade_to' => 24,
                'point_value' => 40.0,
            ]], 30, 0, 'To-only rule rejects grades above to'],
            'boundary lower range' => [[
                (object) ['salary_grade_from' => 1, 'salary_grade_to' => 24, 'point_value' => 40.0],
                (object) ['salary_grade_from' => 25, 'salary_grade_to' => 49, 'point_value' => 43.0],
                (object) ['salary_grade_from' => 50, 'salary_grade_to' => null, 'point_value' => 45.0],
            ], 15, 40.0, 'Grade 15 matches range 1-24'],
            'boundary middle range' => [[
                (object) ['salary_grade_from' => 1, 'salary_grade_to' => 24, 'point_value' => 40.0],
                (object) ['salary_grade_from' => 25, 'salary_grade_to' => 49, 'point_value' => 43.0],
                (object) ['salary_grade_from' => 50, 'salary_grade_to' => null, 'point_value' => 45.0],
            ], 35, 43.0, 'Grade 35 matches range 25-49'],
            'boundary upper range' => [[
                (object) ['salary_grade_from' => 1, 'salary_grade_to' => 24, 'point_value' => 40.0],
                (object) ['salary_grade_from' => 25, 'salary_grade_to' => 49, 'point_value' => 43.0],
                (object) ['salary_grade_from' => 50, 'salary_grade_to' => null, 'point_value' => 45.0],
            ], 60, 45.0, 'Grade 60 matches range 50+'],
            'lower boundary inclusive' => [[
                (object) ['salary_grade_from' => 1, 'salary_grade_to' => 24, 'point_value' => 40.0],
                (object) ['salary_grade_from' => 25, 'salary_grade_to' => 49, 'point_value' => 43.0],
                (object) ['salary_grade_from' => 50, 'salary_grade_to' => null, 'point_value' => 45.0],
            ], 24, 40.0, 'Grade 24 is inclusive'],
            'upper boundary inclusive' => [[
                (object) ['salary_grade_from' => 1, 'salary_grade_to' => 24, 'point_value' => 40.0],
                (object) ['salary_grade_from' => 25, 'salary_grade_to' => 49, 'point_value' => 43.0],
                (object) ['salary_grade_from' => 50, 'salary_grade_to' => null, 'point_value' => 45.0],
            ], 25, 43.0, 'Grade 25 is inclusive'],
            'null grade' => [[(object) [
                'salary_grade_from' => 1,
                'salary_grade_to' => 24,
                'point_value' => 40.0,
            ]], null, 0, 'Null grade returns 0'],
            'empty grade' => [[(object) [
                'salary_grade_from' => 1,
                'salary_grade_to' => 24,
                'point_value' => 40.0,
            ]], '', 0, 'Empty grade returns 0'],
        ];
    }
}
