// Online C++ compiler to run C++ program online
#include <iostream>
#include <limits>
#include <vector>

class Person {
protected:
    std::string personName;

public:
    Person(const std::string& name) : personName(name) {}

    virtual void display() const = 0;
};

class Flight : public Person {
protected:
    int flightID;
    std::string destination;
    int capacity;
    int bookedSeats;

public:
    // The constructor for a regular flight
    Flight(int id, const std::string& dest, int cap)
        : Person("No Passenger"), flightID(id), destination(dest), capacity(cap), bookedSeats(0) {}

    // The constructor for a fully booked flight
    Flight(int id, const std::string& dest, int cap, int booked)
        : Person("No Passenger"), flightID(id), destination(dest), capacity(cap), bookedSeats(booked) {}

    int getFlightID() const {
        return flightID;
    }

    void display() const override {
        std::cout << "Flight ID: " << flightID << "\nDestination: " << destination
                  << "\nMaxCapacity: " << capacity << "\nBooked Seats: " << bookedSeats << std::endl;
    }

    bool bookSeat(const std::string& passengerName) {
        if (bookedSeats < capacity) {
            bookedSeats++;
            this->personName = passengerName;  // Set passenger name for display
            std::cout << "Thank you, your seat has been booked successfully!\n";
            return true;
        } else {
            std::cout << "We are very sorry, the flight you chose is fully booked.\n";
            return false;
        }
    }
};

class Passenger : public Person {
public:
    Passenger(const std::string& name) : Person(name) {}

    void display() const override {
        std::cout << "Passenger Name: " << personName << std::endl;
    }
};

class BookingSystem {
private:
    std::vector<Flight> flights;

public:
    void run() {
        addSampleFlights();
        int choice;
        do {
            displayMainMenu();
            std::cout << "Please select which menu you would like to enter into: ";
            std::cin >> choice;
            switch (choice) {
                case 1:
                    displayAvailableFlights();
                    break;
                case 2:
                    bookSeat();
                    break;
                case 3:
                    restartSystem();
                    break;
                case 0:
                    std::cout << "You are now exiting the Flight Booking System. See you soon!" << std::endl;
                    break;
                default:
                    std::cout << "The input you entered is invalid, please try again." << std::endl;
                    clearInputBuffer();
            }
        } while (choice != 0);
    }

private:
    void displayMainMenu() const {
        std::cout << "\nFlight Booking System Menu\n";
        std::cout << "1. View Available Flights\n";
        std::cout << "2. Book a Seat\n";
        std::cout << "3. Restart the System\n";
        std::cout << "0. Exit the System\n";
    }

    void displayAvailableFlights() const {
        if (flights.empty()) {
            std::cout << "Sorry there are no current flights available.\n";
        } else {
            std::cout << "\nAvailable Flights\n";
            for (const auto& flight : flights) {
                flight.display();
                std::cout << "--------------" << std::endl;
            }
        }
    }

    void bookSeat() {
        int flightID;
        std::string passengerName;
        std::cout << "Please enter the Flight ID: ";
        std::cin >> flightID;
        std::cout << "Please enter your name: ";
        std::cin.ignore();  // Ignore the newline character from previous input
        std::getline(std::cin, passengerName);
        for (auto& flight : flights) {
            if (flightID == flight.getFlightID()) {
                if (!flight.bookSeat(passengerName))
                displayAvailableFlights();
                return;
            }
        }
        std::cout << "Try again, The Flight has not been found with ID: " << flightID << "\n";
    }

    void restartSystem() const {
        std::cout << "Please hold on, the Flight Booking System is being Rebooted.....\n";
        clearInputBuffer();
    }

    void addSampleFlights() {
        flights.push_back(Flight(1, "Cardiff", 100));
        flights.push_back(Flight(2, "Dublin", 120));
        flights.push_back(Flight(3, "London", 90));
        flights.push_back(Flight(4, "Glasgow", 90, 90));  // fully booked flight to test the error messages.
        flights.push_back(Flight(5, "Bristol", 120));
    }

    void clearInputBuffer() const {
        std::cin.clear();
        std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
    }
};

int main() {
    BookingSystem reservationSystem;
    reservationSystem.run();
    return 0;
}
