package vassistent.service;

import vassistent.model.DatabaseEntry;
import vassistent.model.RatioPoint;
import vassistent.util.Logger;

import java.sql.*;
import java.util.ArrayList;
import java.util.List;

/**
 * Computes ratios and time-series aggregates from persisted binary events.
 */
public class StatisticsService {
    private final DataPersistenceService persistenceService;

    /**
     * Creates a statistics service for persisted event data.
     *
     * @param persistenceService persistence service to query raw events
     */
    public StatisticsService(DataPersistenceService persistenceService) {
        this.persistenceService = persistenceService;
    }

    /**
     * Computes the average of the newest {@code lastN} binary values.
     *
     * @param lastN number of newest entries to include
     * @return ratio in range {@code [0, 1]} or {@code 0.0} when unavailable
     */
    public double getRatio(int lastN) {
        if (lastN <= 0) {
            return 0.0;
        }

        String query = """
                       SELECT AVG(value)
                       FROM (
                            SELECT value
                            FROM binary_event
                            ORDER BY id DESC
                            LIMIT ?
                       )
                       """;

        try (Connection c = DriverManager.getConnection(persistenceService.getDbUrl()); PreparedStatement ps = c.prepareStatement(query)) {
            ps.setInt(1, lastN);

            ResultSet rs = ps.executeQuery();
            if (rs.next()) {
                return rs.getDouble(1);
            }
        } catch (SQLException e) {
            Logger.error("Evaluation", "Couldn't get ratio.", e);
        }

        return 0.0;
    }

    /**
     * Computes rolling averages for chart rendering.
     *
     * The rolling window includes the current entry and up to {@code windowSize - 1}
     * previous entries.
     *
     * @param windowSize number of entries considered per rolling average window
     * @return chronological list of ratio points
     */
    public List<RatioPoint> getLastNAverages(int windowSize) {

        if (windowSize <= 0) {
            return List.of();
        }

        List<DatabaseEntry> entries = persistenceService.getLastEntries(windowSize + 1);

        List<RatioPoint> result = new ArrayList<>();

        if (entries.isEmpty()) {
            return result;
        }

        double rollingSum = 0.0;
        int windowStart = 0;

        for (int i = 0; i < entries.size(); i++) {
            rollingSum += entries.get(i).getValue();

            if (i - windowStart + 1 > windowSize) {
                rollingSum -= entries.get(windowStart).getValue();
                windowStart++;
            }

            int windowCount = i - windowStart + 1;
            double avg = rollingSum / windowCount;


            result.add(new RatioPoint(
                    entries.get(i).getTimestamp(),
                    avg
            ));
        }

        Logger.info("STATISTICS",
                "Computed averages: " + result.size());

        return result;
    }
}
