package io.delphiplatform.api.v3.view;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

import java.time.LocalDate;

import io.delphiplatform.api.v3.view.util.Params;

class ParamsTest {

    @Test
    void getStartDateAndEndDate_noCursor() {
        LocalDate testStartDate = LocalDate.of(2020, 10, 10);
        LocalDate testEndDate = LocalDate.of(2020, 10, 20);

        Params params = Params.builder()
            .startDate(testStartDate)
            .endDate(testEndDate)
            .limit(100)
            .offset(10)
            .build();

        Assertions.assertEquals(testStartDate, params.getStartDate());
        Assertions.assertEquals(testEndDate, params.getEndDate());
        Assertions.assertEquals(100, params.getLimit());
        Assertions.assertEquals(10, params.getOffset());
    }

    /*
     * start_date = 2020-01-01
     * range = 5 days
     * dates 1rst, 2nd, 3rd, 4th, 5th -> end_date = 2020-01-05
     */
    @Test
    void getStartDateAndEndDate_correctCursorRange() {
        LocalDate testStartDate = LocalDate.of(2020, 1, 1);
        LocalDate testEndDate = LocalDate.of(2020, 2, 1);

        Params params = Params.builder()
            .startDate(testStartDate)
            .endDate(testEndDate)
            .limit(10)
            .offset(10)
            .limitRange("days:5")
            .cursor("date:2020-01-01")
            .build();

        Assertions.assertEquals(LocalDate.of(2020, 1, 1), params.getStartDate());
        Assertions.assertEquals(LocalDate.of(2020, 1, 5), params.getEndDate());
        Assertions.assertEquals("date:2020-01-06", params.getNextCursor());
        Assertions.assertEquals(10, params.getLimit());
        Assertions.assertEquals(10, params.getOffset());
    }

    /**
     * cursor ignored, but limit_range days used
     */
    @Test
    void getStartDateAndEndDate_ignoresCursor() {
        LocalDate testStartDate = LocalDate.of(2020, 10, 10);
        LocalDate testEndDate = LocalDate.of(2020, 10, 20);

        Params params = Params.builder()
            .startDate(testStartDate)
            .endDate(testEndDate)
            .limit(10)
            .offset(10)
            .limitRange("days:5")
            .cursor("date:2020-01-01")
            .build();

        Assertions.assertEquals(testStartDate, params.getStartDate());
        Assertions.assertEquals(LocalDate.of(2020, 10, 14), params.getEndDate());
        Assertions.assertEquals("date:2020-10-15", params.getNextCursor());
        Assertions.assertEquals(10, params.getLimit());
        Assertions.assertEquals(10, params.getOffset());
    }

    @Test
    void getNextCursor_rangeFor10Days() {
        Params params = Params.builder()
            .startDate(LocalDate.parse("2019-12-22"))
            .endDate(LocalDate.parse("2020-02-01"))
            .limitRange("days:10")
            .cursor("date:2020-01-01")
            .build();

        Assertions.assertEquals("date:2020-01-11", params.getNextCursor());
        Assertions.assertEquals(LocalDate.parse("2020-01-10"), params.getEndDate());
    }

    @Test
    void getNextCursor_endOfPage() {
        Params params = Params.builder()
            .startDate(LocalDate.parse("2019-12-01"))
            .endDate(LocalDate.parse("2020-01-10"))
            .limitRange("days:10")
            .cursor("date:2020-01-01")
            .build();

        Assertions.assertNull(params.getNextCursor());
        Assertions.assertEquals(LocalDate.parse("2020-01-10"), params.getEndDate());
    }

    /**
     * end_date == next_cursor
     */
    @Test
    void getNextCursor_equalsEndDate() {
        Params params = Params.builder()
            .startDate(LocalDate.parse("2020-01-01"))
            .endDate(LocalDate.parse("2020-01-05"))
            .limitRange("days:4")
            .cursor("date:2020-01-01")
            .build();

        Assertions.assertEquals("date:2020-01-05", params.getNextCursor());
    }

    /**
     * limit_range:days exceeds remaining days until end_date
     */
    @Test
    void getNextCursor_rangePastEndDate() {
        Params params = Params.builder()
            .startDate(LocalDate.parse("2019-12-01"))
            .endDate(LocalDate.parse("2020-01-05"))
            .limitRange("days:10")
            .cursor("date:2020-01-01")
            .build();

        Assertions.assertNull(params.getNextCursor());
        Assertions.assertEquals(LocalDate.parse("2020-01-05"), params.getEndDate());
    }

    /**
     * limit_range:days exceeds remaining days until end_date
     */
    @Test
    void getStartDate_cursorEqualsEndDate() {
        Params params = Params.builder()
            .startDate(LocalDate.parse("2019-12-01"))
            .endDate(LocalDate.parse("2020-01-05"))
            .limitRange("days:10")
            .cursor("date:2020-01-05")
            .build();

        Assertions.assertNull(params.getNextCursor());
        Assertions.assertEquals(LocalDate.parse("2020-01-05"), params.getStartDate());
    }

    /**
     * Cursor outside start-end date range
     */
    @Test
    void getEndDate_ignoresCursor() {
        Params params = Params.builder()
            .startDate(LocalDate.parse("2020-01-01"))
            .endDate(LocalDate.parse("2020-01-05"))
            .limitRange("days:10")
            .cursor("date:2020-02-01")
            .build();

        Assertions.assertNull(params.getNextCursor());
        Assertions.assertEquals(LocalDate.parse("2020-01-05"), params.getEndDate());
    }

    /**
     * Contains limit_range but no cursor
     */
    @Test
    void getEndDate_limitRangeNoCursor() {
        Params params = Params.builder()
            .startDate(LocalDate.parse("2020-01-01"))
            .endDate(LocalDate.parse("2020-01-10"))
            .limitRange("days:5")
            .build();

        Assertions.assertEquals("date:2020-01-06", params.getNextCursor());
        Assertions.assertEquals(LocalDate.parse("2020-01-05"), params.getEndDate());
    }

    @Test
    void getNextCursor_noRanges() {
        LocalDate testStartDate = LocalDate.of(2020, 10, 10);
        LocalDate testEndDate = LocalDate.of(2020, 10, 20);

        Params params = Params.builder()
            .startDate(testStartDate)
            .endDate(testEndDate)
            .build();

        Assertions.assertNull(params.getNextCursor());
    }

}
