package database;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import com.google.common.base.Strings;

import objects.ResultsDTO;

public class Ekipage extends Database {

    private static Ekipage instance = new Ekipage();

    private Ekipage() {
    }

    public static Ekipage getInstance() {
        return instance;
    }

    public ResultsDTO avarageTime(int driverId, int horseId, String date) {
        return avarageTimeByDistance(driverId, horseId, 0, 0, date);
    }

    public ResultsDTO avarageTimeByDistance(int driverId, int horseId, int distance, String date) {
        return avarageTimeByDistance(driverId, horseId, distance, 0, date);
    }

    public ResultsDTO avarageTimeWithLimit(int driverId, int horseId, int raceLimit, String date) {
        return avarageTimeByDistance(driverId, horseId, 0, raceLimit, date);
    }

    public ResultsDTO avarageTimeByDistance(int driverId, int horseId, int distance, int raceLimit, String date) {
        final ResultsDTO returnValue = new ResultsDTO();
        final String d = Strings.isNullOrEmpty(date) ? "NOW()" : date;
        final String sql = "SELECT ROUND(AVG(avgRes.Time), 2) as avgTime, count(*) as num FROM (SELECT Time FROM Results "
                + "WHERE Time > 0 AND Lane > 0 AND RaceDate < ? AND DriverId = ? AND horseId = ?";
        final String distanceSql = " AND distance BETWEEN ? AND ?";
        final String limitSql = " LIMIT ?";
        final String endingSql = ") avgRes";

        final StringBuilder sb = new StringBuilder();
        sb.append(sql);

        if (distance > 0) {
            sb.append(distanceSql);
        }
        if (raceLimit > 0) {
            sb.append(limitSql);
        }

        sb.append(endingSql);

        try {
            final PreparedStatement stat = getConnection().prepareStatement(sb.toString());
            stat.setString(1, d);
            stat.setInt(2, driverId);
            stat.setInt(3, horseId);
            if (distance > 0) {
                stat.setInt(4, distance - 50);
                stat.setInt(5, distance + 50);
            }
            if (distance > 0 && raceLimit > 0) {
                stat.setInt(6, raceLimit);
            } else if (distance <= 0 && raceLimit > 0) {
                stat.setInt(4, raceLimit);
            }

            final ResultSet rs = stat.executeQuery();

            while (rs.next()) {
                returnValue.setRes(rs.getFloat("avgTime"));
                returnValue.setCount(rs.getInt("num"));
            }
        } catch (final SQLException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }

        return returnValue;
    }

    public ResultsDTO avaragePlacement(int driverId, int horseId, String date) {
        return avaragePlacementByDistance(driverId, horseId, 0, 0, date);
    }

    public ResultsDTO avaragePlacementByDistance(int driverId, int horseId, int distance, String date) {
        return avaragePlacementByDistance(driverId, horseId, distance, 0, date);
    }

    public ResultsDTO avaragePlacementWithLimit(int driverId, int horseId, int raceLimit, String date) {
        return avaragePlacementByDistance(driverId, horseId, 0, raceLimit, date);
    }

    public ResultsDTO avaragePlacementByDistance(int driverId, int horseId, int distance, int raceLimit, String date) {
        final ResultsDTO returnValue = new ResultsDTO();

        final String d = Strings.isNullOrEmpty(date) ? "NOW()" : date;
        final StringBuilder sb = new StringBuilder();
        final String sql = "SELECT ROUND(avg(" + "CASE " + "WHEN Result = -1 THEN 9 WHEN Result = -2 THEN 10"
                + " WHEN Result = 0 THEN 8" + " ELSE Result " + "END"
                + " ), 2) as avgResult, count(*) as num FROM (SELECT Result FROM Results WHERE RaceDate < ? AND DriverId = ? AND horseId = ?";
        final String distSql = " AND distance BETWEEN ? AND ?";
        final String limitSql = " limit ?";

        sb.append(sql);
        if (distance > 0) {
            sb.append(distSql);
        }
        if (raceLimit > 0) {
            sb.append(limitSql);
        }

        sb.append(") as t");

        try {
            final PreparedStatement stat = getConnection().prepareStatement(sb.toString());
            stat.setString(1, d);
            stat.setInt(2, driverId);
            stat.setInt(3, horseId);
            if (distance > 0) {
                stat.setInt(4, distance - 50);
                stat.setInt(5, distance + 50);
            }
            if (distance > 0 && raceLimit > 0) {
                stat.setInt(6, raceLimit);
            } else if (distance <= 0 && raceLimit > 0) {
                stat.setInt(4, raceLimit);
            }

            final ResultSet rs = stat.executeQuery();

            while (rs.next()) {
                returnValue.setRes(rs.getFloat("avgResult"));
                returnValue.setCount(rs.getInt("num"));
            }
        } catch (final SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        return returnValue;
    }
}
