package main.java.rdg;

import main.java.DbConnection;

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

public class Screening {
    private long id;
    private long movie;
    private long cinemaHall;
    private Set<Ticket> tickets = new HashSet<>();
    private Timestamp timestamp;

    public long getId() {
        return id;
    }

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

    public long getMovie() {
        return movie;
    }

    public void setMovie(long movie) {
        this.movie = movie;
    }

    public long getCinemaHall() {
        return cinemaHall;
    }

    public void setCinemaHall(long cinemaHall) {
        this.cinemaHall = cinemaHall;
    }

    public Set<Ticket> getTickets() {
        return tickets;
    }

    public void setTickets(Set<Ticket> tickets) {
        this.tickets = tickets;
    }

    public Timestamp getTimestamp() {
        return timestamp;
    }

    public void setTimestamp(Timestamp timestamp) {
        this.timestamp = timestamp;
    }

    @Override
    public String toString() {
        return "Screening{" +
                "id=" + id +
                ", movie=" + movie +
                ", cinemaHall=" + cinemaHall +
                ", tickets=" + tickets +
                ", timestamp=" + timestamp +
                '}';
    }

    public boolean create () {
        DbConnection.setIsolationCommitted();

        try (PreparedStatement s = DbConnection.getCon().prepareStatement("INSERT INTO screenings (movie_id, hall_id, screeningday) VALUES (?, ?, ?)", Statement.RETURN_GENERATED_KEYS)){
            DbConnection.disableCommit();

            s.setLong(1, movie);
            s.setLong(2, cinemaHall);
            s.setTimestamp(3, timestamp);

            s.executeUpdate();

            try (ResultSet r = s.getGeneratedKeys()){
                r.next();
                id = r.getLong(1);
            }

            if (id == 0) return false;

            Set<Long> seats = CinemaHall.getSeats(cinemaHall);

            assert seats != null;
            for (long seatID : seats) {
                Ticket t = new Ticket();
                t.setScreening(id);
                t.setSeat(seatID);

                t.addNewTicket();
            }

            DbConnection.getCon().commit();
        } catch (SQLException e) {
            DbConnection.rollback();
            e.printStackTrace();
            return false;
        } finally {
            DbConnection.resetCommit();
            DbConnection.resetIsolation();
        }
        return true;
    }

    public static Screening read (long id) {
        try (PreparedStatement s = DbConnection.getCon().prepareStatement("SELECT * FROM screenings WHERE screening_id=?")) {
            s.setLong(1, id);

            Screening screening = new Screening();

            try (ResultSet r = s.executeQuery()){
                r.next();

                screening.setId(r.getLong(1));
                screening.setMovie(r.getLong(2));
                screening.setCinemaHall(r.getLong(3));
                screening.setTimestamp(r.getTimestamp(4));
            }
            return screening;

        } catch (SQLException e) {
            e.printStackTrace();
            return null;
        }
    }

    public static List<Screening> readByMovie (long movieID) {
        try (PreparedStatement s = DbConnection.getCon().prepareStatement("SELECT * FROM screenings WHERE movie_id=?")) {
            s.setLong(1, movieID);

            List<Screening> screenings = new ArrayList<>();
            try (ResultSet r = s.executeQuery()){
                while (r.next()) {
                    Screening screening = new Screening();

                    screening.setId(r.getLong(1));
                    screening.setMovie(r.getLong(2));
                    screening.setCinemaHall(r.getLong(3));
                    screening.setTimestamp(r.getTimestamp(4));

                    screenings.add(screening);
                }

            }

            return screenings;

        } catch (SQLException e) {
            e.printStackTrace();
            return null;
        }
    }

    //predpoklada sa ze presun nastane ked este niesu zakupene listky
    public boolean update () {
        try (PreparedStatement s = DbConnection.getCon().prepareStatement("UPDATE screenings SET screeningday=? WHERE screening_id=?")){
            s.setTimestamp(1, timestamp);
            s.setLong(2, id);

            s.executeUpdate();

            //ak sa premietanie presunie (neviem z akeho dovodu) na cas ktory uz uplynul tak zmenime listky na nedostupne
            Timestamp now = new Timestamp(System.currentTimeMillis());
            if (timestamp.before(now)) {
                Ticket.updateAllTicketsState(id, "AVAILABLE", "UNAVAILABLE");
            }

        } catch (SQLException e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    public boolean delete (){
        try (PreparedStatement s = DbConnection.getCon().prepareStatement("DELETE FROM screenings WHERE screening_id=?")){
            s.setLong(1, id);
            s.executeUpdate();

        } catch (SQLException e) {
            e.printStackTrace();
            return false;
        }

        return true;
    }

    public static int freeTicketCount (long id) {
        try (PreparedStatement s = DbConnection.getCon().prepareStatement("SELECT COUNT(*) FROM tickets WHERE screening_id=? and state='AVAILABLE'")){
            s.setLong(1, id);

            try (ResultSet r = s.executeQuery()){
                r.next();
                return r.getInt(1);
            }
        } catch (SQLException e) {
            e.printStackTrace();
            return -1;
        }
    }

    public static Set<Screening> listAll () {
        try (PreparedStatement s = DbConnection.getCon().prepareStatement("SELECT * FROM screenings")){
            Set<Screening> screenings = new HashSet<>();

            try (ResultSet r = s.executeQuery()) {
                while (r.next()) {
                    Screening screening = new Screening();
                    screening.setId(r.getLong(1));
                    screening.setMovie(r.getLong(2));
                    screening.setCinemaHall(r.getLong(3));
                    screening.setTimestamp(r.getTimestamp(4));

                    screenings.add(screening);
                }
            }

            return screenings;
        } catch (SQLException e) {
            e.printStackTrace();
            return null;
        }
    }

    public static String getScreeningType (long id) {
        try (PreparedStatement s = DbConnection.getCon().prepareStatement("" +
                "SELECT ch.screentype FROM screenings s " +
                "INNER JOIN cinema_halls ch on s.hall_id = ch.cinemahall_id " +
                "WHERE s.screening_id=?")){
            s.setLong(1, id);

            try (ResultSet r = s.executeQuery()){
                r.next();
                String type = r.getString(1);
                return type;
            }

        } catch (SQLException e) {
            e.printStackTrace();
            return null;
        }
    }

    public static double screeningRevenue (long id){
        try (PreparedStatement s = DbConnection.getCon().prepareStatement("SELECT SUM(finalprice) FROM tickets" +
                " WHERE screening_id=? AND state='PAID'")){
            s.setLong(1, id);

            try (ResultSet r = s.executeQuery()){
                r.next();
                return r.getDouble(1);
            }

        } catch (SQLException e) {
            e.printStackTrace();
            return 0;
        }
    }

}
