package main.java.rdg;

import main.java.DbConnection;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class Ticket {
    private long id;
    private long screening;
    private long seat;
    private String state;
    private long reservation;
    private long price;

    public long getId() {
        return id;
    }

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

    public long getScreening() {
        return screening;
    }

    public void setScreening(long screening) {
        this.screening = screening;
    }

    public long getSeat() {
        return seat;
    }

    public void setSeat(long seat) {
        this.seat = seat;
    }

    public String getState() {
        return state;
    }

    public void setState(String state) {
        this.state = state;
    }

    public long getReservation() {
        return reservation;
    }

    public void setReservation(long reservation) {
        this.reservation = reservation;
    }

    public long getPrice() {
        return price;
    }

    public void setPrice(long price) {
        this.price = price;
    }

    @Override
    public String toString() {
        return "Ticket{" +
                "id=" + id +
                ", screening=" + screening +
                ", seat=" + seat +
                ", state='" + state + '\'' +
                ", reservation=" + reservation +
                ", price=" + price +
                '}';
    }

    public void addNewTicket () throws SQLException {
        try (PreparedStatement s = DbConnection.getCon().prepareStatement("INSERT INTO tickets (screening_id, seat_id) VALUES (?,?)", Statement.RETURN_GENERATED_KEYS)){
            s.setLong(1, screening);
            s.setLong(2, seat);

            s.executeUpdate();

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



    public static void updateAllTicketsState (long screeningID, String formerState, String newState) throws SQLException {
        if (!List.of("AVAILABLE", "UNAVAILABLE").contains(newState))
            throw new RuntimeException("Invalid state!");

        try (PreparedStatement s = DbConnection.getCon().prepareStatement("UPDATE tickets SET state=? WHERE screening_id=? AND state=?")){
            s.setString(1, newState);
            s.setLong(2, screeningID);
            s.setString(3, formerState);

            s.executeUpdate();
        }
    }

    public static void reserveNTickets (long screeningID, long reservationID, String customerType, int n) {
        try (PreparedStatement s = DbConnection.getCon().prepareStatement("UPDATE tickets SET " +
                "state=?, reservation_id=?, price_id=?, finalprice=? WHERE ticket_id IN " +
                "(SELECT ticket_id FROM tickets WHERE screening_id=? AND state='AVAILABLE' ORDER BY ticket_id ASC LIMIT ?)")) {

            s.setString(1, "RESERVED");
            s.setLong(2, reservationID);
            String type = Screening.getScreeningType(screeningID);
            Price p = Price.getPrice(customerType, type);
            s.setLong(3, p.getId());
            s.setDouble(4, p.getValue());
            s.setLong(5, screeningID);
            s.setInt(6, n);

            s.executeUpdate();

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

    public static void unreserveNTickets (long screeningID, long reservationID, String customerType, int n) {
        try (PreparedStatement s = DbConnection.getCon().prepareStatement("UPDATE tickets SET " +
                "state='AVAILABLE', reservation_id=NULL, price_id=NULL, finalprice=0 WHERE ticket_id IN " +
                "(SELECT ticket_id FROM tickets WHERE screening_id=? AND reservation_id=? AND price_id=? ORDER BY ticket_id ASC LIMIT ?)")) {

            String type = Screening.getScreeningType(screeningID);
            Price p = Price.getPrice(customerType, type);

            s.setLong(1, screeningID);
            s.setLong(2, reservationID);
            s.setLong(3, p.getId());
            s.setInt(4, n);

            s.executeUpdate();

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

    public static boolean unreserveTickets (long reservationID) {
        try (PreparedStatement s = DbConnection.getCon().prepareStatement("UPDATE tickets SET state='AVAILABLE', reservation_id=NULL, finalprice=0, price_id=NULL WHERE reservation_id=? AND state='RESERVED'")){
            s.setLong(1, reservationID);
            s.executeUpdate();

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

    public static boolean payTickets (long reservationID) {
        try (PreparedStatement s = DbConnection.getCon().prepareStatement("UPDATE tickets SET state='SOLD' WHERE reservation_id=?")){
            s.setLong(1, reservationID);
            s.executeUpdate();

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

    public boolean updateTicket (){
        try (PreparedStatement s = DbConnection.getCon().prepareStatement("UPDATE tickets SET state=?, price_id=?, finalprice=? WHERE ticket_id=?")){
            s.setString(1, state);
            s.setLong(2, price);
            s.setDouble(3, Price.read(price).getValue());
            s.setLong(4, id);

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

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

            try (ResultSet r = s.executeQuery()) {
                while (r.next()) {
                    Ticket t = new Ticket();

                    t.setId(r.getLong(1));
                    t.setScreening(r.getLong(2));
                    t.setSeat(r.getLong(3));
                    t.setState(r.getString(4));
                    t.setReservation(r.getLong(5));
                    t.setPrice(r.getLong(6));

                    tickets.add(t);
                }
            }

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

    public boolean delete () {
        try (PreparedStatement s = DbConnection.getCon().prepareStatement("DELETE FROM tickets WHERE ticket_id=?")) {
            s.setLong(1, id);
            s.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    public static Set<Ticket> getScreeningTickets (long screeningID) {
        try (PreparedStatement s = DbConnection.getCon().prepareStatement("SELECT * FROM tickets WHERE screening_id=?")){
            s.setLong(1, screeningID);

            Set<Ticket> tickets = new HashSet<>();

            try (ResultSet r = s.executeQuery()) {
                while (r.next()) {
                    Ticket ticket = new Ticket();

                    ticket.setId(r.getLong(1));
                    ticket.setScreening(screeningID);
                    ticket.setSeat(r.getLong(3));
                    ticket.setState(r.getString(4));
                    ticket.setReservation(r.getLong(5));
                    ticket.setPrice(r.getLong(6));

                    tickets.add(ticket);
                }
            }

            return tickets;

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