package fi.lpam.dataluokat;

import fi.lpam.gui.virheDialogit.SiirtoVirhe;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;

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

public class Kierros implements TietokantaOlio {
    private int id = -1;
    private int kierrosNumero;
    private ObservableList<Asiakas> asiakkaat;

    public Kierros(int kierrosNumero, ObservableList<Asiakas> asiakkaat) {
        this.kierrosNumero = kierrosNumero;
        this.asiakkaat = asiakkaat;
    }

    private Kierros(int id, int kierrosNumero, ObservableList<Asiakas> asiakkaat) {
        this.id = id;
        this.kierrosNumero = kierrosNumero;
        this.asiakkaat = asiakkaat;
    }

    /** Hakee kaikki kierrokset tietokannasta
     * @return kaikki kierrokset
     */
    public static ArrayList<Kierros> haeKaikki() {
        ArrayList<Kierros> kierrokset = new ArrayList<>();
        try (Connection tietokanta = Tietokanta.haeYhteys()) {
            Statement stmt = tietokanta.createStatement();
            ResultSet rs = stmt.executeQuery("select id, kierrosNumero, asiakkaat from kierrokset");
            while (rs.next()) {
                kierrokset.add(new Kierros(rs.getInt(1), rs.getInt(2), FXCollections.observableArrayList(muutaMerkkijonoAsiakkaiksi(rs.getString(3)))));
            }
        }
        catch (SQLException e) {
            SiirtoVirhe alert = new SiirtoVirhe(e);
            alert.showAndWait();
        }
        return kierrokset;
    }

    /**
     * Hakee tietyn kierroksen
     * @param kierrosNumero haettavan kierroksen numero
     * @return Kierros, null jos ei löydy
     */
    public static Kierros haeKierros(int kierrosNumero) {
        Kierros kierros;
        try (Connection tietokanta = Tietokanta.haeYhteys()) {
            PreparedStatement stmt = tietokanta.prepareStatement("select id, kierrosNumero, asiakkaat from kierrokset where kierrosNumero = ?");
            stmt.setInt(1, kierrosNumero);
            ResultSet rs = stmt.executeQuery();
            kierros = new Kierros(rs.getInt(1), rs.getInt(2), FXCollections.observableArrayList(muutaMerkkijonoAsiakkaiksi(rs.getString(3))));
            return kierros;
        }
        catch (SQLException e) {
            SiirtoVirhe alert = new SiirtoVirhe(e);
            alert.showAndWait();
        }
        return null;
    }

    /**
     * Haetaan uniikit kierrosnumerot
     * @return kierrosten uniikit kierrosnumerot
     */
    public static ArrayList<Integer> haeKierrosNumerot() {
        ArrayList<Integer> numerot = new ArrayList<>();
        try (Connection tietotokanta = Tietokanta.haeYhteys()) {
            Statement stmt = tietotokanta.createStatement();
            ResultSet rs = stmt.executeQuery("select distinct kierrosNumero from kierrokset ORDER BY kierrosNumero");
            while (rs.next()) {
                numerot.add(rs.getInt("kierrosNumero"));
            }
            return numerot;
        }
        catch (SQLException e) {
            SiirtoVirhe alert = new SiirtoVirhe(e);
            alert.showAndWait();
            return numerot;
        }
    }


    @Override
    public boolean tallennaUusi() {
        try (Connection tietokanta = Tietokanta.haeYhteys()) {
            PreparedStatement stmt = tietokanta.prepareStatement("insert into kierrokset (kierrosNumero, asiakkaat) values (?, ?)", Statement.RETURN_GENERATED_KEYS);
            stmt.setInt(1, kierrosNumero);
            stmt.setString(2, muutaAsiakkaatMerkkijonoksi());
            int muokatutRivit = stmt.executeUpdate();

            if (muokatutRivit == 0) {
                throw new SQLException("Kierroksen luominen epäonnistui, rivejä ei muokattu");
            }

            ResultSet luodutIDt = stmt.getGeneratedKeys();
            if (luodutIDt.next()) {
                this.id = luodutIDt.getInt(1);
            } else {
                throw new SQLException("Kierroksen luominen epäonnistui, idtä ei saatu");
            }
        }

        catch (SQLException e) {
            SiirtoVirhe alert = new SiirtoVirhe(e);
            alert.showAndWait();
            return false;
        }
        return true;
    }

    @Override
    public boolean päivitäTietokantaan() {
        try (Connection tietokanta = Tietokanta.haeYhteys()) {
            PreparedStatement stmt = tietokanta.prepareStatement("update kierrokset set asiakkaat = ?, kierrosnumero = ? where id = ?");
            stmt.setString(1, muutaAsiakkaatMerkkijonoksi());
            stmt.setInt(2, kierrosNumero);
            stmt.setInt(3, id);
            int muokatutRivit = stmt.executeUpdate();
            if (muokatutRivit == 0) {
                throw new SQLException("Kierroksen muokkaaminen epäonnistui, rivejä ei muokattu");
            }
        }
        catch (SQLException e) {
            SiirtoVirhe alert = new SiirtoVirhe(e);
            alert.showAndWait();
            return false;
        }
        return true;
    }

    @Override
    public boolean poista() {
        if (this.id < 0) return false;
        try (Connection tietokanta = Tietokanta.haeYhteys()) {
            PreparedStatement stmt = tietokanta.prepareStatement("delete from kierrokset where id = ?");
            stmt.setInt(1, id);
            int muokatutRivit = stmt.executeUpdate();
            if (muokatutRivit == 0) {
                throw new SQLException("Kierroksen poisto epäonnistui, rivejä ei muokattu");
            }
        }
        catch (SQLException e) {
            SiirtoVirhe alert = new SiirtoVirhe(e);
            alert.showAndWait();
            return false;
        }
        return true;
    }

    @Override
    public boolean tallenna() {
        if (this.id < 0) {
            return this.tallennaUusi();
        }
        else {
            return this.päivitäTietokantaan();
        }
    }

    /**
     * Muuttaa listan asiakkaista merkkijonoksi
     * @return listan asiakkaat muodossa "id id id..."
     */
    private String muutaAsiakkaatMerkkijonoksi() {
        StringBuilder sb = new StringBuilder();
        if (asiakkaat.isEmpty()) {return sb.toString();}

        Iterator<Asiakas> it = asiakkaat.iterator();
        sb.append(it.next().getId());
        while (it.hasNext()) {
            sb.append(" ").append(it.next().getId());
        }
        return sb.toString();
    }

    private static ArrayList<Asiakas> muutaMerkkijonoAsiakkaiksi(String merkkijono) {
        String[] strAsiakasIDt = merkkijono.split(" ");
        int[] asiakasIDt = new int[strAsiakasIDt.length];
        for (int i = 0; i < strAsiakasIDt.length; i++) {
            asiakasIDt[i] = Integer.parseInt(strAsiakasIDt[i]);
        }
        return Asiakas.haeTietyt(asiakasIDt);
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public int getKierrosNumero() {
        return kierrosNumero;
    }

    public void setKierrosNumero(int kierrosNumero) {
        this.kierrosNumero = kierrosNumero;
    }

    public ObservableList<Asiakas> getAsiakkaat() {
        return asiakkaat;
    }

    public void setAsiakkaat(ObservableList<Asiakas> asiakkaat) {
        this.asiakkaat = asiakkaat;
    }

    public String toString() {
        return this.kierrosNumero + ": " + this.asiakkaat;
    }
}
