#include <iostream>
#include <string>
#include <limits>
#include <regex>

using namespace std;

class Flight {
public:
    std::string time;
    std::string origin;
    std::string airline;

    Flight(const std::string& t, const std::string& o, const std::string& a)
            : time(t), origin(o), airline(a) {}
};

class PassengerDetails {
public:
    virtual ~PassengerDetails() {}
    virtual void enterDetails() = 0;
    virtual void displayDetails() const = 0;
};

class Passenger : public PassengerDetails {
public:
    std::string name;
    std::string dateOfBirth;
    std::string passportNumber;
    std::string windowSeat;

    Passenger() {}
    ~Passenger() {}

    bool isValidDate(const std::string& date) {
        std::regex datePattern(R"(\d{2}/\d{2}/\d{4})");
        return std::regex_match(date, datePattern);
    }

    void enterDetails() override {
        std::cout << "Enter your name: \n";
        std::cin.ignore();
        std::getline(std::cin, name);

        do {
            std::cout << "Enter your date of birth (dd/mm/yyyy): \n";
            std::getline(std::cin, dateOfBirth);

            if (!isValidDate(dateOfBirth)) {
                std::cout << "Invalid date format. Please use dd/mm/yyyy.\n";
            }
        } while (!isValidDate(dateOfBirth));

        do {
            std::cout << "Enter your passport number (up to 10 digits): \n";
            std::cin >> passportNumber;

            if (passportNumber.length() > 10) {
                std::cout << "Passport number is too long. Please enter up to 10 digits.\n";
            } else if (!std::all_of(passportNumber.begin(), passportNumber.end(), ::isdigit)) {
                std::cout << "Invalid passport number. Please enter a valid numeric value.\n";
            }
        } while (passportNumber.length() > 10 || !std::all_of(passportNumber.begin(), passportNumber.end(), ::isdigit));

        std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');

        do {
            std::cout << "Window seat? (y/n): \n";
            std::getline(std::cin, windowSeat);

            if (windowSeat != "y" && windowSeat != "Y" && windowSeat != "n" && windowSeat != "N") {
                std::cout << "Invalid input. Please try again.\n";
            }
        } while (windowSeat != "y" && windowSeat != "Y" && windowSeat != "n" && windowSeat != "N");
    }

    void displayDetails() const override {
        std::cout << "Passenger name: " << name << std::endl;
        std::cout << "Date of birth: " << dateOfBirth << std::endl;
        std::cout << "Passport number: " << passportNumber << std::endl;
        std::cout << "Window seat: " << windowSeat << std::endl;
    }
};

class FlightBooking {
private:
    std::string destination;
    bool isBookingConfirmed;
    Flight* selectedFlight;
    PassengerDetails* passengerDetails;

public:
    FlightBooking() : isBookingConfirmed(false), selectedFlight(nullptr), passengerDetails(nullptr) {}

    ~FlightBooking() {
        delete selectedFlight;
        delete passengerDetails;
    }

    void searchFlights() {
        const std::string destinations[] = {"New York", "London", "Barcelona", "Paris", "Rome"};
        const std::string times[] = {"10:25 AM", "02:15 PM", "08:00 AM", "04:00 PM", "12:30 PM"};
        const std::string airlines[] = {"Delta Airlines", "British Airways", "Iberia", "Air France", "Alitalia"};
        const std::string origin[] = {"JFK", "LHR", "BCN", "CDG", "FCO"};

        std::cout << "Available Flights:\n";
        for (int i = 0; i < 5; ++i) {
            std::cout << i + 1 << ". Flight to " << destinations[i] << "\n";
        }

        int choice;
        std::cout << "Select a flight (1-5): ";
        std::cin >> choice;

        if (choice < 1 || choice > 5) {
            std::cout << "Invalid choice.\n";
            return;
        }

        destination = destinations[choice - 1];
        selectedFlight = new Flight(times[choice - 1], origin[choice - 1], airlines[choice - 1]);

        std::cout << "Flight details for " << destination << ":\n";
        std::cout << "Time: " << selectedFlight->time << "\n";
        std::cout << "Origin: " << selectedFlight->origin << "\n";
        std::cout << "Airline: " << selectedFlight->airline << "\n";

        passengerDetails = new Passenger();
        passengerDetails->enterDetails();

        askBookingConfirmation();
    }

    void askBookingConfirmation() {
        char answer;
        std::cout << std::endl << "Do you wish to book this flight? (y/n): \n";
        std::cin >> answer;

        if (answer == 'y' || answer == 'Y') {
            passengerDetails->displayDetails();
            std::cout << "Booking confirmed to " << destination << ". Have a great flight!" << std::endl;
            isBookingConfirmed = true;
            updateBooking();
        }
    }

    void updateBooking() {
        char answer;
        std::cout << "Do you want to update your details? (y/n): \n";
        std::cin >> answer;

        if (answer == 'y' || answer == 'Y') {
            passengerDetails->enterDetails();
            std::cout << "Booking details updated:\n";
            passengerDetails->displayDetails();
            std::cout << std::endl << "Thank you, we have received your request to update booking details.";
        }
    }

    void manageBooking() {
        if (isBookingConfirmed) {
            std::cout << "Manage existing booking to " << destination << ".\n";
            updateBooking();
        } else {
            std::cout << "No booking found. Please search for flights first.\n";
        }
    }
};

int main() {
    FlightBooking booking;

    int choice;
    do {
        std::cout << std::endl << "What would you like to do?" << std::endl;
        std::cout << "1. Search available flights\n";
        std::cout << "2. Manage existing booking\n";
        std::cout << "3. Exit\n";

        std::cin >> choice;

        switch (choice) {
            case 1:
                booking.searchFlights();
                break;
            case 2:
                booking.manageBooking();
                break;
            case 3:
                std::cout << "Exiting programme.\n";
                break;
            default:
                std::cout << "Input error. Please select either 1, 2 or 3 from the options below.\n";
        }

    } while (choice != 3);

    return 0;
}
