package fi.lpam.dataluokat;

import fi.lpam.gui.virheDialogit.SiirtoVirhe;

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

@SuppressWarnings("DuplicatedCode")
public class Asiakas implements TietokantaOlio {
    private int id = -1;
    private String nimi;
    private String osoite;
    private int maanantaiKpl, tiistaiKpl, keskiviikkoKpl, torstaiKpl, perjantaiKpl;
    private int salaatit, pääruoat, jälkiruoat;
    private String erityisruokavalio;
    private String avainTieto;
    private String lisätiedot;

    /**
     * Tyhjä konstruktori uusien luomista varten
     */
    public Asiakas() {
    }

    /**
     * Vain MultiColumnListViewin käyttöön
     * @param nimi Asiakkaan nimi
     */
    public Asiakas(String nimi) {
        this.nimi = nimi;
    }

    /**
     * Kun luetaan asiakas tietokannasta
     * @param id asiakkaan id
     * @param nimi asiakkaan nimi
     * @param osoite osoite
     * @param maanantaiKpl kuljetettava määrä
     * @param tiistaiKpl kuljetettava määrä
     * @param keskiviikkoKpl kuljetettava määrä
     * @param torstaiKpl kuljetettava määrä
     * @param perjantaiKpl kuljetettava määrä
     * @param salaatit kuljetettava määrä
     * @param pääruoat kuljetettava määrä
     * @param jälkiruoat kuljetettava määrä
     * @param erityisruokavalio ...
     * @param avainTieto ...
     * @param lisätiedot mahdolliset lisätilaukset/tiedot
     */
    private Asiakas(int id, String nimi, String osoite, int maanantaiKpl, int tiistaiKpl, int keskiviikkoKpl, int torstaiKpl, int perjantaiKpl, int salaatit, int pääruoat, int jälkiruoat, String erityisruokavalio, String avainTieto, String lisätiedot) {
        this.id = id;
        this.nimi = nimi;
        this.osoite = osoite;
        this.maanantaiKpl = maanantaiKpl;
        this.tiistaiKpl = tiistaiKpl;
        this.keskiviikkoKpl = keskiviikkoKpl;
        this.torstaiKpl = torstaiKpl;
        this.perjantaiKpl = perjantaiKpl;
        this.salaatit = salaatit;
        this.pääruoat = pääruoat;
        this.jälkiruoat = jälkiruoat;
        this.erityisruokavalio = erityisruokavalio;
        this.avainTieto = avainTieto;
        this.lisätiedot = lisätiedot;
    }

    /**
     * @param nimi asiakkaan nimi
     * @param osoite osoite
     * @param maanantaiKpl kuljetettava määrä
     * @param tiistaiKpl kuljetettava määrä
     * @param keskiviikkoKpl kuljetettava määrä
     * @param torstaiKpl kuljetettava määrä
     * @param perjantaiKpl kuljetettava määrä
     * @param salaatit kuljetettava määrä
     * @param pääruoat kuljetettava määrä
     * @param jälkiruoat kuljetettava määrä
     * @param erityisruokavalio ...
     * @param avainTieto ...
     * @param lisätiedot mahdolliset lisätilaukset/tiedot
     */
    public Asiakas(String nimi, String osoite, int maanantaiKpl, int tiistaiKpl, int keskiviikkoKpl, int torstaiKpl, int perjantaiKpl, int salaatit, int pääruoat, int jälkiruoat, String erityisruokavalio, String avainTieto, String lisätiedot) {
        this.nimi = nimi;
        this.osoite = osoite;
        this.maanantaiKpl = maanantaiKpl;
        this.tiistaiKpl = tiistaiKpl;
        this.keskiviikkoKpl = keskiviikkoKpl;
        this.torstaiKpl = torstaiKpl;
        this.perjantaiKpl = perjantaiKpl;
        this.salaatit = salaatit;
        this.pääruoat = pääruoat;
        this.jälkiruoat = jälkiruoat;
        this.erityisruokavalio = erityisruokavalio;
        this.avainTieto = avainTieto;
        this.lisätiedot = lisätiedot;
    }

    /**
     * Hakee kaikki asiakkaat tietokannan asiakkaat taulusta
     * @return ArrayList<Asiakas>
     */
    public static ArrayList<Asiakas> haeKaikki() {
        try (Connection tietokanta = Tietokanta.haeYhteys()) {
            Statement stmt = tietokanta.createStatement();
            ResultSet rs = stmt.executeQuery("select * from asiakkaat");
            return parsiResultSet(rs);
        } catch (SQLException e) {
            SiirtoVirhe alert = new SiirtoVirhe(e);
            alert.showAndWait();
            return null;
        }
    }

    /**
     * Hakee tietokannasta asiakasidn perusteella asiakkaat
     * @param IDt haettavat asiakkkaat
     * @return Haetut asiakkaat tai null
     */
    public static ArrayList<Asiakas> haeTietyt(int[] IDt) {
        StringBuilder sbIDt = new StringBuilder();
        sbIDt.append(IDt[0]);
        for (int i = 1; i < IDt.length; i++) {
            sbIDt.append(", ").append(IDt[i]);
        }
        try (Connection tietokanta = Tietokanta.haeYhteys()) {
            String sql = "select * from asiakkaat where id in (" + sbIDt + ") order by instr('" + sbIDt + "', id)";
            Statement stmt = tietokanta.createStatement();
            ResultSet rs = stmt.executeQuery(sql);
            return parsiResultSet(rs);
        }
        catch (SQLException e) {
            SiirtoVirhe alert = new SiirtoVirhe(e);
            alert.showAndWait();
            return null;
        }
    }

    /**
     * Käsittelee ResultSettiä
     * @param rs saatu ResultSet
     * @return ArrayList<Asiakas>
     */
    private static ArrayList<Asiakas> parsiResultSet(ResultSet rs) {
        ArrayList<Asiakas> asiakkaat = new ArrayList<>();

        try {
            while (rs.next()) {
                Asiakas uusi = new Asiakas(
                        rs.getInt("id"),
                        rs.getString("nimi"),
                        rs.getString("osoite"),
                        rs.getInt("maanantaiKpl"),
                        rs.getInt("tiistaiKpl"),
                        rs.getInt("keskiviikkoKpl"),
                        rs.getInt("torstaiKpl"),
                        rs.getInt("perjantaiKpl"),
                        rs.getInt("salaatit"),
                        rs.getInt("pääruoat"),
                        rs.getInt("jälkiruoat"),
                        rs.getString("erityisruokavalio"),
                        rs.getString("avainTieto"),
                        rs.getString("lisätiedot")
                );
                asiakkaat.add(uusi);
            }
        }
        catch (SQLException e) {
            SiirtoVirhe alert = new SiirtoVirhe(e);
            alert.showAndWait();
        }
        return asiakkaat;
    }

    /**
     * Tallentaa uuden asiakkaan tietokantaan. Tietokanta luo automaattisesti id:n asiakkaalle.
     *
     */
    @Override
    public boolean tallennaUusi() {
        try (Connection tietokanta = Tietokanta.haeYhteys()) {
            PreparedStatement stmt = tietokanta.prepareStatement("INSERT INTO asiakkaat (nimi, osoite, maanantaiKpl, tiistaiKpl, keskiviikkoKpl, torstaiKpl, perjantaiKpl, salaatit, pääruoat, jälkiruoat, erityisruokavalio, avainTieto, lisätiedot) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", Statement.RETURN_GENERATED_KEYS);
            stmt.setString(1, nimi);
            stmt.setString(2, osoite);
            stmt.setInt(3, maanantaiKpl);
            stmt.setInt(4, tiistaiKpl);
            stmt.setInt(5, keskiviikkoKpl);
            stmt.setInt(6, torstaiKpl);
            stmt.setInt(7, perjantaiKpl);
            stmt.setInt(8, salaatit);
            stmt.setInt(9, pääruoat);
            stmt.setInt(10, jälkiruoat);
            stmt.setString(11, erityisruokavalio);
            stmt.setString(12, avainTieto);
            stmt.setString(13, lisätiedot);
            int muokatutRivit = stmt.executeUpdate();

            if (muokatutRivit == 0) {
                throw new SQLException("Käyttäjän luominen epäonnistui, rivejä ei muokattu");
            }
            try (ResultSet generatedKeys = stmt.getGeneratedKeys()) {
                if (generatedKeys.next()) {
                    this.setId(generatedKeys.getInt(1));
                }
                else {
                    throw new SQLException("Käyttäjän luominen epäonnistui, id:tä ei saatu");
                }
            }
        } catch (SQLException e) {
            SiirtoVirhe alert = new SiirtoVirhe(e);
            alert.showAndWait();
            return false;
        }
        return true;
    }

    /**
     * Päivittää kutsuvan asiakkaan tiedot tietokantaan
     */
    @Override
    public boolean päivitäTietokantaan() {
        try (Connection tietokanta = Tietokanta.haeYhteys()) {
            PreparedStatement stmt = tietokanta.prepareStatement("UPDATE asiakkaat set nimi = ?, osoite = ?, maanantaiKpl = ?, tiistaiKpl = ?, keskiviikkoKpl = ?, torstaiKpl = ?, perjantaiKpl = ?, salaatit = ?, pääruoat = ?, jälkiruoat = ?, erityisruokavalio = ?, avainTieto = ?, lisätiedot = ? WHERE id = ?");
            stmt.setString(1, nimi);
            stmt.setString(2, osoite);
            stmt.setInt(3, maanantaiKpl);
            stmt.setInt(4, tiistaiKpl);
            stmt.setInt(5, keskiviikkoKpl);
            stmt.setInt(6, torstaiKpl);
            stmt.setInt(7, perjantaiKpl);
            stmt.setInt(8, salaatit);
            stmt.setInt(9, pääruoat);
            stmt.setInt(10, jälkiruoat);
            stmt.setString(11, erityisruokavalio);
            stmt.setString(12, avainTieto);
            stmt.setString(13, lisätiedot);
            stmt.setInt(14, id);
            stmt.executeUpdate();
            return true;
        } catch (SQLException e) {
            SiirtoVirhe alert = new SiirtoVirhe(e);
            alert.showAndWait();
            return false;
        }
    }

    /**
     * Poistaa asiakkaan tietokannasta
     */
    @Override
    public boolean poista() {
        try (Connection tietokanta = Tietokanta.haeYhteys()) {
            String sql = "DELETE FROM asiakkaat WHERE id = " + id;
            Statement stmt = tietokanta.createStatement();
            stmt.executeUpdate(sql);
            return true;
        } catch (SQLException e) {
            SiirtoVirhe alert = new SiirtoVirhe(e);
            alert.showAndWait();
            return false;
        }
    }

    public boolean tallenna() {
        if (this.id == -1) {
            return this.tallennaUusi();
        }
        else {
            return this.päivitäTietokantaan();
        }
    }

    /**
     * Kierroshallintaa varten toString
     * @return asiakkaan nimi
     */
    public String toString() {
        return this.getNimi();
    }

    public int getId() {
        return id;
    }

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

    public String getNimi() {
        return nimi;
    }

    public void setNimi(String nimi) {
        this.nimi = nimi;
    }

    public String getOsoite() {
        return osoite;
    }

    public void setOsoite(String osoite) {
        this.osoite = osoite;
    }

    public int getMaanantaiKpl() {
        return maanantaiKpl;
    }

    public void setMaanantaiKpl(int maanantaiKpl) {
        this.maanantaiKpl = maanantaiKpl;
    }

    public int getTiistaiKpl() {
        return tiistaiKpl;
    }

    public void setTiistaiKpl(int tiistaiKpl) {
        this.tiistaiKpl = tiistaiKpl;
    }

    public int getKeskiviikkoKpl() {
        return keskiviikkoKpl;
    }

    public void setKeskiviikkoKpl(int keskiviikkoKpl) {
        this.keskiviikkoKpl = keskiviikkoKpl;
    }

    public int getTorstaiKpl() {
        return torstaiKpl;
    }

    public void setTorstaiKpl(int torstaiKpl) {
        this.torstaiKpl = torstaiKpl;
    }

    public int getPerjantaiKpl() {
        return perjantaiKpl;
    }

    public void setPerjantaiKpl(int perjantaiKpl) {
        this.perjantaiKpl = perjantaiKpl;
    }

    public int getSalaatit() {
        return salaatit;
    }

    public void setSalaatit(int salaatit) {
        this.salaatit = salaatit;
    }

    public int getPääruoat() {
        return pääruoat;
    }

    public void setPääruoat(int pääruoat) {
        this.pääruoat = pääruoat;
    }

    public int getJälkiruoat() {
        return jälkiruoat;
    }

    public void setJälkiruoat(int jälkiruoat) {
        this.jälkiruoat = jälkiruoat;
    }

    public String getErityisruokavalio() {
        return erityisruokavalio;
    }

    public void setErityisruokavalio(String erityisruokavalio) {
        this.erityisruokavalio = erityisruokavalio;
    }

    public String getAvainTieto() {
        return avainTieto;
    }

    public void setAvainTieto(String avainTieto) {
        this.avainTieto = avainTieto;
    }

    public String getLisätiedot() {
        return lisätiedot;
    }

    public void setLisätiedot(String lisätiedot) {
        this.lisätiedot = lisätiedot;
    }
}