package com.lingniu.ingest.eventhistory;

import com.lingniu.ingest.tdenginehistory.TdengineHistoryReader;
import com.lingniu.ingest.tdenginehistory.TdengineLocationQuery;
import com.lingniu.ingest.tdenginehistory.TdengineLocationRow;
import com.lingniu.ingest.tdenginehistory.TdenginePage;
import com.lingniu.ingest.tdenginehistory.TdenginePageCursor;
import com.lingniu.ingest.tdenginehistory.TdengineQueryOrder;
import org.junit.jupiter.api.Test;
import org.springframework.http.HttpStatus;
import org.springframework.web.server.ResponseStatusException;

import java.io.IOException;
import java.time.Instant;
import java.util.List;
import java.util.Optional;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;

class Jt808LocationHistoryControllerTest {

    @Test
    void queriesLocationsByPhoneWithKeysetCursor() throws Exception {
        CapturingReader reader = new CapturingReader(new TdenginePage<>(
                List.of(row("fact-1", "2026-06-29T05:00:01Z")),
                Optional.of(new TdenginePageCursor(Instant.parse("2026-06-29T05:00:01Z"), "fact-1"))));
        Jt808LocationHistoryController controller = new Jt808LocationHistoryController(reader);

        Jt808LocationHistoryController.LocationPageResponse response = controller.locations(
                "g7gps",
                "2026-06-29T13:00:00+08:00",
                "2026-06-29T13:10:00+08:00",
                TdengineQueryOrder.DESC,
                50,
                "2026-06-29T05:00:00Z",
                "fact-0");

        assertThat(reader.query.protocol()).isEqualTo("JT808");
        assertThat(reader.query.vehicleKey()).isEqualTo("jt808:g7gps");
        assertThat(reader.query.order()).isEqualTo(TdengineQueryOrder.DESC);
        assertThat(reader.query.limit()).isEqualTo(50);
        assertThat(reader.query.cursor()).isEqualTo(new TdenginePageCursor(
                Instant.parse("2026-06-29T05:00:00Z"), "fact-0"));
        assertThat(response.items())
                .extracting(Jt808LocationHistoryController.LocationResponse::factId)
                .containsExactly("fact-1");
        assertThat(response.items().getFirst().longitude()).isEqualTo(113.12);
        assertThat(response.nextCursor()).isEqualTo(new Jt808LocationHistoryController.CursorResponse(
                "2026-06-29T05:00:01Z", "fact-1"));
    }

    @Test
    void returnsLocationRawUriFromCoreColumn() throws Exception {
        CapturingReader reader = new CapturingReader(new TdenginePage<>(
                List.of(row(
                        "fact-blank-raw",
                        "2026-06-29T05:00:01Z",
                        "archive://jt808/core-frame.bin")),
                Optional.empty()));
        Jt808LocationHistoryController controller = new Jt808LocationHistoryController(reader);

        Jt808LocationHistoryController.LocationPageResponse response = controller.locations(
                "g7gps",
                "2026-06-29T13:00:00+08:00",
                "2026-06-29T13:10:00+08:00",
                TdengineQueryOrder.DESC,
                50,
                null,
                null);

        assertThat(response.items().getFirst().rawUri())
                .isEqualTo("archive://jt808/core-frame.bin");
    }

    @Test
    void rejectsBlankPhone() {
        Jt808LocationHistoryController controller = new Jt808LocationHistoryController(
                new CapturingReader(new TdenginePage<>(List.of(), Optional.empty())));

        assertThatThrownBy(() -> controller.locations(
                " ",
                "2026-06-29T13:00:00+08:00",
                "2026-06-29T13:10:00+08:00",
                TdengineQueryOrder.DESC,
                50,
                null,
                null))
                .isInstanceOfSatisfying(ResponseStatusException.class, ex ->
                        assertThat(ex.getStatusCode()).isEqualTo(HttpStatus.BAD_REQUEST));
    }

    private static TdengineLocationRow row(String factId, String ts) {
        return row(factId, ts, "archive://jt808/frame-1.bin");
    }

    private static TdengineLocationRow row(String factId, String ts, String rawUri) {
        Instant instant = Instant.parse(ts);
        return new TdengineLocationRow(
                instant,
                factId,
                "frame-1",
                instant.plusMillis(500),
                113.12,
                23.45,
                8.0,
                42.5,
                90.0,
                1L,
                3L,
                null,
                rawUri,
                "JT808",
                "jt808:g7gps",
                "",
                "g7gps");
    }

    private static final class CapturingReader implements TdengineHistoryReader {
        private final TdenginePage<TdengineLocationRow> response;
        private TdengineLocationQuery query;

        private CapturingReader(TdenginePage<TdengineLocationRow> response) {
            this.response = response;
        }

        @Override
        public TdenginePage<com.lingniu.ingest.tdenginehistory.TdengineRawFrameRow> queryRawFrames(
                com.lingniu.ingest.tdenginehistory.TdengineRawFrameQuery query) {
            throw new UnsupportedOperationException();
        }

        @Override
        public TdenginePage<TdengineLocationRow> queryLocations(TdengineLocationQuery query) throws IOException {
            this.query = query;
            return response;
        }

    }
}
