package tourplaner.data;

import javafx.geometry.Pos;
import tourplaner.object.Log;
import tourplaner.object.Tour;

import java.sql.Connection;
import java.sql.Date;
import java.sql.ResultSet;
import java.sql.Statement;
import java.time.LocalDate;
import java.util.ArrayList;

/**
 * Verwaltet die Datenbankverbindung zu dem Postgres Server
 */
public class DbConnect {
    private Connection c;
    private Statement stmt;


    /**
     * Erstellt alle Beispieldaten und simuliert somit den
     * Verbindungsaufbau zu einer DB
     */
    public DbConnect() {
        this.c = null;
    }


    /**
     * Erstellt alle Tabellen die für den Betrieb der Software bennötigt werden
     * @return True bei erfolg, sonst error
     */
    public boolean init() {
        ArrayList<Boolean> errors = new ArrayList<>();
        errors.add(PostgresHelper.executeUpdateMessage("create table tour ( tourname varchar not null, dauer decimal, mapjson varchar, start varchar, ziel varchar, strecke decimal);", "Tour Table created"));
        errors.add(PostgresHelper.executeUpdateMessage("create unique index tour_tourname_uindex on tour (tourname);", "Tour Table unique created"));
        errors.add(PostgresHelper.executeUpdateMessage("alter table tour add constraint tour_pk primary key (tourname);", "Tour Table primary created"));
        errors.add(PostgresHelper.executeUpdateMessage("create table log(tourname varchar constraint log_tour_tourname_fk references tour,id varchar,bemerkung varchar,datum date,strecke decimal,avg decimal,hightmeter decimal,pause decimal,gegangen decimal,dauer decimal);", "Log Table created"));
        return !errors.contains(false);
    }


    /**
     * Bearbeitet eine Tour
     * @param oldname Alter Tour name
     * @param tour Neues Tour Object
     * @return false bei error
     */
    public boolean editTour(String oldname, Tour tour) {
        String tourname = tour.getName();
        ArrayList<Boolean> result = new ArrayList<>();
        ArrayList<Log> logs = getLogs(oldname);
        result.add(delLogs(oldname));
        result.add(PostgresHelper.executeUpdate("UPDATE public.tour SET tourname = '"+tour.getName()+"', dauer = 1, mapjson = '"+tour.getMapJson()+"', start = '"+tour.getStart()+"', ziel = '"+tour.getZiel()+"', strecke = "+tour.getStrecke()+" WHERE tourname ='" + oldname + "';"));
        logs.forEach(log -> {
            result.add(addLog(tourname, log));
        });
        return !result.contains(false);
    }

    private boolean delLogs(String tourname){
        return PostgresHelper.executeUpdate("DELETE FROM public.log WHERE tourname = '"+tourname+"'");
    }
    /**
     * Fügt eine Tour hinzu
     * @param tour Neue Tour
     * @return false bei error
     */
    public boolean addTour(Tour tour){
        return PostgresHelper.executeUpdate("INSERT INTO public.tour (tourname, dauer, mapjson, start, ziel, strecke) VALUES ('"+tour.getName()+"', "+tour.getDauer()+", '"+tour.getMapJson()+"', '"+tour.getStart()+"', '"+tour.getZiel()+"', "+tour.getStrecke()+")");
    }

    /**
     * Löscht eine Tour anhand des Tournamens
     * @param tourname Tourname der zu löschen ist
     * @return false bei error
     */
    public boolean delTour(String tourname){
        ArrayList<Boolean> result = new ArrayList<>();
        result.add(delLogs(tourname));
        result.add(PostgresHelper.executeUpdate("DELETE FROM public.tour WHERE tourname = '"+tourname+"'"));
        return !result.contains(false);
    }

    public ArrayList<Log> getLogs(String tourname){

        this.c = PostgresHelper.con();
        String id, bemerkung ;
        double dauer, strecke, pause, gegangen, avg, hightmeter;
        Date datum;

        ArrayList<Log> logs = new ArrayList<>();
        try {
            stmt = this.c.createStatement();
            ResultSet rs = stmt.executeQuery("SELECT * FROM public.log where tourname = '"+ tourname +"'");
            while (rs.next()) {
                id = rs.getString("id");
                bemerkung = rs.getString("bemerkung");
                datum = rs.getDate("datum");
                dauer = rs.getDouble("dauer");
//                avg = rs.getDouble("avg");
                hightmeter = rs.getDouble("hightmeter");
                pause = rs.getDouble("pause");
//                gegangen = rs.getDouble("gegangen");
                strecke = rs.getDouble("strecke");
                if (!tourname.isEmpty()) {
                    logs.add(new Log(id, dauer, datum.toLocalDate(), strecke, bemerkung,hightmeter, pause));
                }else {
                    return null;
                }
            }
            rs.close();
            stmt.close();
            this.c.close();
            return logs;
        } catch (Exception e) {
            System.err.println(e.getClass().getName() + ": " + e.getMessage());
            return null;
        }
    }


    /**
     * Füght einen Logeintrag ein
     * @param tourname Zu welcher Tour der Logeintrag gehört
     * @param log Der Logeintrag
     * @return false bei error
     */
    public boolean addLog(String tourname, Log log){
        if(Double.isInfinite(log.getAvgspeed())) log.setAvgspeed(-1.0);
        return PostgresHelper.executeUpdate("INSERT INTO public.log (tourname, id, bemerkung, datum, strecke, avg, hightmeter, pause, gegangen, dauer) VALUES ('"+tourname+"', '"+log.getId()+"', '"+log.getBemerkung()+"', '"+log.getDatum()+"', "
                +log.getStrecke()+", "+log.getAvgspeed()+", "+log.getHightmeter()+", "+log.getPause()+", "+log.getGegangen()+", "+log.getDauer()+")");
    }

    public boolean editLog(String tourname, Log log){
        return PostgresHelper.executeUpdate("UPDATE public.log SET bemerkung = '"+log.getBemerkung()+"', datum = '"+log.getDatum()+"', strecke = "+log.getStrecke()+", avg = "+log.getAvgspeed()+", hightmeter = "+
                log.getHightmeter()+", pause = "+log.getPause()+", gegangen = "+log.getGegangen()+", dauer = "+log.getDauer()+" WHERE tourname = '"+tourname+"' and id = '"+log.getId()+"'");
    }

    public boolean delLog(String tourname, String id){
        System.out.println("DELETE FROM public.log WHERE tourname = '"+tourname+"' and id = '"+id+"'");
        return PostgresHelper.executeUpdate("DELETE FROM public.log WHERE tourname = '"+tourname+"' and id = '"+id+"'");
    }

    /**
     * Holt alle Touren aus der Datenbank
     * @return Null bei fehler, sonst eine List aus den IDs
     */
    public ArrayList<Tour> getAllTouren(){
        this.c = PostgresHelper.con();
        String tourname, mapjson, start, ziel;
        double dauer, strecke;

        ArrayList<Tour> touren = new ArrayList<>();
        try {
            stmt = this.c.createStatement();
            ResultSet rs = stmt.executeQuery("select * from tour;");
            while (rs.next()) {
                tourname = rs.getString("tourname");
                mapjson = rs.getString("mapjson");
                start = rs.getString("start");
                ziel = rs.getString("ziel");
                dauer = rs.getDouble("dauer");
                strecke = rs.getDouble("strecke");
                if (!tourname.isEmpty()) {
                    touren.add(new Tour(tourname, dauer + "", mapjson, strecke, start, ziel));
                }else {
                    return null;
                }
            }
            rs.close();
            stmt.close();
            this.c.close();
            return touren;
        } catch (Exception e) {
            System.err.println(e.getClass().getName() + ": " + e.getMessage());
            return null;
        }
    }

}
