#include "separate_rides.h"

namespace maps::mrc::tracks_with_sensors {

struct RideInterval {
    chrono::TimePoint begin;
    chrono::TimePoint end;
};

chrono::TimePoint toTimePoint(pos_improvment::Time time) {
    return std::chrono::time_point_cast<chrono::TimePoint::duration>(time);
}

Tracks splitIntoSeparateRides(const db::TrackPoints& trackPoints,
                              const SensorEvents& sensorEvents)
{
    const auto& gyroEvents = sensorEvents.gyroEvents;
    const auto& accEvents = sensorEvents.accEvents;

    std::vector<RideInterval> rides(1);
    rides[0].begin = toTimePoint(gyroEvents[0].time);
    rides[0].end = toTimePoint(gyroEvents[0].time);
    for (auto& gyroEvent : gyroEvents) {
        if (toTimePoint(gyroEvent.time) - rides.back().end
            > std::chrono::milliseconds(1000))
        {
            rides.push_back({toTimePoint(gyroEvent.time),
                             toTimePoint(gyroEvent.time)});
        } else {
            rides.back().end = toTimePoint(gyroEvent.time);
        }
    }

    size_t gyroEventsIndex = 0;
    size_t accEventsIndex = 0;
    size_t trackPointsIndex = 0;

    Tracks tracks;

    for (auto ride : rides) {
        pos_improvment::GyroscopeEvents curGyroEvents;
        pos_improvment::AccelerometerEvents curAccEvents;
        db::TrackPoints curTrackPoints;

        for (; gyroEventsIndex < gyroEvents.size(); gyroEventsIndex++) {
            const auto& event = gyroEvents[gyroEventsIndex];
            if (toTimePoint(event.time) > ride.end) {
                break;
            }
            if (toTimePoint(event.time) >= ride.begin) {
                curGyroEvents.push_back(event);
            }
        }

        for (; accEventsIndex < accEvents.size(); accEventsIndex++) {
            const auto& event = accEvents[accEventsIndex];
            if (toTimePoint(event.time) > ride.end) {
                break;
            }
            if (toTimePoint(event.time) >= ride.begin) {
                curAccEvents.push_back(event);
            }
        }

        for (; trackPointsIndex < trackPoints.size(); trackPointsIndex++) {
            const auto trackPoint = trackPoints[trackPointsIndex];
            if (trackPoint.timestamp() > ride.end) {
                break;
            }
            if (trackPoint.timestamp() >= ride.begin) {
                curTrackPoints.push_back(trackPoint);
            }
        }
        tracks.push_back(
            {curTrackPoints, SensorEvents{curGyroEvents, curAccEvents}});
    }

    return tracks;
}

} // namespace maps::mrc::tracks_with_sensors
