-- Создание базы данных
CREATE DATABASE IF NOT EXISTS hotel;
USE hotel;

-- Таблица Administrators
CREATE TABLE Administrators (
    admin_id INT AUTO_INCREMENT PRIMARY KEY,
    full_name VARCHAR(150) NOT NULL,
    passport_number VARCHAR(20) UNIQUE NOT NULL,
    address TEXT NOT NULL,
    phone_number VARCHAR(30) UNIQUE NOT NULL,
    email VARCHAR(100) UNIQUE NOT NULL,
    login VARCHAR(30) UNIQUE NOT NULL,
    password VARCHAR(255) NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

-- Таблица Receptionists
CREATE TABLE Receptionists (
    receptionist_id INT AUTO_INCREMENT PRIMARY KEY,
    full_name VARCHAR(150) NOT NULL,
    passport_number VARCHAR(20) UNIQUE NOT NULL,
    address TEXT NOT NULL,
    phone_number VARCHAR(15) UNIQUE NOT NULL,
    email VARCHAR(100) UNIQUE NOT NULL,
    login VARCHAR(20) UNIQUE NOT NULL,
    password VARCHAR(255) NOT NULL,
    admin_id INT NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    FOREIGN KEY (admin_id) REFERENCES Administrators(admin_id) ON DELETE CASCADE
);

-- Таблица Shifts
CREATE TABLE Shifts (
    shift_id INT AUTO_INCREMENT PRIMARY KEY,
    shift_name VARCHAR(50) NOT NULL UNIQUE,
    start_time TIME NOT NULL,
    end_time TIME NOT NULL
);

-- Вставка фиксированных смен
INSERT INTO Shifts (shift_name, start_time, end_time) VALUES
('Ночь', '00:00:00', '08:00:00'),
('Утро', '08:00:00', '16:00:00'),
('Вечер', '16:00:00', '00:00:00');

-- Таблица Cleaners
CREATE TABLE Cleaners (
    cleaner_id INT AUTO_INCREMENT PRIMARY KEY,
    full_name VARCHAR(150) NOT NULL,
    phone_number VARCHAR(15) UNIQUE NOT NULL,
    email VARCHAR(100) UNIQUE NOT NULL,
    status ENUM('Свободен', 'Занят') DEFAULT 'Свободен',
    shift_id INT NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    FOREIGN KEY (shift_id) REFERENCES Shifts(shift_id) ON DELETE RESTRICT ON UPDATE CASCADE
);


-- Таблица Rooms
CREATE TABLE Rooms (
    room_id INT AUTO_INCREMENT PRIMARY KEY,
    room_number INT UNIQUE NOT NULL,
    status ENUM('Доступен', 'Недоступен') DEFAULT 'Доступен',
    price DECIMAL(10,2) NOT NULL,
    bed_type ENUM('Одноместный', 'Двухместный', 'Трехместный', 'Четырехместный') NOT NULL,
    room_type ENUM('Стандарт', 'Люкс', 'Делюкс') NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

-- Таблица Cleaning_Schedules
CREATE TABLE Cleaning_Schedules (
    schedule_id INT AUTO_INCREMENT PRIMARY KEY,
    room_id INT NOT NULL,
    cleaner_id INT NOT NULL,
    scheduled_time DATETIME NOT NULL,
    status ENUM('Назначено', 'В процессе', 'Завершено') DEFAULT 'Назначено',
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    FOREIGN KEY (room_id) REFERENCES Rooms(room_id) ON DELETE CASCADE,
    FOREIGN KEY (cleaner_id) REFERENCES Cleaners(cleaner_id) ON DELETE CASCADE
);

-- Таблица Room_Images
CREATE TABLE Room_Images (
    image_id INT AUTO_INCREMENT PRIMARY KEY,
    room_id INT NOT NULL,
    image_url VARCHAR(255) NOT NULL,
    is_primary BOOLEAN DEFAULT FALSE,
    FOREIGN KEY (room_id) REFERENCES Rooms(room_id) ON DELETE CASCADE
);

-- Таблица Customers
CREATE TABLE Customers (
    customer_id INT AUTO_INCREMENT PRIMARY KEY,
    full_name VARCHAR(100) NOT NULL,
    phone VARCHAR(15) UNIQUE NOT NULL,
    email VARCHAR(100) UNIQUE,
    gender ENUM('Мужской', 'Женский'),
    country VARCHAR(50),
    address TEXT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    receptionist_id INT,
    FOREIGN KEY (receptionist_id) REFERENCES Receptionists(receptionist_id) ON DELETE SET NULL
);

-- Таблица Reservations
CREATE TABLE Reservations (
    reservation_id INT AUTO_INCREMENT PRIMARY KEY,
    customer_id INT NOT NULL,
    room_id INT NOT NULL,
    check_in DATE NOT NULL,
    check_out DATE NOT NULL,
    status ENUM('Забронирован', 'Заселён', 'Выселен', 'Отменён') DEFAULT 'Забронирован',
    total_amount DECIMAL(10,2),
    deposit DECIMAL(10,2),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    receptionist_id INT,
    FOREIGN KEY (customer_id) REFERENCES Customers(customer_id) ON DELETE CASCADE,
    FOREIGN KEY (room_id) REFERENCES Rooms(room_id) ON DELETE CASCADE,
    FOREIGN KEY (receptionist_id) REFERENCES Receptionists(receptionist_id) ON DELETE SET NULL
);

-- Таблица Payments
CREATE TABLE Payments (
    payment_id INT AUTO_INCREMENT PRIMARY KEY,
    reservation_id INT NOT NULL,
    amount DECIMAL(10, 2) NOT NULL,
    payment_date DATE NOT NULL,
    payment_method ENUM('Наличные', 'Кредитная карта', 'Дебетовая карта', 'Онлайн перевод') NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (reservation_id) REFERENCES Reservations(reservation_id) ON DELETE CASCADE
);

-- Таблица Cleaning_Actions
CREATE TABLE Cleaning_Actions (
    action_id INT AUTO_INCREMENT PRIMARY KEY,
    reservation_id INT NOT NULL,
    room_id INT NOT NULL,
    cleaner_id INT NOT NULL,
    action_type ENUM('Ручное назначение', 'Автоматическое назначение') NOT NULL,
    scheduled_time DATETIME NOT NULL,
    status ENUM('Запланировано', 'В процессе', 'Завершено') DEFAULT 'Запланировано',
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    FOREIGN KEY (reservation_id) REFERENCES Reservations(reservation_id) ON DELETE CASCADE,
    FOREIGN KEY (room_id) REFERENCES Rooms(room_id) ON DELETE CASCADE,
    FOREIGN KEY (cleaner_id) REFERENCES Cleaners(cleaner_id) ON DELETE CASCADE
);






DELIMITER $$

CREATE TRIGGER trg_update_room_availability
AFTER UPDATE ON Reservations
FOR EACH ROW
BEGIN
    IF NEW.status = 'Забронирован' OR NEW.status = 'Заселён' THEN
        UPDATE Rooms
        SET available = FALSE,
            status = 'Недоступен'
        WHERE room_id = NEW.room_id;
    ELSEIF NEW.status = 'Отменён' OR NEW.status = 'Выселен' THEN
        UPDATE Rooms
        SET available = TRUE,
            status = 'Доступен'
        WHERE room_id = NEW.room_id;
    END IF;
END$$

DELIMITER ;





DELIMITER $$

CREATE TRIGGER trg_prevent_overlapping_reservations
BEFORE INSERT ON Reservations
FOR EACH ROW
BEGIN
    IF EXISTS (
        SELECT 1 FROM Reservations
        WHERE room_id = NEW.room_id
          AND status NOT IN ('Отменён')
          AND (
              (NEW.check_in BETWEEN check_in AND check_out) OR
              (NEW.check_out BETWEEN check_in AND check_out) OR
              (check_in BETWEEN NEW.check_in AND NEW.check_out)
          )
    ) THEN
        SIGNAL SQLSTATE '45000' 
            SET MESSAGE_TEXT = 'Номер уже забронирован на указанные даты.';
    END IF;
END$$

DELIMITER ;





DELIMITER $$

CREATE TRIGGER trg_calculate_total_amount_before_insert
BEFORE INSERT ON Reservations
FOR EACH ROW
BEGIN
    DECLARE roomPrice DECIMAL(10,2);
    DECLARE days INT;

    SELECT price INTO roomPrice FROM Rooms WHERE room_id = NEW.room_id;
    SET days = DATEDIFF(NEW.check_out, NEW.check_in);
    IF days <= 0 THEN
        SIGNAL SQLSTATE '45000' 
            SET MESSAGE_TEXT = 'Дата выезда должна быть позже даты заезда.';
    END IF;
    SET NEW.total_amount = roomPrice * days;
END$$

CREATE TRIGGER trg_calculate_total_amount_before_update
BEFORE UPDATE ON Reservations
FOR EACH ROW
BEGIN
    DECLARE roomPrice DECIMAL(10,2);
    DECLARE days INT;

    SELECT price INTO roomPrice FROM Rooms WHERE room_id = NEW.room_id;
    SET days = DATEDIFF(NEW.check_out, NEW.check_in);
    IF days <= 0 THEN
        SIGNAL SQLSTATE '45000' 
            SET MESSAGE_TEXT = 'Дата выезда должна быть позже даты заезда.';
    END IF;
    SET NEW.total_amount = roomPrice * days;
END$$

DELIMITER ;




DELIMITER $$

CREATE TRIGGER trg_update_cleaner_status_after_action_complete
AFTER UPDATE ON Cleaning_Actions
FOR EACH ROW
BEGIN
    IF NEW.status = 'Завершено' THEN
        UPDATE Cleaners
        SET status = 'Свободен'
        WHERE cleaner_id = NEW.cleaner_id;
    ELSEIF NEW.status = 'В процессе' THEN
        UPDATE Cleaners
        SET status = 'Занят'
        WHERE cleaner_id = NEW.cleaner_id;
    END IF;
END$$

DELIMITER ;











INSERT INTO Administrators (
        full_name, 
        passport_number, 
        address, 
        phone_number, 
        email, 
        login, 
        password, 
        registration_code
    ) VALUES (
        'Иванов Иван Иванович',
        '4510 123456',
        'г. Москва, ул. Ленина, д. 1, кв. 1',
        '+7(999)123-45-67',
        'ivanov@hotel.ru',
        'admin',
        SHA2('admin123', 256), -- используем SHA2 с длиной 256 бит
        'ADM001'
    );

















-- Добавление комнат
INSERT INTO Rooms (room_number, price, bed_type, room_type) VALUES
(101, 3000.00, 'Одноместный', 'Стандарт'),
(102, 3500.00, 'Двухместный', 'Стандарт'),
(201, 4000.00, 'Двухместный', 'Стандарт'),
(202, 4500.00, 'Двухместный', 'Делюкс'),
(301, 5000.00, 'Двухместный', 'Люкс'),
(302, 5500.00, 'Трехместный', 'Люкс'),
(401, 6000.00, 'Четырехместный', 'Люкс'),
(402, 4200.00, 'Двухместный', 'Делюкс'),
(501, 3800.00, 'Двухместный', 'Стандарт'),
(502, 7000.00, 'Четырехместный', 'Люкс');











-- Добавление уборщиков
INSERT INTO Cleaners (full_name, phone_number, email, shift_id) VALUES
('Петрова Анна Сергеевна', '+7(999)111-22', 'petrova@hotel.ru', 1),
('Сидорова Елена Павловна', '+7(999)222-33', 'sidorova@hotel.ru', 2),
('Козлова Мария Ивановна', '+7(999)333-44', 'kozlova@hotel.ru', 3),
('Николаева Ольга Дмитриевна', '+7(999)444-55', 'nikolaeva@hotel.ru', 1),
('Морозова Татьяна Александровна', '+7(999)555-66', 'morozova@hotel.ru', 2);










-- Добавление изображений для номеров
INSERT INTO Room_Images (room_id, image_url, is_primary) VALUES
(1, '/images/rooms/101/main.jpg', TRUE),
(2, '/images/rooms/101/bathroom.jpg', TRUE),
(3, '/images/rooms/101/view.jpg', TRUE),
(4, '/images/rooms/102/main.jpg', TRUE),
(5, '/images/rooms/102/bathroom.jpg', TRUE),
(6, '/images/rooms/201/main.jpg', TRUE),
(7, '/images/rooms/201/living.jpg', TRUE),
(8, '/images/rooms/202/main.jpg', TRUE),
(9, '/images/rooms/202/bathroom.jpg', TRUE),
(10, '/images/rooms/301/main.jpg', TRUE);








// src/h/ConnectMySQL.java
package h;

import java.sql.*;

public class ConnectMySQL implements AutoCloseable {
    private static final String URL = "jdbc:mysql://localhost:1369/hotel?useSSL=false&serverTimezone=UTC";
    private static final String USER = "root";
    private static final String PASSWORD = "1369sukAnigghaD1ck";

    private Connection connection;

    public ConnectMySQL() throws SQLException, ClassNotFoundException {
        // Загрузка драйвера MySQL JDBC
        Class.forName("com.mysql.cj.jdbc.Driver");
        this.connection = DriverManager.getConnection(URL, USER, PASSWORD);
    }

    public Connection getConnection() {
        return connection;
    }

    @Override
    public void close() throws SQLException {
        if (connection != null && !connection.isClosed()) {
            connection.close();
        }
    }
}













package h;

import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import java.awt.*;
import java.awt.event.*;
import java.sql.*;
import java.util.Vector;

public class DashboardAdmin extends JFrame {
    private JPanel roomsPanel;
    private int adminId;
    private JTabbedPane tabbedPane;

    // Components for Receptionists Tab
    private JTable receptionistsTable;
    private DefaultTableModel receptionistsModel;
    private JButton addReceptionistButton, editReceptionistButton, deleteReceptionistButton;

    // Components for Cleaners Tab
    private JTable cleanersTable;
    private DefaultTableModel cleanersModel;
    private JButton addCleanerButton, editCleanerButton, deleteCleanerButton;

    // Components for Rooms Tab
    private JTable roomsTable;
    private DefaultTableModel roomsModel;
    private JButton addRoomButton, editRoomButton, deleteRoomButton;

    // Components for Income Tab
    private JLabel totalIncomeLabel;
    private JTable paymentsTable;
    private DefaultTableModel paymentsModel;

    public DashboardAdmin(int adminId) {
        this.adminId = adminId;
        setTitle("Панель Администратора");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(1200, 800);
        setLocationRelativeTo(null);

        tabbedPane = new JTabbedPane();

        // Инициализируем вкладки
        initReceptionistsTab();
        initCleanersTab();
        initRoomsTab();
        initIncomeTab();

        add(tabbedPane);

        setVisible(true);
    }

    // Инициализация вкладки "Ресепшионисты"
    private void initReceptionistsTab() {
        JPanel panel = new JPanel(new BorderLayout());

        // Верхняя панель с кнопками
        JPanel topPanel = new JPanel();
        addReceptionistButton = new JButton("Добавить");
        editReceptionistButton = new JButton("Редактировать");
        deleteReceptionistButton = new JButton("Удалить");

        topPanel.add(addReceptionistButton);
        topPanel.add(editReceptionistButton);
        topPanel.add(deleteReceptionistButton);

        panel.add(topPanel, BorderLayout.NORTH);

        // Таблица ресепшионистов
        receptionistsModel = new DefaultTableModel();
        receptionistsTable = new JTable(receptionistsModel);
        receptionistsModel.setColumnIdentifiers(new String[]{
                "ID", "Полное имя", "Номер паспорта", "Адрес", "Телефон", "Email", "Логин", "Дата создания", "Дата обновления"
        });

        loadReceptionists();

        JScrollPane scrollPane = new JScrollPane(receptionistsTable);
        panel.add(scrollPane, BorderLayout.CENTER);

        // Обработчики кнопок
        addReceptionistButton.addActionListener(e -> openAddReceptionistDialog());
        editReceptionistButton.addActionListener(e -> openEditReceptionistDialog());
        deleteReceptionistButton.addActionListener(e -> deleteSelectedReceptionist());

        tabbedPane.addTab("Ресепшионисты", panel);
    }

    // Загрузка данных ресепшионистов из базы
    private void loadReceptionists() {
        receptionistsModel.setRowCount(0);
        try {
            ConnectMySQL connection = new ConnectMySQL();
            Connection conn = connection.getConnection();
            String query = "SELECT receptionist_id, full_name, passport_number, address, phone_number, email, login, created_at, updated_at FROM Receptionists";
            Statement stmt = conn.createStatement();
            ResultSet rs = stmt.executeQuery(query);

            while (rs.next()) {
                Vector<Object> row = new Vector<>();
                row.add(rs.getInt("receptionist_id"));
                row.add(rs.getString("full_name"));
                row.add(rs.getString("passport_number"));
                row.add(rs.getString("address"));
                row.add(rs.getString("phone_number"));
                row.add(rs.getString("email"));
                row.add(rs.getString("login"));
                row.add(rs.getTimestamp("created_at"));
                row.add(rs.getTimestamp("updated_at"));
                receptionistsModel.addRow(row);
            }
            conn.close();
        } catch (Exception e) {
            e.printStackTrace();
            JOptionPane.showMessageDialog(this, "Ошибка загрузки ресепшионистов.", "Ошибка", JOptionPane.ERROR_MESSAGE);
        }
    }

    // Диалог для добавления нового ресепшиониста
    private void openAddReceptionistDialog() {
        JDialog dialog = new JDialog(this, "Добавить Ресепшиониста", true);
        dialog.setSize(400, 500);
        dialog.setLocationRelativeTo(this);
        dialog.setLayout(new GridBagLayout());

        GridBagConstraints gbc = new GridBagConstraints();
        gbc.insets = new Insets(5,5,5,5);
        gbc.fill = GridBagConstraints.HORIZONTAL;

        // Поля ввода
        JLabel nameLabel = new JLabel("Полное имя:");
        JTextField nameField = new JTextField(20);
        JLabel passportLabel = new JLabel("Номер паспорта:");
        JTextField passportField = new JTextField(20);
        JLabel addressLabel = new JLabel("Адрес:");
        JTextField addressField = new JTextField(20);
        JLabel phoneLabel = new JLabel("Телефон:");
        JTextField phoneField = new JTextField(20);
        JLabel emailLabel = new JLabel("Email:");
        JTextField emailField = new JTextField(20);
        JLabel loginLabel = new JLabel("Логин:");
        JTextField loginField = new JTextField(20);
        JLabel passwordLabel = new JLabel("Пароль:");
        JPasswordField passwordField = new JPasswordField(20);

        // Кнопки
        JButton saveButton = new JButton("Сохранить");
        JButton cancelButton = new JButton("Отмена");

        // Размещение компонентов
        gbc.gridx = 0;
        gbc.gridy = 0;
        dialog.add(nameLabel, gbc);
        gbc.gridx = 1;
        dialog.add(nameField, gbc);

        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(passportLabel, gbc);
        gbc.gridx = 1;
        dialog.add(passportField, gbc);

        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(addressLabel, gbc);
        gbc.gridx = 1;
        dialog.add(addressField, gbc);

        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(phoneLabel, gbc);
        gbc.gridx = 1;
        dialog.add(phoneField, gbc);

        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(emailLabel, gbc);
        gbc.gridx = 1;
        dialog.add(emailField, gbc);

        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(loginLabel, gbc);
        gbc.gridx = 1;
        dialog.add(loginField, gbc);

        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(passwordLabel, gbc);
        gbc.gridx = 1;
        dialog.add(passwordField, gbc);

        // Панель кнопок
        JPanel buttonPanel = new JPanel();
        buttonPanel.add(saveButton);
        buttonPanel.add(cancelButton);
        gbc.gridx = 0;
        gbc.gridy++;
        gbc.gridwidth = 2;
        dialog.add(buttonPanel, gbc);

        // Обработчики кнопок
        saveButton.addActionListener(e -> {
            String fullName = nameField.getText().trim();
            String passport = passportField.getText().trim();
            String address = addressField.getText().trim();
            String phone = phoneField.getText().trim();
            String email = emailField.getText().trim();
            String login = loginField.getText().trim();
            String password = new String(passwordField.getPassword()).trim();

            if (fullName.isEmpty() || passport.isEmpty() || address.isEmpty() ||
                    phone.isEmpty() || email.isEmpty() || login.isEmpty() || password.isEmpty()) {
                JOptionPane.showMessageDialog(dialog, "Пожалуйста, заполните все поля.", "Ошибка", JOptionPane.ERROR_MESSAGE);
                return;
            }

            try {
                ConnectMySQL connection = new ConnectMySQL();
                Connection conn = connection.getConnection();

                String query = "INSERT INTO Receptionists (full_name, passport_number, address, phone_number, email, login, password, admin_id, created_at, updated_at) "
                        + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, NOW(), NOW())";
                PreparedStatement pstmt = conn.prepareStatement(query);
                pstmt.setString(1, fullName);
                pstmt.setString(2, passport);
                pstmt.setString(3, address);
                pstmt.setString(4, phone);
                pstmt.setString(5, email);
                pstmt.setString(6, login);
                pstmt.setString(7, hashPassword(password));
                pstmt.setInt(8, adminId); // Привязываем к текущему администратору

                pstmt.executeUpdate();
                conn.close();

                JOptionPane.showMessageDialog(dialog, "Ресепшионист добавлен успешно.");
                dialog.dispose();
                loadReceptionists();
            } catch (SQLIntegrityConstraintViolationException ex) {
                JOptionPane.showMessageDialog(dialog, "Логин, телефон или email уже существуют!", "Ошибка", JOptionPane.ERROR_MESSAGE);
            } catch (Exception ex) {
                ex.printStackTrace();
                JOptionPane.showMessageDialog(dialog, "Ошибка подключения к базе данных.", "Ошибка", JOptionPane.ERROR_MESSAGE);
            }
        });

        cancelButton.addActionListener(e -> dialog.dispose());

        dialog.setVisible(true);
    }

    // Диалог для редактирования выбранного ресепшиониста
    private void openEditReceptionistDialog() {
        int selectedRow = receptionistsTable.getSelectedRow();
        if (selectedRow == -1) {
            JOptionPane.showMessageDialog(this, "Пожалуйста, выберите ресепшиониста для редактирования.", "Информация", JOptionPane.INFORMATION_MESSAGE);
            return;
        }

        int receptionistId = (int) receptionistsModel.getValueAt(selectedRow, 0);
        String currentName = (String) receptionistsModel.getValueAt(selectedRow, 1);
        String currentPassport = (String) receptionistsModel.getValueAt(selectedRow, 2);
        String currentAddress = (String) receptionistsModel.getValueAt(selectedRow, 3);
        String currentPhone = (String) receptionistsModel.getValueAt(selectedRow, 4);
        String currentEmail = (String) receptionistsModel.getValueAt(selectedRow, 5);
        String currentLogin = (String) receptionistsModel.getValueAt(selectedRow, 6);

        JDialog dialog = new JDialog(this, "Редактировать Ресепшиониста", true);
        dialog.setSize(400, 500);
        dialog.setLocationRelativeTo(this);
        dialog.setLayout(new GridBagLayout());

        GridBagConstraints gbc = new GridBagConstraints();
        gbc.insets = new Insets(5,5,5,5);
        gbc.fill = GridBagConstraints.HORIZONTAL;

        // Поля ввода
        JLabel nameLabel = new JLabel("Полное имя:");
        JTextField nameField = new JTextField(currentName, 20);
        JLabel passportLabel = new JLabel("Номер паспорта:");
        JTextField passportField = new JTextField(currentPassport, 20);
        JLabel addressLabel = new JLabel("Адрес:");
        JTextField addressField = new JTextField(currentAddress, 20);
        JLabel phoneLabel = new JLabel("Телефон:");
        JTextField phoneField = new JTextField(currentPhone, 20);
        JLabel emailLabel = new JLabel("Email:");
        JTextField emailField = new JTextField(currentEmail, 20);
        JLabel loginLabel = new JLabel("Логин:");
        JTextField loginField = new JTextField(currentLogin, 20);
        JLabel passwordLabel = new JLabel("Новый Пароль:");
        JPasswordField passwordField = new JPasswordField(20);

        // Кнопки
        JButton saveButton = new JButton("Сохранить");
        JButton cancelButton = new JButton("Отмена");

        // Размещение компонентов
        gbc.gridx = 0;
        gbc.gridy = 0;
        dialog.add(nameLabel, gbc);
        gbc.gridx = 1;
        dialog.add(nameField, gbc);

        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(passportLabel, gbc);
        gbc.gridx = 1;
        dialog.add(passportField, gbc);

        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(addressLabel, gbc);
        gbc.gridx = 1;
        dialog.add(addressField, gbc);

        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(phoneLabel, gbc);
        gbc.gridx = 1;
        dialog.add(phoneField, gbc);

        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(emailLabel, gbc);
        gbc.gridx = 1;
        dialog.add(emailField, gbc);

        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(loginLabel, gbc);
        gbc.gridx = 1;
        dialog.add(loginField, gbc);

        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(passwordLabel, gbc);
        gbc.gridx = 1;
        dialog.add(passwordField, gbc);

        // Панель кнопок
        JPanel buttonPanel = new JPanel();
        buttonPanel.add(saveButton);
        buttonPanel.add(cancelButton);
        gbc.gridx = 0;
        gbc.gridy++;
        gbc.gridwidth = 2;
        dialog.add(buttonPanel, gbc);

        // Обработчики кнопок
        saveButton.addActionListener(e -> {
            String fullName = nameField.getText().trim();
            String passport = passportField.getText().trim();
            String address = addressField.getText().trim();
            String phone = phoneField.getText().trim();
            String email = emailField.getText().trim();
            String login = loginField.getText().trim();
            String password = new String(passwordField.getPassword()).trim();

            if (fullName.isEmpty() || passport.isEmpty() || address.isEmpty() ||
                    phone.isEmpty() || email.isEmpty() || login.isEmpty()) {
                JOptionPane.showMessageDialog(dialog, "Пожалуйста, заполните все обязательные поля.", "Ошибка", JOptionPane.ERROR_MESSAGE);
                return;
            }

            try {
                ConnectMySQL connection = new ConnectMySQL();
                Connection conn = connection.getConnection();

                String query;
                if (password.isEmpty()) {
                    // Если пароль не изменяется
                    query = "UPDATE Receptionists SET full_name = ?, passport_number = ?, address = ?, phone_number = ?, email = ?, login = ?, updated_at = NOW() WHERE receptionist_id = ?";
                } else {
                    // Если пароль изменяется
                    query = "UPDATE Receptionists SET full_name = ?, passport_number = ?, address = ?, phone_number = ?, email = ?, login = ?, password = ?, updated_at = NOW() WHERE receptionist_id = ?";
                }

                PreparedStatement pstmt = conn.prepareStatement(query);
                pstmt.setString(1, fullName);
                pstmt.setString(2, passport);
                pstmt.setString(3, address);
                pstmt.setString(4, phone);
                pstmt.setString(5, email);
                pstmt.setString(6, login);
                if (password.isEmpty()) {
                    pstmt.setInt(7, receptionistId);
                } else {
                    pstmt.setString(7, hashPassword(password));
                    pstmt.setInt(8, receptionistId);
                }

                pstmt.executeUpdate();
                conn.close();

                JOptionPane.showMessageDialog(dialog, "Ресепшионист обновлен успешно.");
                dialog.dispose();
                loadReceptionists();
            } catch (SQLIntegrityConstraintViolationException ex) {
                JOptionPane.showMessageDialog(dialog, "Логин, телефон или email уже существуют!", "Ошибка", JOptionPane.ERROR_MESSAGE);
            } catch (Exception ex) {
                ex.printStackTrace();
                JOptionPane.showMessageDialog(dialog, "Ошибка подключения к базе данных.", "Ошибка", JOptionPane.ERROR_MESSAGE);
            }
        });

        cancelButton.addActionListener(e -> dialog.dispose());

        dialog.setVisible(true);
    }

    // Удаление выбранного ресепшиониста
    private void deleteSelectedReceptionist() {
        int selectedRow = receptionistsTable.getSelectedRow();
        if (selectedRow == -1) {
            JOptionPane.showMessageDialog(this, "Пожалуйста, выберите ресепшиониста для удаления.", "Информация", JOptionPane.INFORMATION_MESSAGE);
            return;
        }

        int receptionistId = (int) receptionistsModel.getValueAt(selectedRow, 0);
        String receptionistName = (String) receptionistsModel.getValueAt(selectedRow, 1);

        int confirm = JOptionPane.showConfirmDialog(this, "Вы уверены, что хотите удалить ресепшиониста \"" + receptionistName + "\"?", "Подтверждение", JOptionPane.YES_NO_OPTION);
        if (confirm != JOptionPane.YES_OPTION) {
            return;
        }

        try {
            ConnectMySQL connection = new ConnectMySQL();
            Connection conn = connection.getConnection();

            String query = "DELETE FROM Receptionists WHERE receptionist_id = ?";
            PreparedStatement pstmt = conn.prepareStatement(query);
            pstmt.setInt(1, receptionistId);
            pstmt.executeUpdate();
            conn.close();

            JOptionPane.showMessageDialog(this, "Ресепшионист удален успешно.");
            loadReceptionists();
        } catch (Exception e) {
            e.printStackTrace();
            JOptionPane.showMessageDialog(this, "Ошибка при удалении ресепшиониста.", "Ошибка", JOptionPane.ERROR_MESSAGE);
        }
    }

    // Инициализация вкладки "Уборщики"
    private void initCleanersTab() {
        JPanel panel = new JPanel(new BorderLayout());

        // Верхняя панель с кнопками
        JPanel topPanel = new JPanel();
        addCleanerButton = new JButton("Добавить");
        editCleanerButton = new JButton("Редактировать");
        deleteCleanerButton = new JButton("Удалить");

        topPanel.add(addCleanerButton);
        topPanel.add(editCleanerButton);
        topPanel.add(deleteCleanerButton);

        panel.add(topPanel, BorderLayout.NORTH);

        // Таблица уборщиков
        cleanersModel = new DefaultTableModel();
        cleanersTable = new JTable(cleanersModel);
        cleanersModel.setColumnIdentifiers(new String[]{
                "ID", "Полное имя", "Телефон", "Email", "Статус", "Смена", "Дата создания", "Дата обновления"
        });

        loadCleaners();

        JScrollPane scrollPane = new JScrollPane(cleanersTable);
        panel.add(scrollPane, BorderLayout.CENTER);

        // Обработчики кнопок
        addCleanerButton.addActionListener(e -> openAddCleanerDialog());
        editCleanerButton.addActionListener(e -> openEditCleanerDialog());
        deleteCleanerButton.addActionListener(e -> deleteSelectedCleaner());

        tabbedPane.addTab("Уборщики", panel);
    }

    // Загрузка данных уборщиков из базы
    private void loadCleaners() {
        cleanersModel.setRowCount(0);
        try {
            ConnectMySQL connection = new ConnectMySQL();
            Connection conn = connection.getConnection();
            String query = "SELECT c.cleaner_id, c.full_name, c.phone_number, c.email, c.status, s.shift_name, c.created_at, c.updated_at " +
                    "FROM Cleaners c JOIN Shifts s ON c.shift_id = s.shift_id";
            Statement stmt = conn.createStatement();
            ResultSet rs = stmt.executeQuery(query);

            while (rs.next()) {
                Vector<Object> row = new Vector<>();
                row.add(rs.getInt("cleaner_id"));
                row.add(rs.getString("full_name"));
                row.add(rs.getString("phone_number"));
                row.add(rs.getString("email"));
                row.add(rs.getString("status"));
                row.add(rs.getString("shift_name"));
                row.add(rs.getTimestamp("created_at"));
                row.add(rs.getTimestamp("updated_at"));
                cleanersModel.addRow(row);
            }
            conn.close();
        } catch (Exception e) {
            e.printStackTrace();
            JOptionPane.showMessageDialog(this, "Ошибка загрузки уборщиков.", "Ошибка", JOptionPane.ERROR_MESSAGE);
        }
    }

    // Диалог для добавления нового уборщика
    private void openAddCleanerDialog() {
        JDialog dialog = new JDialog(this, "Добавить Уборщика", true);
        dialog.setSize(400, 400);
        dialog.setLocationRelativeTo(this);
        dialog.setLayout(new GridBagLayout());

        GridBagConstraints gbc = new GridBagConstraints();
        gbc.insets = new Insets(5,5,5,5);
        gbc.fill = GridBagConstraints.HORIZONTAL;

        // Поля ввода
        JLabel nameLabel = new JLabel("Полное имя:");
        JTextField nameField = new JTextField(20);
        JLabel phoneLabel = new JLabel("Телефон:");
        JTextField phoneField = new JTextField(20);
        JLabel emailLabel = new JLabel("Email:");
        JTextField emailField = new JTextField(20);
        JLabel statusLabel = new JLabel("Статус:");
        JComboBox<String> statusComboBox = new JComboBox<>(new String[]{"Свободен", "Занят"});
        JLabel shiftLabel = new JLabel("Смена:");
        JComboBox<String> shiftComboBox = new JComboBox<>();

        // Загрузка смен из базы
        try {
            ConnectMySQL connection = new ConnectMySQL();
            Connection conn = connection.getConnection();
            String shiftQuery = "SELECT shift_id, shift_name FROM Shifts";
            Statement stmt = conn.createStatement();
            ResultSet rs = stmt.executeQuery(shiftQuery);
            while (rs.next()) {
                shiftComboBox.addItem(rs.getString("shift_name"));
            }
            conn.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

        // Кнопки
        JButton saveButton = new JButton("Сохранить");
        JButton cancelButton = new JButton("Отмена");

        // Размещение компонентов
        gbc.gridx = 0;
        gbc.gridy = 0;
        dialog.add(nameLabel, gbc);
        gbc.gridx = 1;
        dialog.add(nameField, gbc);

        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(phoneLabel, gbc);
        gbc.gridx = 1;
        dialog.add(phoneField, gbc);

        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(emailLabel, gbc);
        gbc.gridx = 1;
        dialog.add(emailField, gbc);

        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(statusLabel, gbc);
        gbc.gridx = 1;
        dialog.add(statusComboBox, gbc);

        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(shiftLabel, gbc);
        gbc.gridx = 1;
        dialog.add(shiftComboBox, gbc);

        // Панель кнопок
        JPanel buttonPanel = new JPanel();
        buttonPanel.add(saveButton);
        buttonPanel.add(cancelButton);
        gbc.gridx = 0;
        gbc.gridy++;
        gbc.gridwidth = 2;
        dialog.add(buttonPanel, gbc);

        // Обработчики кнопок
        saveButton.addActionListener(e -> {
            String fullName = nameField.getText().trim();
            String phone = phoneField.getText().trim();
            String email = emailField.getText().trim();
            String status = (String) statusComboBox.getSelectedItem();
            String shiftName = (String) shiftComboBox.getSelectedItem();

            if (fullName.isEmpty() || phone.isEmpty() || email.isEmpty() || shiftName == null) {
                JOptionPane.showMessageDialog(dialog, "Пожалуйста, заполните все обязательные поля.", "Ошибка", JOptionPane.ERROR_MESSAGE);
                return;
            }

            try {
                int shiftId = getShiftIdByName(shiftName);
                if (shiftId == -1) {
                    JOptionPane.showMessageDialog(dialog, "Выбранная смена не существует.", "Ошибка", JOptionPane.ERROR_MESSAGE);
                    return;
                }

                ConnectMySQL connection = new ConnectMySQL();
                Connection conn = connection.getConnection();

                String query = "INSERT INTO Cleaners (full_name, phone_number, email, status, shift_id, created_at, updated_at) "
                        + "VALUES (?, ?, ?, ?, ?, NOW(), NOW())";
                PreparedStatement pstmt = conn.prepareStatement(query);
                pstmt.setString(1, fullName);
                pstmt.setString(2, phone);
                pstmt.setString(3, email);
                pstmt.setString(4, status);
                pstmt.setInt(5, shiftId);

                pstmt.executeUpdate();
                conn.close();

                JOptionPane.showMessageDialog(dialog, "Уборщик добавлен успешно.");
                dialog.dispose();
                loadCleaners();
            } catch (SQLIntegrityConstraintViolationException ex) {
                JOptionPane.showMessageDialog(dialog, "Телефон или email уже существуют!", "Ошибка", JOptionPane.ERROR_MESSAGE);
            } catch (Exception ex) {
                ex.printStackTrace();
                JOptionPane.showMessageDialog(dialog, "Ошибка подключения к базе данных.", "Ошибка", JOptionPane.ERROR_MESSAGE);
            }
        });

        cancelButton.addActionListener(e -> dialog.dispose());

        dialog.setVisible(true);
    }

    // Получение ID смены по имени
    private int getShiftIdByName(String shiftName) {
        int shiftId = -1;
        try {
            ConnectMySQL connection = new ConnectMySQL();
            Connection conn = connection.getConnection();
            String query = "SELECT shift_id FROM Shifts WHERE shift_name = ?";
            PreparedStatement pstmt = conn.prepareStatement(query);
            pstmt.setString(1, shiftName);
            ResultSet rs = pstmt.executeQuery();
            if (rs.next()) {
                shiftId = rs.getInt("shift_id");
            }
            conn.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return shiftId;
    }

    // Диалог для редактирования выбранного уборщика
    private void openEditCleanerDialog() {
        int selectedRow = cleanersTable.getSelectedRow();
        if (selectedRow == -1) {
            JOptionPane.showMessageDialog(this, "Пожалуйста, выберите уборщика для редактирования.", "Информация", JOptionPane.INFORMATION_MESSAGE);
            return;
        }

        int cleanerId = (int) cleanersModel.getValueAt(selectedRow, 0);
        String currentName = (String) cleanersModel.getValueAt(selectedRow, 1);
        String currentPhone = (String) cleanersModel.getValueAt(selectedRow, 2);
        String currentEmail = (String) cleanersModel.getValueAt(selectedRow, 3);
        String currentStatus = (String) cleanersModel.getValueAt(selectedRow, 4);
        String currentShift = (String) cleanersModel.getValueAt(selectedRow, 5);

        JDialog dialog = new JDialog(this, "Редактировать Уборщика", true);
        dialog.setSize(400, 400);
        dialog.setLocationRelativeTo(this);
        dialog.setLayout(new GridBagLayout());

        GridBagConstraints gbc = new GridBagConstraints();
        gbc.insets = new Insets(5,5,5,5);
        gbc.fill = GridBagConstraints.HORIZONTAL;

        // Поля ввода
        JLabel nameLabel = new JLabel("Полное имя:");
        JTextField nameField = new JTextField(currentName, 20);
        JLabel phoneLabel = new JLabel("Телефон:");
        JTextField phoneField = new JTextField(currentPhone, 20);
        JLabel emailLabel = new JLabel("Email:");
        JTextField emailField = new JTextField(currentEmail, 20);
        JLabel statusLabel = new JLabel("Статус:");
        JComboBox<String> statusComboBox = new JComboBox<>(new String[]{"Свободен", "Занят"});
        statusComboBox.setSelectedItem(currentStatus);
        JLabel shiftLabel = new JLabel("Смена:");
        JComboBox<String> shiftComboBox = new JComboBox<>();

        // Загрузка смен из базы
        try {
            ConnectMySQL connection = new ConnectMySQL();
            Connection conn = connection.getConnection();
            String shiftQuery = "SELECT shift_id, shift_name FROM Shifts";
            Statement stmt = conn.createStatement();
            ResultSet rs = stmt.executeQuery(shiftQuery);
            while (rs.next()) {
                shiftComboBox.addItem(rs.getString("shift_name"));
            }
            shiftComboBox.setSelectedItem(currentShift);
            conn.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

        // Кнопки
        JButton saveButton = new JButton("Сохранить");
        JButton cancelButton = new JButton("Отмена");

        // Размещение компонентов
        gbc.gridx = 0;
        gbc.gridy = 0;
        dialog.add(nameLabel, gbc);
        gbc.gridx = 1;
        dialog.add(nameField, gbc);

        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(phoneLabel, gbc);
        gbc.gridx = 1;
        dialog.add(phoneField, gbc);

        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(emailLabel, gbc);
        gbc.gridx = 1;
        dialog.add(emailField, gbc);

        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(statusLabel, gbc);
        gbc.gridx = 1;
        dialog.add(statusComboBox, gbc);

        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(shiftLabel, gbc);
        gbc.gridx = 1;
        dialog.add(shiftComboBox, gbc);

        // Панель кнопок
        JPanel buttonPanel = new JPanel();
        buttonPanel.add(saveButton);
        buttonPanel.add(cancelButton);
        gbc.gridx = 0;
        gbc.gridy++;
        gbc.gridwidth = 2;
        dialog.add(buttonPanel, gbc);

        // Обработчики кнопок
        saveButton.addActionListener(e -> {
            String fullName = nameField.getText().trim();
            String phone = phoneField.getText().trim();
            String email = emailField.getText().trim();
            String status = (String) statusComboBox.getSelectedItem();
            String shiftName = (String) shiftComboBox.getSelectedItem();

            if (fullName.isEmpty() || phone.isEmpty() || email.isEmpty() || shiftName == null) {
                JOptionPane.showMessageDialog(dialog, "Пожалуйста, заполните все обязательные поля.", "Ошибка", JOptionPane.ERROR_MESSAGE);
                return;
            }

            try {
                int shiftId = getShiftIdByName(shiftName);
                if (shiftId == -1) {
                    JOptionPane.showMessageDialog(dialog, "Выбранная смена не существует.", "Ошибка", JOptionPane.ERROR_MESSAGE);
                    return;
                }

                ConnectMySQL connection = new ConnectMySQL();
                Connection conn = connection.getConnection();

                String query = "UPDATE Cleaners SET full_name = ?, phone_number = ?, email = ?, status = ?, shift_id = ?, updated_at = NOW() WHERE cleaner_id = ?";
                PreparedStatement pstmt = conn.prepareStatement(query);
                pstmt.setString(1, fullName);
                pstmt.setString(2, phone);
                pstmt.setString(3, email);
                pstmt.setString(4, status);
                pstmt.setInt(5, shiftId);
                pstmt.setInt(6, cleanerId);

                pstmt.executeUpdate();
                conn.close();

                JOptionPane.showMessageDialog(dialog, "Уборщик обновлен успешно.");
                dialog.dispose();
                loadCleaners();
            } catch (SQLIntegrityConstraintViolationException ex) {
                JOptionPane.showMessageDialog(dialog, "Телефон или email уже существуют!", "Ошибка", JOptionPane.ERROR_MESSAGE);
            } catch (Exception ex) {
                ex.printStackTrace();
                JOptionPane.showMessageDialog(dialog, "Ошибка подключения к базе данных.", "Ошибка", JOptionPane.ERROR_MESSAGE);
            }
        });

        cancelButton.addActionListener(e -> dialog.dispose());

        dialog.setVisible(true);
    }

    // Удаление выбранного уборщика
    private void deleteSelectedCleaner() {
        int selectedRow = cleanersTable.getSelectedRow();
        if (selectedRow == -1) {
            JOptionPane.showMessageDialog(this, "Пожалуйста, выберите уборщика для удаления.", "Информация", JOptionPane.INFORMATION_MESSAGE);
            return;
        }

        int cleanerId = (int) cleanersModel.getValueAt(selectedRow, 0);
        String cleanerName = (String) cleanersModel.getValueAt(selectedRow, 1);

        int confirm = JOptionPane.showConfirmDialog(this, "Вы уверены, что хотите удалить уборщика \"" + cleanerName + "\"?", "Подтверждение", JOptionPane.YES_NO_OPTION);
        if (confirm != JOptionPane.YES_OPTION) {
            return;
        }

        try {
            ConnectMySQL connection = new ConnectMySQL();
            Connection conn = connection.getConnection();

            String query = "DELETE FROM Cleaners WHERE cleaner_id = ?";
            PreparedStatement pstmt = conn.prepareStatement(query);
            pstmt.setInt(1, cleanerId);
            pstmt.executeUpdate();
            conn.close();

            JOptionPane.showMessageDialog(this, "Уборщик удален успешно.");
            loadCleaners();
        } catch (Exception e) {
            e.printStackTrace();
            JOptionPane.showMessageDialog(this, "Ошибка при удалении уборщика.", "Ошибка", JOptionPane.ERROR_MESSAGE);
        }
    }

    // Инициализация вкладки "Номера"
    private void initRoomsTab() {
        JPanel panel = new JPanel(new BorderLayout());

        // Верхняя панель с кнопками
        JPanel topPanel = new JPanel();
        addRoomButton = new JButton("Добавить");
        editRoomButton = new JButton("Редактировать");
        deleteRoomButton = new JButton("Удалить");

        topPanel.add(addRoomButton);
        topPanel.add(editRoomButton);
        topPanel.add(deleteRoomButton);

        panel.add(topPanel, BorderLayout.NORTH);

        // Таблица номеров
        roomsModel = new DefaultTableModel();
        roomsTable = new JTable(roomsModel);
        roomsModel.setColumnIdentifiers(new String[]{
                "ID", "Номер", "Статус", "Цена", "Тип кровати", "Тип номера", "Дата создания", "Дата обновления"
        });

        loadRooms();

        JScrollPane scrollPane = new JScrollPane(roomsTable);
        panel.add(scrollPane, BorderLayout.CENTER);

        // Обработчики кнопок
        addRoomButton.addActionListener(e -> openAddRoomDialog());
        editRoomButton.addActionListener(e -> openEditRoomDialog());
        deleteRoomButton.addActionListener(e -> deleteSelectedRoom());

        tabbedPane.addTab("Номера", panel);
    }

    // Загрузка данных номеров из базы
    private void loadRooms() {
        roomsModel.setRowCount(0);
        try {
            ConnectMySQL connection = new ConnectMySQL();
            Connection conn = connection.getConnection();
            String query = "SELECT room_id, room_number, status, price, bed_type, room_type, created_at, updated_at FROM Rooms";
            Statement stmt = conn.createStatement();
            ResultSet rs = stmt.executeQuery(query);

            while (rs.next()) {
                Vector<Object> row = new Vector<>();
                row.add(rs.getInt("room_id"));
                row.add(rs.getInt("room_number"));
                row.add(rs.getString("status"));
                row.add(rs.getDouble("price"));
                row.add(rs.getString("bed_type"));
                row.add(rs.getString("room_type"));
                row.add(rs.getTimestamp("created_at"));
                row.add(rs.getTimestamp("updated_at"));
                roomsModel.addRow(row);
            }
            conn.close();
        } catch (Exception e) {
            e.printStackTrace();
            JOptionPane.showMessageDialog(this, "Ошибка загрузки номеров.", "Ошибка", JOptionPane.ERROR_MESSAGE);
        }
    }

    // Диалог для добавления нового номера
    private void openAddRoomDialog() {
        JDialog dialog = new JDialog(this, "Добавить Номер", true);
        dialog.setSize(400, 500);
        dialog.setLocationRelativeTo(this);
        dialog.setLayout(new GridBagLayout());

        GridBagConstraints gbc = new GridBagConstraints();
        gbc.insets = new Insets(5,5,5,5);
        gbc.fill = GridBagConstraints.HORIZONTAL;

        // Поля ввода
        JLabel roomNumberLabel = new JLabel("Номер:");
        JTextField roomNumberField = new JTextField(20);
        JLabel statusLabel = new JLabel("Статус:");
        JComboBox<String> statusComboBox = new JComboBox<>(new String[]{"Доступен", "Недоступен"});
        JLabel priceLabel = new JLabel("Цена:");
        JTextField priceField = new JTextField(20);
        JLabel bedTypeLabel = new JLabel("Тип кровати:");
        JComboBox<String> bedTypeComboBox = new JComboBox<>(new String[]{"Одноместный", "Двухместный", "Трехместный", "Четырехместный"});
        JLabel roomTypeLabel = new JLabel("Тип номера:");
        JComboBox<String> roomTypeComboBox = new JComboBox<>(new String[]{"Стандарт", "Люкс", "Делюкс"});

        // Кнопки
        JButton saveButton = new JButton("Сохранить");
        JButton cancelButton = new JButton("Отмена");

        // Размещение компонентов
        gbc.gridx = 0;
        gbc.gridy = 0;
        dialog.add(roomNumberLabel, gbc);
        gbc.gridx = 1;
        dialog.add(roomNumberField, gbc);

        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(statusLabel, gbc);
        gbc.gridx = 1;
        dialog.add(statusComboBox, gbc);

        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(priceLabel, gbc);
        gbc.gridx = 1;
        dialog.add(priceField, gbc);

        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(bedTypeLabel, gbc);
        gbc.gridx = 1;
        dialog.add(bedTypeComboBox, gbc);

        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(roomTypeLabel, gbc);
        gbc.gridx = 1;
        dialog.add(roomTypeComboBox, gbc);

        // Панель кнопок
        JPanel buttonPanel = new JPanel();
        buttonPanel.add(saveButton);
        buttonPanel.add(cancelButton);
        gbc.gridx = 0;
        gbc.gridy++;
        gbc.gridwidth = 2;
        dialog.add(buttonPanel, gbc);

        // Обработчики кнопок
        saveButton.addActionListener(e -> {
            String roomNumberStr = roomNumberField.getText().trim();
            String status = (String) statusComboBox.getSelectedItem();
            String priceStr = priceField.getText().trim();
            String bedType = (String) bedTypeComboBox.getSelectedItem();
            String roomType = (String) roomTypeComboBox.getSelectedItem();

            if (roomNumberStr.isEmpty() || priceStr.isEmpty()) {
                JOptionPane.showMessageDialog(dialog, "Пожалуйста, заполните все обязательные поля.", "Ошибка", JOptionPane.ERROR_MESSAGE);
                return;
            }

            try {
                int roomNumber = Integer.parseInt(roomNumberStr);
                double price = Double.parseDouble(priceStr);

                ConnectMySQL connection = new ConnectMySQL();
                Connection conn = connection.getConnection();

                String query = "INSERT INTO Rooms (room_number, status, price, bed_type, room_type, created_at, updated_at) "
                        + "VALUES (?, ?, ?, ?, ?, NOW(), NOW())";
                PreparedStatement pstmt = conn.prepareStatement(query);
                pstmt.setInt(1, roomNumber);
                pstmt.setString(2, status);
                pstmt.setDouble(3, price);
                pstmt.setString(4, bedType);
                pstmt.setString(5, roomType);

                pstmt.executeUpdate();
                conn.close();

                JOptionPane.showMessageDialog(dialog, "Номер добавлен успешно.");
                dialog.dispose();
                loadRooms();
            } catch (NumberFormatException ex) {
                JOptionPane.showMessageDialog(dialog, "Пожалуйста, введите корректные числовые значения для номера и цены.", "Ошибка", JOptionPane.ERROR_MESSAGE);
            } catch (SQLIntegrityConstraintViolationException ex) {
                JOptionPane.showMessageDialog(dialog, "Номер комнаты уже существует!", "Ошибка", JOptionPane.ERROR_MESSAGE);
            } catch (Exception ex) {
                ex.printStackTrace();
                JOptionPane.showMessageDialog(dialog, "Ошибка подключения к базе данных.", "Ошибка", JOptionPane.ERROR_MESSAGE);
            }
        });

        cancelButton.addActionListener(e -> dialog.dispose());

        dialog.setVisible(true);
    }

    // Диалог для редактирования выбранного номера
    private void openEditRoomDialog() {
        int selectedRow = roomsTable.getSelectedRow();
        if (selectedRow == -1) {
            JOptionPane.showMessageDialog(this, "Пожалуйста, выберите номер для редактирования.", "Информация", JOptionPane.INFORMATION_MESSAGE);
            return;
        }

        int roomId = (int) roomsModel.getValueAt(selectedRow, 0);
        int roomNumber = (int) roomsModel.getValueAt(selectedRow, 1);
        String currentStatus = (String) roomsModel.getValueAt(selectedRow, 2);
        double price = (double) roomsModel.getValueAt(selectedRow, 3);
        String bedType = (String) roomsModel.getValueAt(selectedRow, 4);
        String roomType = (String) roomsModel.getValueAt(selectedRow, 5);

        JDialog dialog = new JDialog(this, "Редактировать Номер", true);
        dialog.setSize(400, 500);
        dialog.setLocationRelativeTo(this);
        dialog.setLayout(new GridBagLayout());

        GridBagConstraints gbc = new GridBagConstraints();
        gbc.insets = new Insets(5,5,5,5);
        gbc.fill = GridBagConstraints.HORIZONTAL;

        // Поля ввода
        JLabel roomNumberLabel = new JLabel("Номер:");
        JTextField roomNumberField = new JTextField(String.valueOf(roomNumber), 20);
        JLabel statusLabel = new JLabel("Статус:");
        JComboBox<String> statusComboBox = new JComboBox<>(new String[]{"Доступен", "Недоступен"});
        statusComboBox.setSelectedItem(currentStatus);
        JLabel priceLabel = new JLabel("Цена:");
        JTextField priceField = new JTextField(String.valueOf(price), 20);
        JLabel bedTypeLabel = new JLabel("Тип кровати:");
        JComboBox<String> bedTypeComboBox = new JComboBox<>(new String[]{"Одноместный", "Двухместный", "Трехместный", "Четырехместный"});
        bedTypeComboBox.setSelectedItem(bedType);
        JLabel roomTypeLabel = new JLabel("Тип номера:");
        JComboBox<String> roomTypeComboBox = new JComboBox<>(new String[]{"Стандарт", "Люкс", "Делюкс"});
        roomTypeComboBox.setSelectedItem(roomType);

        // Кнопки
        JButton saveButton = new JButton("Сохранить");
        JButton cancelButton = new JButton("Отмена");

        // Размещение компонентов
        gbc.gridx = 0;
        gbc.gridy = 0;
        dialog.add(roomNumberLabel, gbc);
        gbc.gridx = 1;
        dialog.add(roomNumberField, gbc);

        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(statusLabel, gbc);
        gbc.gridx = 1;
        dialog.add(statusComboBox, gbc);

        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(priceLabel, gbc);
        gbc.gridx = 1;
        dialog.add(priceField, gbc);

        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(bedTypeLabel, gbc);
        gbc.gridx = 1;
        dialog.add(bedTypeComboBox, gbc);

        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(roomTypeLabel, gbc);
        gbc.gridx = 1;
        dialog.add(roomTypeComboBox, gbc);

        // Панель кнопок
        JPanel buttonPanel = new JPanel();
        buttonPanel.add(saveButton);
        buttonPanel.add(cancelButton);
        gbc.gridx = 0;
        gbc.gridy++;
        gbc.gridwidth = 2;
        dialog.add(buttonPanel, gbc);

        // Обработчики кнопок
        saveButton.addActionListener(e -> {
            String roomNumberStr = roomNumberField.getText().trim();
            String status = (String) statusComboBox.getSelectedItem();
            String priceStr = priceField.getText().trim();
            String bedTypeNew = (String) bedTypeComboBox.getSelectedItem();
            String roomTypeNew = (String) roomTypeComboBox.getSelectedItem();

            if (roomNumberStr.isEmpty() || priceStr.isEmpty()) {
                JOptionPane.showMessageDialog(dialog, "Пожалуйста, заполните все обязательные поля.", "Ошибка", JOptionPane.ERROR_MESSAGE);
                return;
            }

            try {
                int roomNumberParsed = Integer.parseInt(roomNumberStr);
                double priceParsed = Double.parseDouble(priceStr);

                ConnectMySQL connection = new ConnectMySQL();
                Connection conn = connection.getConnection();

                String query = "UPDATE Rooms SET room_number = ?, status = ?, price = ?, bed_type = ?, room_type = ?, updated_at = NOW() WHERE room_id = ?";
                PreparedStatement pstmt = conn.prepareStatement(query);
                pstmt.setInt(1, roomNumberParsed);
                pstmt.setString(2, status);
                pstmt.setDouble(3, priceParsed);
                pstmt.setString(4, bedTypeNew);
                pstmt.setString(5, roomTypeNew);
                pstmt.setInt(6, roomId);

                pstmt.executeUpdate();
                conn.close();

                JOptionPane.showMessageDialog(dialog, "Номер обновлён успешно.");
                dialog.dispose();
                loadRooms();
            } catch (NumberFormatException ex) {
                JOptionPane.showMessageDialog(dialog, "Пожалуйста, введите корректные числовые значения для номера и цены.", "Ошибка", JOptionPane.ERROR_MESSAGE);
            } catch (SQLIntegrityConstraintViolationException ex) {
                JOptionPane.showMessageDialog(dialog, "Номер комнаты уже существует!", "Ошибка", JOptionPane.ERROR_MESSAGE);
            } catch (Exception ex) {
                ex.printStackTrace();
                JOptionPane.showMessageDialog(dialog, "Ошибка подключения к базе данных.", "Ошибка", JOptionPane.ERROR_MESSAGE);
            }
        });

        cancelButton.addActionListener(e -> dialog.dispose());

        dialog.setVisible(true);
    }

    // Удаление выбранного номера
    private void deleteSelectedRoom() {
        int selectedRow = roomsTable.getSelectedRow();
        if (selectedRow == -1) {
            JOptionPane.showMessageDialog(this, "Пожалуйста, выберите номер для удаления.", "Информация", JOptionPane.INFORMATION_MESSAGE);
            return;
        }

        int roomId = (int) roomsModel.getValueAt(selectedRow, 0);
        int roomNumber = (int) roomsModel.getValueAt(selectedRow, 1);

        int confirm = JOptionPane.showConfirmDialog(this, "Вы уверены, что хотите удалить номер \"" + roomNumber + "\"?", "Подтверждение", JOptionPane.YES_NO_OPTION);
        if (confirm != JOptionPane.YES_OPTION) {
            return;
        }

        try {
            ConnectMySQL connection = new ConnectMySQL();
            Connection conn = connection.getConnection();

            String query = "DELETE FROM Rooms WHERE room_id = ?";
            PreparedStatement pstmt = conn.prepareStatement(query);
            pstmt.setInt(1, roomId);
            pstmt.executeUpdate();
            conn.close();

            JOptionPane.showMessageDialog(this, "Номер удалён успешно.");
            loadRooms();
        } catch (Exception e) {
            e.printStackTrace();
            JOptionPane.showMessageDialog(this, "Ошибка при удалении номера.", "Ошибка", JOptionPane.ERROR_MESSAGE);
        }
    }

    // Инициализация вкладки "Доходы"
    private void initIncomeTab() {
        JPanel panel = new JPanel(new BorderLayout());

        // Верхняя панель с общей суммой дохода
        JPanel topPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
        totalIncomeLabel = new JLabel("Общий доход: ");
        topPanel.add(totalIncomeLabel);

        panel.add(topPanel, BorderLayout.NORTH);

        // Таблица платежей
        paymentsModel = new DefaultTableModel();
        paymentsTable = new JTable(paymentsModel);
        paymentsModel.setColumnIdentifiers(new String[]{
                "ID Платежа", "ID Бронирования", "Сумма", "Дата платежа", "Способ оплаты", "Дата создания"
        });

        loadPayments();

        JScrollPane scrollPane = new JScrollPane(paymentsTable);
        panel.add(scrollPane, BorderLayout.CENTER);

        tabbedPane.addTab("Доходы", panel);
    }

    // Загрузка данных платежей и расчет общего дохода
    private void loadPayments() {
        paymentsModel.setRowCount(0);
        double totalIncome = 0.0;
        try {
            ConnectMySQL connection = new ConnectMySQL();
            Connection conn = connection.getConnection();
            String query = "SELECT payment_id, reservation_id, amount, payment_date, payment_method, created_at FROM Payments";
            Statement stmt = conn.createStatement();
            ResultSet rs = stmt.executeQuery(query);

            while (rs.next()) {
                Vector<Object> row = new Vector<>();
                row.add(rs.getInt("payment_id"));
                row.add(rs.getInt("reservation_id"));
                row.add(rs.getDouble("amount"));
                row.add(rs.getDate("payment_date"));
                row.add(rs.getString("payment_method"));
                row.add(rs.getTimestamp("created_at"));
                paymentsModel.addRow(row);
                totalIncome += rs.getDouble("amount");
            }
            conn.close();

            totalIncomeLabel.setText(String.format("Общий доход: %.2f", totalIncome));
        } catch (Exception e) {
            e.printStackTrace();
            JOptionPane.showMessageDialog(this, "Ошибка загрузки платежей.", "Ошибка", JOptionPane.ERROR_MESSAGE);
        }
    }

    // Хеширование пароля (тот же метод, что и в других классах)
    private String hashPassword(String password) {
        try {
            java.security.MessageDigest md = java.security.MessageDigest.getInstance("SHA-256");
            byte[] hashBytes = md.digest(password.getBytes());

            StringBuilder sb = new StringBuilder();
            for(byte b : hashBytes){
                sb.append(String.format("%02x", b));
            }

            return sb.toString();
        } catch (java.security.NoSuchAlgorithmException e) {
            e.printStackTrace();
            return null;
        }
    }

    // Основной метод для запуска панели администратора
    public static void main(String[] args) {
        // Установка системного вида для современного оформления
        try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } catch (Exception ignored) {}

        // Передача реального adminId при запуске. Для тестирования используем adminId = 1
        SwingUtilities.invokeLater(() -> new DashboardAdmin(1));
    }
}















package h;

import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import java.awt.*;
import java.awt.event.*;
import java.sql.*;
import java.util.Vector;

public class DashboardReceptionist extends JFrame {

    private int receptionistId;
    private JTabbedPane tabbedPane;

    // Компоненты для вкладки Актуальные Бронирования
    private JTable reservationsTable;
    private DefaultTableModel reservationsModel;
    private JButton checkInButton, checkOutButton, refreshReservationsButton;

    // Компоненты для вкладки Клиенты
    private JTable customersTable;
    private DefaultTableModel customersModel;
    private JButton addCustomerButton, editCustomerButton, deleteCustomerButton, refreshCustomersButton;

    // Компоненты для вкладки Номера
    private JTable roomsTable;
    private DefaultTableModel roomsModel;
    private JButton refreshRoomsButton;

    // Компоненты для вкладки Платежи
    private JTable paymentsTable;
    private DefaultTableModel paymentsModel;
    private JButton refreshPaymentsButton;

    // Компоненты для вкладки Уборка
    private JTable cleaningTable;
    private DefaultTableModel cleaningModel;
    private JButton assignCleanerButton, markInProgressButton, markCompletedButton, refreshCleaningButton;

    public DashboardReceptionist(int receptionistId) {
        this.receptionistId = receptionistId;
        setTitle("Панель Ресепшиониста");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(1200, 800);
        setLocationRelativeTo(null);

        tabbedPane = new JTabbedPane();

        // Инициализация вкладок
        initCurrentReservationsTab();
        initCustomersTab();
        initRoomsTab();
        initPaymentsTab();
        initCleaningTab(); // Новая вкладка "Уборка"

        add(tabbedPane);

        setVisible(true);
    }

    // Вкладка "Актуальные Бронирования"
    private void initCurrentReservationsTab() {
        JPanel panel = new JPanel(new BorderLayout());

        // Верхняя панель с кнопками
        JPanel topPanel = new JPanel();
        checkInButton = new JButton("Заселить Клиента");
        checkOutButton = new JButton("Выселить Клиента");
        refreshReservationsButton = new JButton("Обновить");

        topPanel.add(checkInButton);
        topPanel.add(checkOutButton);
        topPanel.add(refreshReservationsButton);

        panel.add(topPanel, BorderLayout.NORTH);

        // Таблица бронирований
        reservationsModel = new DefaultTableModel();
        reservationsTable = new JTable(reservationsModel);
        reservationsModel.setColumnIdentifiers(new String[]{
                "ID Бронирования", "Клиент", "Номер", "Дата заезда", "Дата выезда", "Статус", "Сумма", "Депозит", "Дата создания", "Дата обновления"
        });

        loadReservations();

        JScrollPane scrollPane = new JScrollPane(reservationsTable);
        panel.add(scrollPane, BorderLayout.CENTER);

        // Обработчики кнопок
        checkInButton.addActionListener(e -> checkInSelectedReservation());
        checkOutButton.addActionListener(e -> checkOutSelectedReservation());
        refreshReservationsButton.addActionListener(e -> loadReservations());

        tabbedPane.addTab("Актуальные Бронирования", panel);
    }

    // Загрузка бронирований из базы данных
    private void loadReservations() {
        reservationsModel.setRowCount(0);
        try {
            ConnectMySQL connection = new ConnectMySQL();
            Connection conn = connection.getConnection();
            String query = "SELECT r.reservation_id, c.full_name AS customer, ro.room_number, r.check_in, r.check_out, r.status, " +
                    "r.total_amount, r.deposit, r.created_at, r.updated_at " +
                    "FROM Reservations r " +
                    "JOIN Customers c ON r.customer_id = c.customer_id " +
                    "JOIN Rooms ro ON r.room_id = ro.room_id " +
                    "WHERE r.status IN ('Забронирован', 'Заселён')"; // Отображаем только актуальные бронирования
            Statement stmt = conn.createStatement();
            ResultSet rs = stmt.executeQuery(query);

            while (rs.next()) {
                Vector<Object> row = new Vector<>();
                row.add(rs.getInt("reservation_id"));
                row.add(rs.getString("customer"));
                row.add(rs.getInt("room_number"));
                row.add(rs.getDate("check_in"));
                row.add(rs.getDate("check_out"));
                row.add(rs.getString("status"));
                row.add(rs.getDouble("total_amount"));
                row.add(rs.getDouble("deposit"));
                row.add(rs.getTimestamp("created_at"));
                row.add(rs.getTimestamp("updated_at"));
                reservationsModel.addRow(row);
            }
            conn.close();
        } catch (Exception e) {
            e.printStackTrace();
            JOptionPane.showMessageDialog(this, "Ошибка загрузки бронирований.", "Ошибка", JOptionPane.ERROR_MESSAGE);
        }
    }

    // Заселение выбранного бронирования
    private void checkInSelectedReservation() {
        int selectedRow = reservationsTable.getSelectedRow();
        if (selectedRow == -1) {
            JOptionPane.showMessageDialog(this, "Пожалуйста, выберите бронирование для заселения.", "Информация", JOptionPane.INFORMATION_MESSAGE);
            return;
        }

        String status = (String) reservationsModel.getValueAt(selectedRow, 5);
        if (status.equals("Заселён")) {
            JOptionPane.showMessageDialog(this, "Клиент уже заселен.", "Информация", JOptionPane.INFORMATION_MESSAGE);
            return;
        }

        if (!status.equals("Забронирован")) {
            JOptionPane.showMessageDialog(this, "Невозможно заселить клиента с текущим статусом.", "Ошибка", JOptionPane.ERROR_MESSAGE);
            return;
        }

        int reservationId = (int) reservationsModel.getValueAt(selectedRow, 0);
        int roomNumber = (int) reservationsModel.getValueAt(selectedRow, 2);

        int confirm = JOptionPane.showConfirmDialog(this, "Вы уверены, что хотите заселить этого клиента?", "Подтверждение", JOptionPane.YES_NO_OPTION);
        if (confirm != JOptionPane.YES_OPTION) {
            return;
        }

        try {
            ConnectMySQL connection = new ConnectMySQL();
            Connection conn = connection.getConnection();

            // Обновление статуса бронирования
            String updateReservation = "UPDATE Reservations SET status = 'Заселён', updated_at = NOW() WHERE reservation_id = ?";
            PreparedStatement pstmt1 = conn.prepareStatement(updateReservation);
            pstmt1.setInt(1, reservationId);
            pstmt1.executeUpdate();

            // Обновление статуса номера
            String updateRoom = "UPDATE Rooms SET status = 'Недоступен' WHERE room_number = ?";
            PreparedStatement pstmt2 = conn.prepareStatement(updateRoom);
            pstmt2.setInt(1, roomNumber);
            pstmt2.executeUpdate();

            conn.close();

            JOptionPane.showMessageDialog(this, "Клиент успешно заселен.");
            loadReservations();
            loadRooms();

        } catch (Exception e) {
            e.printStackTrace();
            JOptionPane.showMessageDialog(this, "Ошибка при заселении клиента.", "Ошибка", JOptionPane.ERROR_MESSAGE);
        }
    }

    // Выселение выбранного бронирования
    private void checkOutSelectedReservation() {
        int selectedRow = reservationsTable.getSelectedRow();
        if (selectedRow == -1) {
            JOptionPane.showMessageDialog(this, "Пожалуйста, выберите бронирование для выселения.", "Информация", JOptionPane.INFORMATION_MESSAGE);
            return;
        }

        String status = (String) reservationsModel.getValueAt(selectedRow, 5);
        if (!status.equals("Заселён")) {
            JOptionPane.showMessageDialog(this, "Клиент не заселен или уже выселен.", "Ошибка", JOptionPane.ERROR_MESSAGE);
            return;
        }

        int reservationId = (int) reservationsModel.getValueAt(selectedRow, 0);
        int roomNumber = (int) reservationsModel.getValueAt(selectedRow, 2);

        int confirm = JOptionPane.showConfirmDialog(this, "Вы уверены, что хотите выселить этого клиента?", "Подтверждение", JOptionPane.YES_NO_OPTION);
        if (confirm != JOptionPane.YES_OPTION) {
            return;
        }

        try {
            ConnectMySQL connection = new ConnectMySQL();
            Connection conn = connection.getConnection();

            // Обновление статуса бронирования
            String updateReservation = "UPDATE Reservations SET status = 'Выселен', updated_at = NOW() WHERE reservation_id = ?";
            PreparedStatement pstmt1 = conn.prepareStatement(updateReservation);
            pstmt1.setInt(1, reservationId);
            pstmt1.executeUpdate();

            // Обновление статуса номера
            String updateRoom = "UPDATE Rooms SET status = 'Доступен' WHERE room_number = ?";
            PreparedStatement pstmt2 = conn.prepareStatement(updateRoom);
            pstmt2.setInt(1, roomNumber);
            pstmt2.executeUpdate();

            // Вставка записи о платеже (если необходимо)
            // Здесь вы можете добавить логику для записи платежа при выселении клиента

            conn.close();

            JOptionPane.showMessageDialog(this, "Клиент успешно выселен.");
            loadReservations();
            loadRooms();

        } catch (Exception e) {
            e.printStackTrace();
            JOptionPane.showMessageDialog(this, "Ошибка при выселении клиента.", "Ошибка", JOptionPane.ERROR_MESSAGE);
        }
    }

    // Вкладка "Клиенты"
    private void initCustomersTab() {
        JPanel panel = new JPanel(new BorderLayout());

        // Верхняя панель с кнопками
        JPanel topPanel = new JPanel();
        addCustomerButton = new JButton("Добавить Клиента");
        editCustomerButton = new JButton("Редактировать Клиента");
        deleteCustomerButton = new JButton("Удалить Клиента");
        refreshCustomersButton = new JButton("Обновить");

        topPanel.add(addCustomerButton);
        topPanel.add(editCustomerButton);
        topPanel.add(deleteCustomerButton);
        topPanel.add(refreshCustomersButton);

        panel.add(topPanel, BorderLayout.NORTH);

        // Таблица клиентов
        customersModel = new DefaultTableModel();
        customersTable = new JTable(customersModel);
        customersModel.setColumnIdentifiers(new String[]{
                "ID Клиента", "Полное имя", "Телефон", "Email", "Пол", "Страна", "Адрес", "Дата создания", "Дата обновления"
        });

        loadCustomers();

        JScrollPane scrollPane = new JScrollPane(customersTable);
        panel.add(scrollPane, BorderLayout.CENTER);

        // Обработчики кнопок
        addCustomerButton.addActionListener(e -> openAddCustomerDialog());
        editCustomerButton.addActionListener(e -> openEditCustomerDialog());
        deleteCustomerButton.addActionListener(e -> deleteSelectedCustomer());
        refreshCustomersButton.addActionListener(e -> loadCustomers());

        tabbedPane.addTab("Клиенты", panel);
    }

    // Загрузка клиентов из базы данных
    private void loadCustomers() {
        customersModel.setRowCount(0);
        try {
            ConnectMySQL connection = new ConnectMySQL();
            Connection conn = connection.getConnection();
            String query = "SELECT customer_id, full_name, phone, email, gender, country, address, created_at, updated_at FROM Customers";
            Statement stmt = conn.createStatement();
            ResultSet rs = stmt.executeQuery(query);

            while (rs.next()) {
                Vector<Object> row = new Vector<>();
                row.add(rs.getInt("customer_id"));
                row.add(rs.getString("full_name"));
                row.add(rs.getString("phone"));
                row.add(rs.getString("email"));
                row.add(rs.getString("gender"));
                row.add(rs.getString("country"));
                row.add(rs.getString("address"));
                row.add(rs.getTimestamp("created_at"));
                row.add(rs.getTimestamp("updated_at"));
                customersModel.addRow(row);
            }
            conn.close();
        } catch (Exception e) {
            e.printStackTrace();
            JOptionPane.showMessageDialog(this, "Ошибка загрузки клиентов.", "Ошибка", JOptionPane.ERROR_MESSAGE);
        }
    }

    // Диалоговое окно для добавления нового клиента
    private void openAddCustomerDialog() {
        JDialog dialog = new JDialog(this, "Добавить Клиента", true);
        dialog.setSize(500, 600);
        dialog.setLocationRelativeTo(this);
        dialog.setLayout(new GridBagLayout());

        GridBagConstraints gbc = new GridBagConstraints();
        gbc.insets = new Insets(10,10,10,10);
        gbc.fill = GridBagConstraints.HORIZONTAL;

        // Полное имя
        JLabel nameLabel = new JLabel("Полное имя:");
        gbc.gridx = 0;
        gbc.gridy = 0;
        dialog.add(nameLabel, gbc);

        JTextField nameField = new JTextField(20);
        gbc.gridx = 1;
        dialog.add(nameField, gbc);

        // Телефон
        JLabel phoneLabel = new JLabel("Телефон:");
        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(phoneLabel, gbc);

        JTextField phoneField = new JTextField(20);
        gbc.gridx = 1;
        dialog.add(phoneField, gbc);

        // Email
        JLabel emailLabel = new JLabel("Email:");
        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(emailLabel, gbc);

        JTextField emailField = new JTextField(20);
        gbc.gridx = 1;
        dialog.add(emailField, gbc);

        // Пол
        JLabel genderLabel = new JLabel("Пол:");
        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(genderLabel, gbc);

        JComboBox<String> genderComboBox = new JComboBox<>(new String[]{"Мужской", "Женский"});
        gbc.gridx = 1;
        dialog.add(genderComboBox, gbc);

        // Страна
        JLabel countryLabel = new JLabel("Страна:");
        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(countryLabel, gbc);

        JTextField countryField = new JTextField(20);
        gbc.gridx = 1;
        dialog.add(countryField, gbc);

        // Адрес
        JLabel addressLabel = new JLabel("Адрес:");
        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(addressLabel, gbc);

        JTextField addressField = new JTextField(20);
        gbc.gridx = 1;
        dialog.add(addressField, gbc);

        // Кнопки
        JButton saveButton = new JButton("Сохранить");
        JButton cancelButton = new JButton("Отмена");

        JPanel buttonPanel = new JPanel();
        buttonPanel.add(saveButton);
        buttonPanel.add(cancelButton);

        gbc.gridx = 0;
        gbc.gridy++;
        gbc.gridwidth = 2;
        dialog.add(buttonPanel, gbc);

        // Обработчики кнопок
        saveButton.addActionListener(e -> {
            String fullName = nameField.getText().trim();
            String phone = phoneField.getText().trim();
            String email = emailField.getText().trim();
            String gender = (String) genderComboBox.getSelectedItem();
            String country = countryField.getText().trim();
            String address = addressField.getText().trim();

            // Валидация
            if (fullName.isEmpty() || phone.isEmpty() || gender.isEmpty()) {
                JOptionPane.showMessageDialog(dialog, "Пожалуйста, заполните все обязательные поля.", "Ошибка", JOptionPane.ERROR_MESSAGE);
                return;
            }

            try {
                ConnectMySQL connection = new ConnectMySQL();
                Connection conn = connection.getConnection();

                String query = "INSERT INTO Customers (full_name, phone, email, gender, country, address, receptionist_id, created_at, updated_at) " +
                        "VALUES (?, ?, ?, ?, ?, ?, ?, NOW(), NOW())";
                PreparedStatement pstmt = conn.prepareStatement(query);
                pstmt.setString(1, fullName);
                pstmt.setString(2, phone);
                pstmt.setString(3, email.isEmpty() ? null : email);
                pstmt.setString(4, gender);
                pstmt.setString(5, country.isEmpty() ? null : country);
                pstmt.setString(6, address.isEmpty() ? null : address);
                pstmt.setInt(7, receptionistId);

                pstmt.executeUpdate();
                conn.close();

                JOptionPane.showMessageDialog(dialog, "Клиент успешно добавлен.");
                dialog.dispose();
                loadCustomers();
            } catch (SQLIntegrityConstraintViolationException ex) {
                JOptionPane.showMessageDialog(dialog, "Такой телефон или email уже существуют!", "Ошибка", JOptionPane.ERROR_MESSAGE);
            } catch (Exception ex) {
                ex.printStackTrace();
                JOptionPane.showMessageDialog(dialog, "Ошибка при добавлении клиента.", "Ошибка", JOptionPane.ERROR_MESSAGE);
            }
        });

        cancelButton.addActionListener(e -> dialog.dispose());

        dialog.setVisible(true);
    }

    // Диалоговое окно для редактирования выбранного клиента
    private void openEditCustomerDialog() {
        int selectedRow = customersTable.getSelectedRow();
        if (selectedRow == -1) {
            JOptionPane.showMessageDialog(this, "Пожалуйста, выберите клиента для редактирования.", "Информация", JOptionPane.INFORMATION_MESSAGE);
            return;
        }

        int customerId = (int) customersModel.getValueAt(selectedRow, 0);
        String currentName = (String) customersModel.getValueAt(selectedRow, 1);
        String currentPhone = (String) customersModel.getValueAt(selectedRow, 2);
        String currentEmail = (String) customersModel.getValueAt(selectedRow, 3);
        String currentGender = (String) customersModel.getValueAt(selectedRow, 4);
        String currentCountry = (String) customersModel.getValueAt(selectedRow, 5);
        String currentAddress = (String) customersModel.getValueAt(selectedRow, 6);

        JDialog dialog = new JDialog(this, "Редактировать Клиента", true);
        dialog.setSize(500, 600);
        dialog.setLocationRelativeTo(this);
        dialog.setLayout(new GridBagLayout());

        GridBagConstraints gbc = new GridBagConstraints();
        gbc.insets = new Insets(10,10,10,10);
        gbc.fill = GridBagConstraints.HORIZONTAL;

        // Полное имя
        JLabel nameLabel = new JLabel("Полное имя:");
        gbc.gridx = 0;
        gbc.gridy = 0;
        dialog.add(nameLabel, gbc);

        JTextField nameField = new JTextField(currentName, 20);
        gbc.gridx = 1;
        dialog.add(nameField, gbc);

        // Телефон
        JLabel phoneLabel = new JLabel("Телефон:");
        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(phoneLabel, gbc);

        JTextField phoneField = new JTextField(currentPhone, 20);
        gbc.gridx = 1;
        dialog.add(phoneField, gbc);

        // Email
        JLabel emailLabel = new JLabel("Email:");
        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(emailLabel, gbc);

        JTextField emailField = new JTextField(currentEmail, 20);
        gbc.gridx = 1;
        dialog.add(emailField, gbc);

        // Пол
        JLabel genderLabel = new JLabel("Пол:");
        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(genderLabel, gbc);

        JComboBox<String> genderComboBox = new JComboBox<>(new String[]{"Мужской", "Женский"});
        genderComboBox.setSelectedItem(currentGender);
        gbc.gridx = 1;
        dialog.add(genderComboBox, gbc);

        // Страна
        JLabel countryLabel = new JLabel("Страна:");
        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(countryLabel, gbc);

        JTextField countryField = new JTextField(currentCountry, 20);
        gbc.gridx = 1;
        dialog.add(countryField, gbc);

        // Адрес
        JLabel addressLabel = new JLabel("Адрес:");
        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(addressLabel, gbc);

        JTextField addressField = new JTextField(currentAddress, 20);
        gbc.gridx = 1;
        dialog.add(addressField, gbc);

        // Кнопки
        JButton saveButton = new JButton("Сохранить");
        JButton cancelButton = new JButton("Отмена");

        JPanel buttonPanel = new JPanel();
        buttonPanel.add(saveButton);
        buttonPanel.add(cancelButton);

        gbc.gridx = 0;
        gbc.gridy++;
        gbc.gridwidth = 2;
        dialog.add(buttonPanel, gbc);

        // Обработчики кнопок
        saveButton.addActionListener(e -> {
            String fullName = nameField.getText().trim();
            String phone = phoneField.getText().trim();
            String email = emailField.getText().trim();
            String gender = (String) genderComboBox.getSelectedItem();
            String country = countryField.getText().trim();
            String address = addressField.getText().trim();

            // Валидация
            if (fullName.isEmpty() || phone.isEmpty() || gender.isEmpty()) {
                JOptionPane.showMessageDialog(dialog, "Пожалуйста, заполните все обязательные поля.", "Ошибка", JOptionPane.ERROR_MESSAGE);
                return;
            }

            try {
                ConnectMySQL connection = new ConnectMySQL();
                Connection conn = connection.getConnection();

                String query = "UPDATE Customers SET full_name = ?, phone = ?, email = ?, gender = ?, country = ?, address = ?, updated_at = NOW() WHERE customer_id = ?";
                PreparedStatement pstmt = conn.prepareStatement(query);
                pstmt.setString(1, fullName);
                pstmt.setString(2, phone);
                pstmt.setString(3, email.isEmpty() ? null : email);
                pstmt.setString(4, gender);
                pstmt.setString(5, country.isEmpty() ? null : country);
                pstmt.setString(6, address.isEmpty() ? null : address);
                pstmt.setInt(7, customerId);

                pstmt.executeUpdate();
                conn.close();

                JOptionPane.showMessageDialog(dialog, "Клиент успешно обновлен.");
                dialog.dispose();
                loadCustomers();
            } catch (SQLIntegrityConstraintViolationException ex) {
                JOptionPane.showMessageDialog(dialog, "Такой телефон или email уже существуют!", "Ошибка", JOptionPane.ERROR_MESSAGE);
            } catch (Exception ex) {
                ex.printStackTrace();
                JOptionPane.showMessageDialog(dialog, "Ошибка при обновлении клиента.", "Ошибка", JOptionPane.ERROR_MESSAGE);
            }
        });

        cancelButton.addActionListener(e -> dialog.dispose());

        dialog.setVisible(true);
    }

    // Удаление выбранного клиента
    private void deleteSelectedCustomer() {
        int selectedRow = customersTable.getSelectedRow();
        if (selectedRow == -1) {
            JOptionPane.showMessageDialog(this, "Пожалуйста, выберите клиента для удаления.", "Информация", JOptionPane.INFORMATION_MESSAGE);
            return;
        }

        int customerId = (int) customersModel.getValueAt(selectedRow, 0);
        String customerName = (String) customersModel.getValueAt(selectedRow, 1);

        int confirm = JOptionPane.showConfirmDialog(this, "Вы уверены, что хотите удалить клиента \"" + customerName + "\"?", "Подтверждение", JOptionPane.YES_NO_OPTION);
        if (confirm != JOptionPane.YES_OPTION) {
            return;
        }

        try {
            ConnectMySQL connection = new ConnectMySQL();
            Connection conn = connection.getConnection();

            String query = "DELETE FROM Customers WHERE customer_id = ?";
            PreparedStatement pstmt = conn.prepareStatement(query);
            pstmt.setInt(1, customerId);
            pstmt.executeUpdate();
            conn.close();

            JOptionPane.showMessageDialog(this, "Клиент успешно удален.");
            loadCustomers();
        } catch (SQLIntegrityConstraintViolationException ex) {
            JOptionPane.showMessageDialog(this, "Невозможно удалить клиента, так как существуют связанные бронирования.", "Ошибка", JOptionPane.ERROR_MESSAGE);
        } catch (Exception e) {
            e.printStackTrace();
            JOptionPane.showMessageDialog(this, "Ошибка при удалении клиента.", "Ошибка", JOptionPane.ERROR_MESSAGE);
        }
    }

    // Вкладка "Номера"
    private void initRoomsTab() {
        JPanel panel = new JPanel(new BorderLayout());

        // Верхняя панель с кнопкой обновления
        JPanel topPanel = new JPanel();
        refreshRoomsButton = new JButton("Обновить");
        topPanel.add(refreshRoomsButton);

        panel.add(topPanel, BorderLayout.NORTH);

        // Таблица номеров
        roomsModel = new DefaultTableModel();
        roomsTable = new JTable(roomsModel);
        roomsModel.setColumnIdentifiers(new String[]{
                "ID Номера", "Номер", "Статус", "Цена", "Тип кровати", "Тип номера", "Дата создания", "Дата обновления"
        });

        loadRooms();

        JScrollPane scrollPane = new JScrollPane(roomsTable);
        panel.add(scrollPane, BorderLayout.CENTER);

        // Обработчик кнопки обновления
        refreshRoomsButton.addActionListener(e -> loadRooms());

        tabbedPane.addTab("Номера", panel);
    }

    // Загрузка номеров из базы данных
    private void loadRooms() {
        roomsModel.setRowCount(0);
        try {
            ConnectMySQL connection = new ConnectMySQL();
            Connection conn = connection.getConnection();
            String query = "SELECT room_id, room_number, status, price, bed_type, room_type, created_at, updated_at FROM Rooms";
            Statement stmt = conn.createStatement();
            ResultSet rs = stmt.executeQuery(query);

            while (rs.next()) {
                Vector<Object> row = new Vector<>();
                row.add(rs.getInt("room_id"));
                row.add(rs.getInt("room_number"));
                row.add(rs.getString("status"));
                row.add(rs.getDouble("price"));
                row.add(rs.getString("bed_type"));
                row.add(rs.getString("room_type"));
                row.add(rs.getTimestamp("created_at"));
                row.add(rs.getTimestamp("updated_at"));
                roomsModel.addRow(row);
            }
            conn.close();
        } catch (Exception e) {
            e.printStackTrace();
            JOptionPane.showMessageDialog(this, "Ошибка загрузки номеров.", "Ошибка", JOptionPane.ERROR_MESSAGE);
        }
    }

    // Вкладка "Платежи"
    private void initPaymentsTab() {
        JPanel panel = new JPanel(new BorderLayout());

        // Верхняя панель с кнопкой обновления
        JPanel topPanel = new JPanel();
        refreshPaymentsButton = new JButton("Обновить");
        topPanel.add(refreshPaymentsButton);

        panel.add(topPanel, BorderLayout.NORTH);

        // Таблица платежей
        paymentsModel = new DefaultTableModel();
        paymentsTable = new JTable(paymentsModel);
        paymentsModel.setColumnIdentifiers(new String[]{
                "ID Платежа", "ID Бронирования", "Сумма", "Дата платежа", "Метод оплаты", "Дата создания"
        });

        loadPayments();

        JScrollPane scrollPane = new JScrollPane(paymentsTable);
        panel.add(scrollPane, BorderLayout.CENTER);

        // Обработчик кнопки обновления
        refreshPaymentsButton.addActionListener(e -> loadPayments());

        tabbedPane.addTab("Платежи", panel);
    }

    // Загрузка платежей из базы данных
    private void loadPayments() {
        paymentsModel.setRowCount(0);
        try {
            ConnectMySQL connection = new ConnectMySQL();
            Connection conn = connection.getConnection();
            String query = "SELECT payment_id, reservation_id, amount, payment_date, payment_method, created_at FROM Payments";
            Statement stmt = conn.createStatement();
            ResultSet rs = stmt.executeQuery(query);

            while (rs.next()) {
                Vector<Object> row = new Vector<>();
                row.add(rs.getInt("payment_id"));
                row.add(rs.getInt("reservation_id"));
                row.add(rs.getDouble("amount"));
                row.add(rs.getDate("payment_date"));
                row.add(rs.getString("payment_method"));
                row.add(rs.getTimestamp("created_at"));
                paymentsModel.addRow(row);
            }
            conn.close();
        } catch (Exception e) {
            e.printStackTrace();
            JOptionPane.showMessageDialog(this, "Ошибка загрузки платежей.", "Ошибка", JOptionPane.ERROR_MESSAGE);
        }
    }

    // Вкладка "Уборка"
    private void initCleaningTab() {
        JPanel panel = new JPanel(new BorderLayout());

        // Верхняя панель с кнопками
        JPanel topPanel = new JPanel();
        assignCleanerButton = new JButton("Назначить Уборщика");
        markInProgressButton = new JButton("Отметить как 'В процессе'");
        markCompletedButton = new JButton("Отметить как 'Завершено'");
        refreshCleaningButton = new JButton("Обновить");

        topPanel.add(assignCleanerButton);
        topPanel.add(markInProgressButton);
        topPanel.add(markCompletedButton);
        topPanel.add(refreshCleaningButton);

        panel.add(topPanel, BorderLayout.NORTH);

        // Таблица заданий по уборке
        cleaningModel = new DefaultTableModel();
        cleaningTable = new JTable(cleaningModel);
        cleaningModel.setColumnIdentifiers(new String[]{
                "ID Действия", "ID Бронирования", "Номер Комнаты", "Уборщик", "Тип Действия", "Запланировано на", "Статус", "Дата создания", "Дата обновления"
        });

        loadCleaningTasks();

        JScrollPane scrollPane = new JScrollPane(cleaningTable);
        panel.add(scrollPane, BorderLayout.CENTER);

        // Обработчики кнопок
        assignCleanerButton.addActionListener(e -> assignCleanerToTask());
        markInProgressButton.addActionListener(e -> updateCleaningTaskStatus("В процессе"));
        markCompletedButton.addActionListener(e -> updateCleaningTaskStatus("Завершено"));
        refreshCleaningButton.addActionListener(e -> loadCleaningTasks());

        tabbedPane.addTab("Уборка", panel);
    }

    // Загрузка заданий по уборке из базы данных
    private void loadCleaningTasks() {
        cleaningModel.setRowCount(0);
        try {
            ConnectMySQL connection = new ConnectMySQL();
            Connection conn = connection.getConnection();
            String query = "SELECT ca.action_id, ca.reservation_id, ro.room_number, cl.full_name AS cleaner_name, " +
                    "ca.action_type, ca.scheduled_time, ca.status, ca.created_at, ca.updated_at " +
                    "FROM Cleaning_Actions ca " +
                    "LEFT JOIN Cleaners cl ON ca.cleaner_id = cl.cleaner_id " +
                    "JOIN Rooms ro ON ca.room_id = ro.room_id";
            Statement stmt = conn.createStatement();
            ResultSet rs = stmt.executeQuery(query);

            while (rs.next()) {
                Vector<Object> row = new Vector<>();
                row.add(rs.getInt("action_id"));
                row.add(rs.getInt("reservation_id"));
                row.add(rs.getInt("room_number"));
                row.add(rs.getString("cleaner_name"));
                row.add(rs.getString("action_type"));
                row.add(rs.getTimestamp("scheduled_time"));
                row.add(rs.getString("status"));
                row.add(rs.getTimestamp("created_at"));
                row.add(rs.getTimestamp("updated_at"));
                cleaningModel.addRow(row);
            }
            conn.close();
        } catch (Exception e) {
            e.printStackTrace();
            JOptionPane.showMessageDialog(this, "Ошибка загрузки заданий на уборку.", "Ошибка", JOptionPane.ERROR_MESSAGE);
        }
    }

    // Назначение уборщика на выбранное задание по уборке
    private void assignCleanerToTask() {
        int selectedRow = cleaningTable.getSelectedRow();
        if (selectedRow == -1) {
            JOptionPane.showMessageDialog(this, "Пожалуйста, выберите задание для назначения уборщика.", "Информация", JOptionPane.INFORMATION_MESSAGE);
            return;
        }

        int actionId = (int) cleaningModel.getValueAt(selectedRow, 0);

        // Диалоговое окно для выбора уборщика
        JDialog dialog = new JDialog(this, "Назначить Уборщика", true);
        dialog.setSize(300, 200);
        dialog.setLocationRelativeTo(this);
        dialog.setLayout(new GridBagLayout());

        GridBagConstraints gbc = new GridBagConstraints();
        gbc.insets = new Insets(5,5,5,5);
        gbc.fill = GridBagConstraints.HORIZONTAL;

        JLabel cleanerLabel = new JLabel("Уборщик:");
        JComboBox<String> cleanerComboBox = new JComboBox<>();

        // Загрузка доступных уборщиков
        try {
            ConnectMySQL connection = new ConnectMySQL();
            Connection conn = connection.getConnection();
            String query = "SELECT cleaner_id, full_name FROM Cleaners WHERE status = 'Свободен'";
            Statement stmt = conn.createStatement();
            ResultSet rs = stmt.executeQuery(query);
            while (rs.next()) {
                cleanerComboBox.addItem(rs.getInt("cleaner_id") + " - " + rs.getString("full_name"));
            }
            conn.close();
        } catch (Exception e) {
            e.printStackTrace();
            JOptionPane.showMessageDialog(this, "Ошибка загрузки списка уборщиков.", "Ошибка", JOptionPane.ERROR_MESSAGE);
            return;
        }

        if (cleanerComboBox.getItemCount() == 0) {
            JOptionPane.showMessageDialog(this, "Нет доступных уборщиков.", "Информация", JOptionPane.INFORMATION_MESSAGE);
            return;
        }

        gbc.gridx = 0;
        gbc.gridy = 0;
        dialog.add(cleanerLabel, gbc);
        gbc.gridx = 1;
        dialog.add(cleanerComboBox, gbc);

        JButton assignButton = new JButton("Назначить");
        gbc.gridx = 0;
        gbc.gridy++;
        gbc.gridwidth = 2;
        dialog.add(assignButton, gbc);

        assignButton.addActionListener(e -> {
            String selectedCleaner = (String) cleanerComboBox.getSelectedItem();
            int cleanerId = Integer.parseInt(selectedCleaner.split(" - ")[0]);

            try {
                ConnectMySQL connection = new ConnectMySQL();
                Connection conn = connection.getConnection();
                String updateQuery = "UPDATE Cleaning_Actions SET cleaner_id = ?, status = 'Назначено', updated_at = NOW() WHERE action_id = ?";
                PreparedStatement pstmt = conn.prepareStatement(updateQuery);
                pstmt.setInt(1, cleanerId);
                pstmt.setInt(2, actionId);
                pstmt.executeUpdate();

                // Обновляем статус уборщика на 'Занят'
                String updateCleanerStatus = "UPDATE Cleaners SET status = 'Занят' WHERE cleaner_id = ?";
                PreparedStatement pstmtCleaner = conn.prepareStatement(updateCleanerStatus);
                pstmtCleaner.setInt(1, cleanerId);
                pstmtCleaner.executeUpdate();

                conn.close();

                JOptionPane.showMessageDialog(dialog, "Уборщик успешно назначен.");
                dialog.dispose();
                loadCleaningTasks();
                // Если необходимо, реализуйте метод loadCleaners() для обновления статусов уборщиков

            } catch (Exception ex) {
                ex.printStackTrace();
                JOptionPane.showMessageDialog(dialog, "Ошибка при назначении уборщика.", "Ошибка", JOptionPane.ERROR_MESSAGE);
            }
        });

        dialog.setVisible(true);
    }

    // Обновление статуса задания по уборке
    private void updateCleaningTaskStatus(String newStatus) {
        int selectedRow = cleaningTable.getSelectedRow();
        if (selectedRow == -1) {
            JOptionPane.showMessageDialog(this, "Пожалуйста, выберите задание для обновления статуса.", "Информация", JOptionPane.INFORMATION_MESSAGE);
            return;
        }

        int actionId = (int) cleaningModel.getValueAt(selectedRow, 0);
        String cleanerName = (String) cleaningModel.getValueAt(selectedRow, 3);
        Integer cleanerId = null;

        if (cleanerName != null && !cleanerName.isEmpty()) {
            // Получаем ID уборщика по имени
            try {
                ConnectMySQL connection = new ConnectMySQL();
                Connection conn = connection.getConnection();
                String query = "SELECT cleaner_id FROM Cleaners WHERE full_name = ?";
                PreparedStatement pstmt = conn.prepareStatement(query);
                pstmt.setString(1, cleanerName);
                ResultSet rs = pstmt.executeQuery();
                if (rs.next()) {
                    cleanerId = rs.getInt("cleaner_id");
                }
                conn.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        try {
            ConnectMySQL connection = new ConnectMySQL();
            Connection conn = connection.getConnection();
            String updateQuery = "UPDATE Cleaning_Actions SET status = ?, updated_at = NOW() WHERE action_id = ?";
            PreparedStatement pstmt = conn.prepareStatement(updateQuery);
            pstmt.setString(1, newStatus);
            pstmt.setInt(2, actionId);
            pstmt.executeUpdate();

            if ("Завершено".equals(newStatus) && cleanerId != null) {
                // Обновляем статус уборщика на 'Свободен'
                String updateCleanerStatus = "UPDATE Cleaners SET status = 'Свободен' WHERE cleaner_id = ?";
                PreparedStatement pstmtCleaner = conn.prepareStatement(updateCleanerStatus);
                pstmtCleaner.setInt(1, cleanerId);
                pstmtCleaner.executeUpdate();
            }

            conn.close();

            JOptionPane.showMessageDialog(this, "Статус задания обновлен.");
            loadCleaningTasks();
            // Если необходимо, реализуйте метод loadCleaners() для обновления статусов уборщиков

        } catch (Exception ex) {
            ex.printStackTrace();
            JOptionPane.showMessageDialog(this, "Ошибка при обновлении статуса задания.", "Ошибка", JOptionPane.ERROR_MESSAGE);
        }
    }

    // Главный метод для запуска панели ресепшиониста
    public static void main(String[] args) {
        // Установка системного стиля для современного интерфейса
        try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } catch (Exception ignored) {}

        // Для тестирования используем receptionistId = 1
        SwingUtilities.invokeLater(() -> new DashboardReceptionist(1));
    }
}















// src/h/Login.java
package h;

import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.sql.*;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class Login extends JFrame implements ActionListener {

    private JLabel usernameLabel, passwordLabel;
    private JTextField usernameField;
    private JPasswordField passwordField;
    private JButton loginButton, cancelButton;
    private JCheckBox showPasswordCheck;
    private JButton signupLink;

    public Login() {
        setTitle("Авторизация");
        setBounds(700, 300, 400, 300);
        setLayout(null);

        // Метка и поле ввода для логина
        usernameLabel = new JLabel("Имя пользователя:");
        usernameLabel.setBounds(50, 50, 120, 30);
        add(usernameLabel);

        usernameField = new JTextField();
        usernameField.setBounds(180, 50, 150, 30);
        add(usernameField);

        // Метка и поле ввода для пароля
        passwordLabel = new JLabel("Пароль:");
        passwordLabel.setBounds(50, 100, 120, 30);
        add(passwordLabel);

        passwordField = new JPasswordField();
        passwordField.setBounds(180, 100, 150, 30);
        add(passwordField);

        // Чекбокс для показа пароля
        showPasswordCheck = new JCheckBox("Показать пароль");
        showPasswordCheck.setBounds(180, 140, 150, 25);
        showPasswordCheck.setBackground(Color.WHITE);
        showPasswordCheck.addActionListener(this);
        add(showPasswordCheck);

        // Кнопка входа
        loginButton = new JButton("Войти");
        loginButton.setBounds(50, 180, 120, 30);
        loginButton.setForeground(Color.BLACK);
        loginButton.setBackground(Color.BLACK);
        loginButton.addActionListener(this);
        add(loginButton);

        // Кнопка отмены
        cancelButton = new JButton("Выход");
        cancelButton.setBounds(210, 180, 120, 30);
        cancelButton.setForeground(Color.BLACK);
        cancelButton.setBackground(Color.BLACK);
        cancelButton.addActionListener(this);
        add(cancelButton);

        // Ссылка на регистрацию
        signupLink = new JButton("<HTML><U>Нет аккаунта? Зарегистрироваться</U></HTML>");
        signupLink.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
        signupLink.setBorderPainted(false);
        signupLink.setForeground(Color.BLUE.darker());
        signupLink.setBackground(Color.WHITE);
        signupLink.setFocusPainted(false);
        signupLink.setBounds(100, 220, 200, 25);
        signupLink.addActionListener(this);
        add(signupLink);

        getContentPane().setBackground(Color.WHITE);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setVisible(true);
    }

    // Метод для хеширования пароля
    private String hashPassword(String password) {
        try {
            MessageDigest md = MessageDigest.getInstance("SHA-256");
            byte[] hash = md.digest(password.getBytes());
            StringBuilder sb = new StringBuilder();
            for (byte b : hash) {
                sb.append(String.format("%02x", b));
            }
            return sb.toString();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            return null;
        }
    }

    // Обработка событий
    public void actionPerformed(ActionEvent ae) {
        // Обработка чекбокса показа пароля
        if (ae.getSource() == showPasswordCheck) {
            if (showPasswordCheck.isSelected()) {
                passwordField.setEchoChar((char) 0);
            } else {
                passwordField.setEchoChar('•');
            }
        }

        // Обработка кнопки "Войти"
        if (ae.getSource() == loginButton) {
            authenticateUser();
        }

        // Обработка кнопки "Отмена"
        if (ae.getSource() == cancelButton) {
            int confirm = JOptionPane.showConfirmDialog(this, "Вы уверены, что хотите выйти?", "Подтверждение", JOptionPane.YES_NO_OPTION);
            if (confirm == JOptionPane.YES_OPTION) {
                System.exit(0);
            }
        }

        // Обработка ссылки на регистрацию
        if (ae.getSource() == signupLink) {
            new SignUp().setVisible(true);
            this.dispose();
        }
    }

    // Метод аутентификации пользователя
    private void authenticateUser() {
        String username = usernameField.getText().trim();
        String password = new String(passwordField.getPassword()).trim();

        if (username.isEmpty() || password.isEmpty()) {
            JOptionPane.showMessageDialog(this, "Пожалуйста, введите имя пользователя и пароль.", "Ошибка", JOptionPane.ERROR_MESSAGE);
            return;
        }

        String hashedPassword = hashPassword(password);
        if (hashedPassword == null) {
            JOptionPane.showMessageDialog(this, "Ошибка хеширования пароля.", "Ошибка", JOptionPane.ERROR_MESSAGE);
            return;
        }

        // Попытка авторизоваться как Администратор
        Pr user = authenticateInRole("Administrators", "admin_id", "login", "password");
        if (user != null) {
            JOptionPane.showMessageDialog(this, "Добро пожаловать, Администратор!");
            new DashboardAdmin(user.getId()).setVisible(true);
            this.dispose();
            return;
        }

        // Попытка авторизоваться как Ресепшионист
        user = authenticateInRole("Receptionists", "receptionist_id", "login", "password");
        if (user != null) {
            JOptionPane.showMessageDialog(this, "Добро пожаловать, Ресепшионист!");
            new DashboardReceptionist(user.getId()).setVisible(true);
            this.dispose();
            return;
        }

        // Если пользователь не найден
        JOptionPane.showMessageDialog(this, "Неверные имя пользователя или пароль.", "Ошибка", JOptionPane.ERROR_MESSAGE);
        usernameField.setText("");
        passwordField.setText("");
    }

    /**
     * Метод для аутентификации пользователя в заданной роли.
     *
     * @param tableName      Название таблицы (Administrators или Receptionists)
     * @param idColumn       Название столбца ID (admin_id или receptionist_id)
     * @param loginColumn    Название столбца с логином
     * @param passwordColumn Название столбца с паролем
     * @return Объект Pr с информацией о пользователе или null, если не найден
     */
    private Pr authenticateInRole(String tableName, String idColumn, String loginColumn, String passwordColumn) {
        String query = "SELECT * FROM " + tableName + " WHERE " + loginColumn + " = ? AND " + passwordColumn + " = ?";
        try (ConnectMySQL connection = new ConnectMySQL();
             PreparedStatement pstmt = connection.getConnection().prepareStatement(query)) {

            pstmt.setString(1, usernameField.getText().trim());
            pstmt.setString(2, hashPassword(new String(passwordField.getPassword()).trim()));

            try (ResultSet rs = pstmt.executeQuery()) {
                if (rs.next()) {
                    int id = rs.getInt(idColumn);
                    String fullName = rs.getString("full_name");
                    String role = tableName.equals("Administrators") ? "Administrator" : "Receptionist";
                    return new Pr(id, fullName, role);
                }
            }

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
            JOptionPane.showMessageDialog(this, "Драйвер базы данных не найден.", "Ошибка", JOptionPane.ERROR_MESSAGE);
        } catch (SQLException e) {
            e.printStackTrace();
            JOptionPane.showMessageDialog(this, "Ошибка подключения к базе данных.", "Ошибка", JOptionPane.ERROR_MESSAGE);
        }
        return null;
    }

    public static void main(String[] args) {
        // Установка системного вида для современного оформления
        try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } catch (Exception ignored) {}

        new Login();
    }
}












// src/h/Pr.java
package h;

public class Pr {
    private int id;
    private String fullName;
    private String role; // "Administrator" или "Receptionist"

    public Pr(int id, String fullName, String role) {
        this.id = id;
        this.fullName = fullName;
        this.role = role;
    }

    // Геттеры
    public int getId() {
        return id;
    }

    public String getFullName() {
        return fullName;
    }

    public String getRole() {
        return role;
    }
}














// src/h/SignUp.java
package h;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.sql.*;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class SignUp extends JFrame implements ActionListener {

    private JTextField nameField, passportField, addressField, phoneField, emailField, loginField;
    private JPasswordField passwordField;
    private JCheckBox showPasswordCheck;
    private JButton signupButton, cancelButton;
    private JButton loginLink;

    public SignUp() {
        setTitle("Регистрация Администратора");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(500, 500);
        setLocationRelativeTo(null);

        JPanel panel = new JPanel(new GridBagLayout());
        panel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
        GridBagConstraints gbc = new GridBagConstraints();
        gbc.fill = GridBagConstraints.HORIZONTAL;

        gbc.insets = new Insets(5,5,5,5);

        // Полное имя
        JLabel nameLabel = new JLabel("Полное имя:");
        gbc.gridx = 0;
        gbc.gridy = 0;
        panel.add(nameLabel, gbc);

        nameField = new JTextField(20);
        gbc.gridx = 1;
        panel.add(nameField, gbc);

        // Номер паспорта
        JLabel passportLabel = new JLabel("Номер паспорта:");
        gbc.gridx = 0;
        gbc.gridy++;
        panel.add(passportLabel, gbc);

        passportField = new JTextField(20);
        gbc.gridx = 1;
        panel.add(passportField, gbc);

        // Адрес
        JLabel addressLabel = new JLabel("Адрес:");
        gbc.gridx = 0;
        gbc.gridy++;
        panel.add(addressLabel, gbc);

        addressField = new JTextField(20);
        gbc.gridx = 1;
        panel.add(addressField, gbc);

        // Телефон
        JLabel phoneLabel = new JLabel("Телефон:");
        gbc.gridx = 0;
        gbc.gridy++;
        panel.add(phoneLabel, gbc);

        phoneField = new JTextField(20);
        gbc.gridx = 1;
        panel.add(phoneField, gbc);

        // Email
        JLabel emailLabel = new JLabel("Email:");
        gbc.gridx = 0;
        gbc.gridy++;
        panel.add(emailLabel, gbc);

        emailField = new JTextField(20);
        gbc.gridx = 1;
        panel.add(emailField, gbc);

        // Логин
        JLabel loginLabel = new JLabel("Логин:");
        gbc.gridx = 0;
        gbc.gridy++;
        panel.add(loginLabel, gbc);

        loginField = new JTextField(20);
        gbc.gridx = 1;
        panel.add(loginField, gbc);

        // Пароль
        JLabel passwordLabel = new JLabel("Пароль:");
        gbc.gridx = 0;
        gbc.gridy++;
        panel.add(passwordLabel, gbc);

        passwordField = new JPasswordField(20);
        gbc.gridx = 1;
        panel.add(passwordField, gbc);

        // Чекбокс для показа пароля
        showPasswordCheck = new JCheckBox("Показать пароль");
        gbc.gridx = 1;
        gbc.gridy++;
        panel.add(showPasswordCheck, gbc);
        showPasswordCheck.addActionListener(this);

        // Кнопки регистрации и отмены
        signupButton = new JButton("Зарегистрироваться");
        gbc.gridx = 0;
        gbc.gridy++;
        gbc.gridwidth = 2;
        gbc.insets = new Insets(20,5,5,5);
        panel.add(signupButton, gbc);
        signupButton.addActionListener(this);

        cancelButton = new JButton("Отмена");
        gbc.gridy++;
        panel.add(cancelButton, gbc);
        cancelButton.addActionListener(this);

        // Ссылка на окно входа
        loginLink = new JButton("<HTML><U>Уже есть аккаунт? Войти</U></HTML>");
        loginLink.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
        loginLink.setBorderPainted(false);
        loginLink.setForeground(Color.BLUE.darker());
        loginLink.setBackground(Color.WHITE);
        loginLink.setFocusPainted(false);
        loginLink.addActionListener(this);
        gbc.gridy++;
        panel.add(loginLink, gbc);

        add(panel);
        setVisible(true);
    }

    // Метод для хеширования пароля
    private String hashPassword(String password) {
        try {
            MessageDigest md = MessageDigest.getInstance("SHA-256");
            byte[] hashBytes = md.digest(password.getBytes());

            StringBuilder sb = new StringBuilder();
            for(byte b : hashBytes){
                sb.append(String.format("%02x", b));
            }

            return sb.toString();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            return null;
        }
    }

    // Обработка событий
    @Override
    public void actionPerformed(ActionEvent ae) {
        Object source = ae.getSource();

        if (source == showPasswordCheck) {
            if (showPasswordCheck.isSelected()) {
                passwordField.setEchoChar((char)0);
            } else {
                passwordField.setEchoChar('•');
            }
        }

        if (source == signupButton) {
            String fullName = nameField.getText().trim();
            String passportNumber = passportField.getText().trim();
            String address = addressField.getText().trim();
            String phone = phoneField.getText().trim();
            String email = emailField.getText().trim();
            String login = loginField.getText().trim();
            String password = new String(passwordField.getPassword()).trim();

            // Валидация
            if (fullName.isEmpty() || passportNumber.isEmpty() || address.isEmpty() ||
                    phone.isEmpty() || email.isEmpty() || login.isEmpty() || password.isEmpty()) {
                JOptionPane.showMessageDialog(this, "Пожалуйста, заполните все обязательные поля.", "Ошибка", JOptionPane.ERROR_MESSAGE);
                return;
            }

            try {
                ConnectMySQL connection = new ConnectMySQL();
                Connection conn = connection.getConnection();

                String query = "INSERT INTO Administrators (full_name, passport_number, address, phone_number, email, login, password, created_at, updated_at) "
                        + "VALUES (?, ?, ?, ?, ?, ?, ?, NOW(), NOW())";

                PreparedStatement pstmt = conn.prepareStatement(query);
                pstmt.setString(1, fullName);
                pstmt.setString(2, passportNumber);
                pstmt.setString(3, address);
                pstmt.setString(4, phone);
                pstmt.setString(5, email);
                pstmt.setString(6, login);
                pstmt.setString(7, hashPassword(password));

                int rowsAffected = pstmt.executeUpdate();
                if (rowsAffected > 0) {
                    JOptionPane.showMessageDialog(this, "Аккаунт администратора успешно создан!");
                    new Login().setVisible(true);
                    this.dispose();
                } else {
                    JOptionPane.showMessageDialog(this, "Ошибка при создании аккаунта. Пожалуйста, попробуйте снова.", "Ошибка", JOptionPane.ERROR_MESSAGE);
                }

                conn.close();

            } catch (SQLIntegrityConstraintViolationException e) {
                JOptionPane.showMessageDialog(this, "Такой логин, номер паспорта, телефон или email уже существуют!", "Ошибка", JOptionPane.ERROR_MESSAGE);
            } catch (Exception e) {
                e.printStackTrace();
                JOptionPane.showMessageDialog(this, "Ошибка подключения к базе данных.", "Ошибка", JOptionPane.ERROR_MESSAGE);
            }
        }

        if (source == cancelButton) {
            int confirm = JOptionPane.showConfirmDialog(this, "Вы уверены, что хотите отменить регистрацию?", "Подтверждение", JOptionPane.YES_NO_OPTION);
            if (confirm == JOptionPane.YES_OPTION) {
                new Login().setVisible(true);
                this.dispose();
            }
        }

        if (source == loginLink) {
            new Login().setVisible(true);
            this.dispose();
        }
    }

    public static void main(String[] args) {
        // Установка системного вида для современного оформления
        try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } catch (Exception ignored) {}

        new SignUp();
    }
}





// src/h/DashboardReceptionist.java
package h;

import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import java.awt.*;
import java.awt.event.*;
import java.sql.*;
import java.util.Vector;

public class DashboardReceptionist extends JFrame {

    private int receptionistId;
    private JTabbedPane tabbedPane;

    // Components for Reservations Tab
    private JTable reservationsTable;
    private DefaultTableModel reservationsModel;
    private JButton addReservationButton, editReservationButton, cancelReservationButton, checkInButton, checkOutButton;

    // Components for Customers Tab
    private JTable customersTable;
    private DefaultTableModel customersModel;
    private JButton addCustomerButton, editCustomerButton, deleteCustomerButton;

    // Components for Rooms Tab
    private JTable roomsTable;
    private DefaultTableModel roomsModel;
    private JButton refreshRoomsButton;

    // Components for Income Tab
    private JLabel totalIncomeLabel;
    private JTable paymentsTable;
    private DefaultTableModel paymentsModel;

    public DashboardReceptionist(int receptionistId) {
        this.receptionistId = receptionistId;
        setTitle("Панель Ресепшиониста");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(1200, 800);
        setLocationRelativeTo(null);

        tabbedPane = new JTabbedPane();

        // Initialize Tabs
        initReservationsTab();
        initCustomersTab();
        initRoomsTab();
        initIncomeTab();

        add(tabbedPane);

        setVisible(true);
    }

    // Initialization of Reservations Tab
    private void initReservationsTab() {
        JPanel panel = new JPanel(new BorderLayout());

        // Top Panel with Buttons
        JPanel topPanel = new JPanel();
        addReservationButton = new JButton("Добавить Бронирование");
        editReservationButton = new JButton("Редактировать Бронирование");
        cancelReservationButton = new JButton("Отменить Бронирование");
        checkInButton = new JButton("Заселить Клиента");
        checkOutButton = new JButton("Выселить Клиента");

        topPanel.add(addReservationButton);
        topPanel.add(editReservationButton);
        topPanel.add(cancelReservationButton);
        topPanel.add(checkInButton);
        topPanel.add(checkOutButton);

        panel.add(topPanel, BorderLayout.NORTH);

        // Table for Reservations
        reservationsModel = new DefaultTableModel();
        reservationsTable = new JTable(reservationsModel);
        reservationsModel.setColumnIdentifiers(new String[]{
                "ID Бронирования", "Клиент", "Номер", "Дата заезда", "Дата выезда", "Статус", "Сумма", "Депозит", "Ресепшионист", "Дата создания", "Дата обновления"
        });

        loadReservations();

        JScrollPane scrollPane = new JScrollPane(reservationsTable);
        panel.add(scrollPane, BorderLayout.CENTER);

        // Action Listeners for Buttons
        addReservationButton.addActionListener(e -> openAddReservationDialog());
        editReservationButton.addActionListener(e -> openEditReservationDialog());
        cancelReservationButton.addActionListener(e -> cancelSelectedReservation());
        checkInButton.addActionListener(e -> checkInSelectedReservation());
        checkOutButton.addActionListener(e -> checkOutSelectedReservation());

        tabbedPane.addTab("Бронирования", panel);
    }

    // Loading Reservations from Database
    private void loadReservations() {
        reservationsModel.setRowCount(0);
        try {
            ConnectMySQL connection = new ConnectMySQL();
            Connection conn = connection.getConnection();
            String query = "SELECT r.reservation_id, c.full_name AS customer, ro.room_number, r.check_in, r.check_out, r.status, r.total_amount, r.deposit, " +
                    "rec.full_name AS receptionist, r.created_at, r.updated_at " +
                    "FROM Reservations r " +
                    "JOIN Customers c ON r.customer_id = c.customer_id " +
                    "JOIN Rooms ro ON r.room_id = ro.room_id " +
                    "LEFT JOIN Receptionists rec ON r.receptionist_id = rec.receptionist_id";
            Statement stmt = conn.createStatement();
            ResultSet rs = stmt.executeQuery(query);

            while (rs.next()) {
                Vector<Object> row = new Vector<>();
                row.add(rs.getInt("reservation_id"));
                row.add(rs.getString("customer"));
                row.add(rs.getInt("room_number"));
                row.add(rs.getDate("check_in"));
                row.add(rs.getDate("check_out"));
                row.add(rs.getString("status"));
                row.add(rs.getDouble("total_amount"));
                row.add(rs.getDouble("deposit"));
                row.add(rs.getString("receptionist"));
                row.add(rs.getTimestamp("created_at"));
                row.add(rs.getTimestamp("updated_at"));
                reservationsModel.addRow(row);
            }
            conn.close();
        } catch (Exception e) {
            e.printStackTrace();
            JOptionPane.showMessageDialog(this, "Ошибка загрузки бронирований.", "Ошибка", JOptionPane.ERROR_MESSAGE);
        }
    }

    // Dialog to Add New Reservation
    private void openAddReservationDialog() {
        JDialog dialog = new JDialog(this, "Добавить Бронирование", true);
        dialog.setSize(500, 600);
        dialog.setLocationRelativeTo(this);
        dialog.setLayout(new GridBagLayout());

        GridBagConstraints gbc = new GridBagConstraints();
        gbc.insets = new Insets(10,10,10,10);
        gbc.fill = GridBagConstraints.HORIZONTAL;

        // Customer Selection
        JLabel customerLabel = new JLabel("Клиент:");
        gbc.gridx = 0;
        gbc.gridy = 0;
        dialog.add(customerLabel, gbc);

        JComboBox<String> customerComboBox = new JComboBox<>();
        loadCustomersIntoComboBox(customerComboBox);
        gbc.gridx = 1;
        dialog.add(customerComboBox, gbc);

        // Room Selection
        JLabel roomLabel = new JLabel("Номер:");
        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(roomLabel, gbc);

        JComboBox<String> roomComboBox = new JComboBox<>();
        loadAvailableRoomsIntoComboBox(roomComboBox);
        gbc.gridx = 1;
        dialog.add(roomComboBox, gbc);

        // Check-in Date
        JLabel checkInLabel = new JLabel("Дата заезда:");
        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(checkInLabel, gbc);

        JTextField checkInField = new JTextField("YYYY-MM-DD");
        gbc.gridx = 1;
        dialog.add(checkInField, gbc);

        // Check-out Date
        JLabel checkOutLabel = new JLabel("Дата выезда:");
        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(checkOutLabel, gbc);

        JTextField checkOutField = new JTextField("YYYY-MM-DD");
        gbc.gridx = 1;
        dialog.add(checkOutField, gbc);

        // Deposit
        JLabel depositLabel = new JLabel("Депозит:");
        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(depositLabel, gbc);

        JTextField depositField = new JTextField(20);
        gbc.gridx = 1;
        dialog.add(depositField, gbc);

        // Buttons
        JButton saveButton = new JButton("Сохранить");
        JButton cancelButton = new JButton("Отмена");

        JPanel buttonPanel = new JPanel();
        buttonPanel.add(saveButton);
        buttonPanel.add(cancelButton);

        gbc.gridx = 0;
        gbc.gridy++;
        gbc.gridwidth = 2;
        dialog.add(buttonPanel, gbc);

        // Action Listeners
        saveButton.addActionListener(e -> {
            String selectedCustomer = (String) customerComboBox.getSelectedItem();
            String selectedRoom = (String) roomComboBox.getSelectedItem();
            String checkInDate = checkInField.getText().trim();
            String checkOutDate = checkOutField.getText().trim();
            String depositStr = depositField.getText().trim();

            if (selectedCustomer == null || selectedRoom == null || checkInDate.isEmpty() || checkOutDate.isEmpty()) {
                JOptionPane.showMessageDialog(dialog, "Пожалуйста, заполните все обязательные поля.", "Ошибка", JOptionPane.ERROR_MESSAGE);
                return;
            }

            double deposit = 0.0;
            if (!depositStr.isEmpty()) {
                try {
                    deposit = Double.parseDouble(depositStr);
                } catch (NumberFormatException ex) {
                    JOptionPane.showMessageDialog(dialog, "Пожалуйста, введите корректную сумму депозита.", "Ошибка", JOptionPane.ERROR_MESSAGE);
                    return;
                }
            }

            try {
                ConnectMySQL connection = new ConnectMySQL();
                Connection conn = connection.getConnection();

                // Получение customer_id
                String customerQuery = "SELECT customer_id FROM Customers WHERE full_name = ?";
                PreparedStatement customerStmt = conn.prepareStatement(customerQuery);
                customerStmt.setString(1, selectedCustomer);
                ResultSet customerRs = customerStmt.executeQuery();
                int customerId = -1;
                if (customerRs.next()) {
                    customerId = customerRs.getInt("customer_id");
                }

                // Получение room_id
                String roomQuery = "SELECT room_id, price FROM Rooms WHERE room_number = ?";
                PreparedStatement roomStmt = conn.prepareStatement(roomQuery);
                roomStmt.setString(1, selectedRoom);
                ResultSet roomRs = roomStmt.executeQuery();
                int roomId = -1;
                double roomPrice = 0.0;
                if (roomRs.next()) {
                    roomId = roomRs.getInt("room_id");
                    roomPrice = roomRs.getDouble("price");
                }

                if (customerId == -1 || roomId == -1) {
                    JOptionPane.showMessageDialog(dialog, "Ошибка при получении данных клиента или номера.", "Ошибка", JOptionPane.ERROR_MESSAGE);
                    conn.close();
                    return;
                }

                // Расчет количества дней
                long daysBetween = java.time.temporal.ChronoUnit.DAYS.between(
                        java.time.LocalDate.parse(checkInDate),
                        java.time.LocalDate.parse(checkOutDate)
                );

                if (daysBetween <= 0) {
                    JOptionPane.showMessageDialog(dialog, "Дата выезда должна быть позже даты заезда.", "Ошибка", JOptionPane.ERROR_MESSAGE);
                    conn.close();
                    return;
                }

                double totalAmount = roomPrice * daysBetween;

                // Вставка бронирования
                String insertQuery = "INSERT INTO Reservations (customer_id, room_id, check_in, check_out, status, total_amount, deposit, created_at, updated_at, receptionist_id) " +
                        "VALUES (?, ?, ?, ?, 'Забронирован', ?, ?, NOW(), NOW(), ?)";
                PreparedStatement insertStmt = conn.prepareStatement(insertQuery);
                insertStmt.setInt(1, customerId);
                insertStmt.setInt(2, roomId);
                insertStmt.setDate(3, Date.valueOf(checkInDate));
                insertStmt.setDate(4, Date.valueOf(checkOutDate));
                insertStmt.setDouble(5, totalAmount);
                insertStmt.setDouble(6, deposit);
                insertStmt.setInt(7, receptionistId);

                insertStmt.executeUpdate();

                conn.close();

                JOptionPane.showMessageDialog(dialog, "Бронирование успешно добавлено.");
                dialog.dispose();
                loadReservations();
                loadRooms(); // Обновляем статус нумера

            } catch (SQLIntegrityConstraintViolationException ex) {
                JOptionPane.showMessageDialog(dialog, "Номер уже забронирован на указанные даты.", "Ошибка", JOptionPane.ERROR_MESSAGE);
            } catch (Exception ex) {
                ex.printStackTrace();
                JOptionPane.showMessageDialog(dialog, "Ошибка при добавлении бронирования.", "Ошибка", JOptionPane.ERROR_MESSAGE);
            }
        });

        cancelButton.addActionListener(e -> dialog.dispose());

        dialog.setVisible(true);
    }

    // Load customers into ComboBox
    private void loadCustomersIntoComboBox(JComboBox<String> comboBox) {
        try {
            ConnectMySQL connection = new ConnectMySQL();
            Connection conn = connection.getConnection();
            String query = "SELECT full_name FROM Customers";
            Statement stmt = conn.createStatement();
            ResultSet rs = stmt.executeQuery(query);

            while(rs.next()) {
                comboBox.addItem(rs.getString("full_name"));
            }
            conn.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // Load available rooms into ComboBox
    private void loadAvailableRoomsIntoComboBox(JComboBox<String> comboBox) {
        try {
            ConnectMySQL connection = new ConnectMySQL();
            Connection conn = connection.getConnection();
            // Изменяем запрос, убирая ссылку на несуществующий столбец 'available'
            String query = "SELECT room_number FROM Rooms WHERE status = 'Доступен'";
            Statement stmt = conn.createStatement();
            ResultSet rs = stmt.executeQuery(query);

            while(rs.next()) {
                comboBox.addItem(String.valueOf(rs.getInt("room_number")));
            }
            conn.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // Dialog to Edit Selected Reservation
    private void openEditReservationDialog() {
        int selectedRow = reservationsTable.getSelectedRow();
        if (selectedRow == -1) {
            JOptionPane.showMessageDialog(this, "Пожалуйста, выберите бронирование для редактирования.", "Информация", JOptionPane.INFORMATION_MESSAGE);
            return;
        }

        int reservationId = (int) reservationsModel.getValueAt(selectedRow, 0);
        String currentCustomer = (String) reservationsModel.getValueAt(selectedRow, 1);
        String currentRoom = String.valueOf(reservationsModel.getValueAt(selectedRow, 2));
        String currentCheckIn = reservationsModel.getValueAt(selectedRow, 3).toString();
        String currentCheckOut = reservationsModel.getValueAt(selectedRow, 4).toString();
        String currentStatus = (String) reservationsModel.getValueAt(selectedRow, 5);
        double currentTotalAmount = (double) reservationsModel.getValueAt(selectedRow, 6);
        double currentDeposit = (double) reservationsModel.getValueAt(selectedRow, 7);

        JDialog dialog = new JDialog(this, "Редактировать Бронирование", true);
        dialog.setSize(500, 600);
        dialog.setLocationRelativeTo(this);
        dialog.setLayout(new GridBagLayout());

        GridBagConstraints gbc = new GridBagConstraints();
        gbc.insets = new Insets(10,10,10,10);
        gbc.fill = GridBagConstraints.HORIZONTAL;

        // Customer Selection
        JLabel customerLabel = new JLabel("Клиент:");
        gbc.gridx = 0;
        gbc.gridy = 0;
        dialog.add(customerLabel, gbc);

        JComboBox<String> customerComboBox = new JComboBox<>();
        loadCustomersIntoComboBox(customerComboBox);
        customerComboBox.setSelectedItem(currentCustomer);
        gbc.gridx = 1;
        dialog.add(customerComboBox, gbc);

        // Room Selection
        JLabel roomLabel = new JLabel("Номер:");
        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(roomLabel, gbc);

        JComboBox<String> roomComboBox = new JComboBox<>();
        loadAvailableRoomsIntoComboBox(roomComboBox);
        roomComboBox.setSelectedItem(currentRoom);
        gbc.gridx = 1;
        dialog.add(roomComboBox, gbc);

        // Check-in Date
        JLabel checkInLabel = new JLabel("Дата заезда:");
        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(checkInLabel, gbc);

        JTextField checkInField = new JTextField(currentCheckIn, 20);
        gbc.gridx = 1;
        dialog.add(checkInField, gbc);

        // Check-out Date
        JLabel checkOutLabel = new JLabel("Дата выезда:");
        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(checkOutLabel, gbc);

        JTextField checkOutField = new JTextField(currentCheckOut, 20);
        gbc.gridx = 1;
        dialog.add(checkOutField, gbc);

        // Deposit
        JLabel depositLabel = new JLabel("Депозит:");
        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(depositLabel, gbc);

        JTextField depositField = new JTextField(String.valueOf(currentDeposit), 20);
        gbc.gridx = 1;
        dialog.add(depositField, gbc);

        // Status
        JLabel statusLabel = new JLabel("Статус:");
        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(statusLabel, gbc);

        JComboBox<String> statusComboBox = new JComboBox<>(new String[]{"Забронирован", "Заселен", "Выселен", "Отменён"});
        statusComboBox.setSelectedItem(currentStatus);
        gbc.gridx = 1;
        dialog.add(statusComboBox, gbc);

        // Buttons
        JButton saveButton = new JButton("Сохранить");
        JButton cancelButton = new JButton("Отмена");

        JPanel buttonPanel = new JPanel();
        buttonPanel.add(saveButton);
        buttonPanel.add(cancelButton);

        gbc.gridx = 0;
        gbc.gridy++;
        gbc.gridwidth = 2;
        dialog.add(buttonPanel, gbc);

        // Action Listeners
        saveButton.addActionListener(e -> {
            String selectedCustomer = (String) customerComboBox.getSelectedItem();
            String selectedRoom = (String) roomComboBox.getSelectedItem();
            String checkInDate = checkInField.getText().trim();
            String checkOutDate = checkOutField.getText().trim();
            String depositStr = depositField.getText().trim();
            String status = (String) statusComboBox.getSelectedItem();

            if (selectedCustomer == null || selectedRoom == null || checkInDate.isEmpty() || checkOutDate.isEmpty()) {
                JOptionPane.showMessageDialog(dialog, "Пожалуйста, заполните все обязательные поля.", "Ошибка", JOptionPane.ERROR_MESSAGE);
                return;
            }

            double deposit = 0.0;
            if (!depositStr.isEmpty()) {
                try {
                    deposit = Double.parseDouble(depositStr);
                } catch (NumberFormatException ex) {
                    JOptionPane.showMessageDialog(dialog, "Пожалуйста, введите корректную сумму депозита.", "Ошибка", JOptionPane.ERROR_MESSAGE);
                    return;
                }
            }

            try {
                ConnectMySQL connection = new ConnectMySQL();
                Connection conn = connection.getConnection();

                // Получение customer_id
                String customerQuery = "SELECT customer_id FROM Customers WHERE full_name = ?";
                PreparedStatement customerStmt = conn.prepareStatement(customerQuery);
                customerStmt.setString(1, selectedCustomer);
                ResultSet customerRs = customerStmt.executeQuery();
                int customerId = -1;
                if (customerRs.next()) {
                    customerId = customerRs.getInt("customer_id");
                }

                // Получение room_id
                String roomQuery = "SELECT room_id, price FROM Rooms WHERE room_number = ?";
                PreparedStatement roomStmt = conn.prepareStatement(roomQuery);
                roomStmt.setString(1, selectedRoom);
                ResultSet roomRs = roomStmt.executeQuery();
                int roomId = -1;
                double roomPrice = 0.0;
                if (roomRs.next()) {
                    roomId = roomRs.getInt("room_id");
                    roomPrice = roomRs.getDouble("price");
                }

                if (customerId == -1 || roomId == -1) {
                    JOptionPane.showMessageDialog(dialog, "Ошибка при получении данных клиента или номера.", "Ошибка", JOptionPane.ERROR_MESSAGE);
                    conn.close();
                    return;
                }

                // Расчет количества дней
                long daysBetween = java.time.temporal.ChronoUnit.DAYS.between(
                        java.time.LocalDate.parse(checkInDate),
                        java.time.LocalDate.parse(checkOutDate)
                );

                if (daysBetween <= 0) {
                    JOptionPane.showMessageDialog(dialog, "Дата выезда должна быть позже даты заезда.", "Ошибка", JOptionPane.ERROR_MESSAGE);
                    conn.close();
                    return;
                }

                double totalAmount = roomPrice * daysBetween;

                // Обновление бронирования
                String updateQuery = "UPDATE Reservations SET customer_id = ?, room_id = ?, check_in = ?, check_out = ?, status = ?, " +
                        "total_amount = ?, deposit = ?, updated_at = ? WHERE reservation_id = ?";
                PreparedStatement updateStmt = conn.prepareStatement(updateQuery);
                updateStmt.setInt(1, customerId);
                updateStmt.setInt(2, roomId);
                updateStmt.setDate(3, Date.valueOf(checkInDate));
                updateStmt.setDate(4, Date.valueOf(checkOutDate));
                updateStmt.setString(5, status);
                updateStmt.setDouble(6, totalAmount);
                updateStmt.setDouble(7, deposit);
                updateStmt.setTimestamp(8, new Timestamp(System.currentTimeMillis()));
                updateStmt.setInt(9, reservationId);

                updateStmt.executeUpdate();
                conn.close();

                JOptionPane.showMessageDialog(dialog, "Бронирование успешно обновлено.");
                dialog.dispose();
                loadReservations();
                loadRooms(); // Обновляем статус номеров

            } catch (SQLIntegrityConstraintViolationException ex) {
                JOptionPane.showMessageDialog(dialog, "Номер уже забронирован на указанные даты.", "Ошибка", JOptionPane.ERROR_MESSAGE);
            } catch (Exception ex) {
                ex.printStackTrace();
                JOptionPane.showMessageDialog(dialog, "Ошибка при обновлении бронирования.", "Ошибка", JOptionPane.ERROR_MESSAGE);
            }
        });

        cancelButton.addActionListener(e -> dialog.dispose());

        dialog.setVisible(true);
    }

    // Cancel Selected Reservation
    private void cancelSelectedReservation() {
        int selectedRow = reservationsTable.getSelectedRow();
        if (selectedRow == -1) {
            JOptionPane.showMessageDialog(this, "Пожалуйста, выберите бронирование для отмены.", "Информация", JOptionPane.INFORMATION_MESSAGE);
            return;
        }

        String status = (String) reservationsModel.getValueAt(selectedRow, 5);
        if (status.equals("Отменён")) {
            JOptionPane.showMessageDialog(this, "Бронирование уже отменено.", "Информация", JOptionPane.INFORMATION_MESSAGE);
            return;
        }

        int reservationId = (int) reservationsModel.getValueAt(selectedRow, 0);
        int confirm = JOptionPane.showConfirmDialog(this, "Вы уверены, что хотите отменить это бронирование?", "Подтверждение", JOptionPane.YES_NO_OPTION);
        if (confirm != JOptionPane.YES_OPTION) {
            return;
        }

        try {
            ConnectMySQL connection = new ConnectMySQL();
            Connection conn = connection.getConnection();

            String updateQuery = "UPDATE Reservations SET status = 'Отменён', updated_at = NOW() WHERE reservation_id = ?";
            PreparedStatement updateStmt = conn.prepareStatement(updateQuery);
            updateStmt.setInt(1, reservationId);
            updateStmt.executeUpdate();
            conn.close();

            JOptionPane.showMessageDialog(this, "Бронирование успешно отменено.");
            loadReservations();
            loadRooms(); // Обновляем статус номеров

        } catch (Exception e) {
            e.printStackTrace();
            JOptionPane.showMessageDialog(this, "Ошибка при отмене бронирования.", "Ошибка", JOptionPane.ERROR_MESSAGE);
        }
    }

    // Check-in Selected Reservation
    // Check-in Selected Reservation
    private void checkInSelectedReservation() {
        int selectedRow = reservationsTable.getSelectedRow();
        if (selectedRow == -1) {
            JOptionPane.showMessageDialog(this, "Пожалуйста, выберите бронирование для заселения.", "Информация", JOptionPane.INFORMATION_MESSAGE);
            return;
        }

        String status = (String) reservationsModel.getValueAt(selectedRow, 5);
        if (status.equals("Заселён")) {
            JOptionPane.showMessageDialog(this, "Клиент уже заселен.", "Информация", JOptionPane.INFORMATION_MESSAGE);
            return;
        }

        if (!status.equals("Забронирован")) {
            JOptionPane.showMessageDialog(this, "Невозможно заселить клиента с текущим статусом.", "Ошибка", JOptionPane.ERROR_MESSAGE);
            return;
        }

        int reservationId = (int) reservationsModel.getValueAt(selectedRow, 0);
        int roomNumber = (int) reservationsModel.getValueAt(selectedRow, 2);

        int confirm = JOptionPane.showConfirmDialog(this, "Вы уверены, что хотите заселить этого клиента?", "Подтверждение", JOptionPane.YES_NO_OPTION);
        if (confirm != JOptionPane.YES_OPTION) {
            return;
        }

        try {
            ConnectMySQL connection = new ConnectMySQL();
            Connection conn = connection.getConnection();

            // Обновление статуса бронирования
            String updateReservation = "UPDATE Reservations SET status = 'Заселён', updated_at = NOW() WHERE reservation_id = ?";
            PreparedStatement pstmt1 = conn.prepareStatement(updateReservation);
            pstmt1.setInt(1, reservationId);
            pstmt1.executeUpdate();

            // Обновление статуса номера (Room)
            String updateRoom = "UPDATE Rooms SET status = 'Недоступен' WHERE room_number = ?";
            PreparedStatement pstmt2 = conn.prepareStatement(updateRoom);
            pstmt2.setInt(1, roomNumber);
            pstmt2.executeUpdate();

            conn.close();

            JOptionPane.showMessageDialog(this, "Клиент успешно заселен.");
            loadReservations();
            loadRooms();

        } catch (Exception e) {
            e.printStackTrace();
            JOptionPane.showMessageDialog(this, "Ошибка при заселении клиента.", "Ошибка", JOptionPane.ERROR_MESSAGE);
        }
    }

    // Check-out Selected Reservation
    private void checkOutSelectedReservation() {
        int selectedRow = reservationsTable.getSelectedRow();
        if (selectedRow == -1) {
            JOptionPane.showMessageDialog(this, "Пожалуйста, выберите бронирование для выселения.", "Информация", JOptionPane.INFORMATION_MESSAGE);
            return;
        }

        String status = (String) reservationsModel.getValueAt(selectedRow, 5);
        if (!status.equals("Заселён")) {
            JOptionPane.showMessageDialog(this, "Клиент не заселен или уже выселен.", "Ошибка", JOptionPane.ERROR_MESSAGE);
            return;
        }

        int reservationId = (int) reservationsModel.getValueAt(selectedRow, 0);
        int roomNumber = (int) reservationsModel.getValueAt(selectedRow, 2);

        int confirm = JOptionPane.showConfirmDialog(this, "Вы уверены, что хотите выселить этого клиента?", "Подтверждение", JOptionPane.YES_NO_OPTION);
        if (confirm != JOptionPane.YES_OPTION) {
            return;
        }

        try {
            ConnectMySQL connection = new ConnectMySQL();
            Connection conn = connection.getConnection();

            // Обновление статуса бронирования
            String updateReservation = "UPDATE Reservations SET status = 'Выселен', updated_at = NOW() WHERE reservation_id = ?";
            PreparedStatement pstmt1 = conn.prepareStatement(updateReservation);
            pstmt1.setInt(1, reservationId);
            pstmt1.executeUpdate();

            // Обновление статуса номера
            String updateRoom = "UPDATE Rooms SET status = 'Доступен' WHERE room_number = ?";
            PreparedStatement pstmt2 = conn.prepareStatement(updateRoom);
            pstmt2.setInt(1, roomNumber);
            pstmt2.executeUpdate();

            conn.close();

            JOptionPane.showMessageDialog(this, "Клиент успешно выселен.");
            loadReservations();
            loadRooms();

        } catch (Exception e) {
            e.printStackTrace();
            JOptionPane.showMessageDialog(this, "Ошибка при выселении клиента.", "Ошибка", JOptionPane.ERROR_MESSAGE);
        }
    }

    // Initialization of Customers Tab
    private void initCustomersTab() {
        JPanel panel = new JPanel(new BorderLayout());

        // Top Panel with Buttons
        JPanel topPanel = new JPanel();
        addCustomerButton = new JButton("Добавить Клиента");
        editCustomerButton = new JButton("Редактировать Клиента");
        deleteCustomerButton = new JButton("Удалить Клиента");

        topPanel.add(addCustomerButton);
        topPanel.add(editCustomerButton);
        topPanel.add(deleteCustomerButton);

        panel.add(topPanel, BorderLayout.NORTH);

        // Table for Customers
        customersModel = new DefaultTableModel();
        customersTable = new JTable(customersModel);
        customersModel.setColumnIdentifiers(new String[]{
                "ID Клиента", "Полное имя", "Телефон", "Email", "Пол", "Страна", "Адрес", "Ресепшионист", "Дата создания", "Дата обновления"
        });

        loadCustomers();

        JScrollPane scrollPane = new JScrollPane(customersTable);
        panel.add(scrollPane, BorderLayout.CENTER);

        // Action Listeners for Buttons
        addCustomerButton.addActionListener(e -> openAddCustomerDialog());
        editCustomerButton.addActionListener(e -> openEditCustomerDialog());
        deleteCustomerButton.addActionListener(e -> deleteSelectedCustomer());

        tabbedPane.addTab("Клиенты", panel);
    }

    // Loading Customers from Database
    private void loadCustomers() {
        customersModel.setRowCount(0);
        try {
            ConnectMySQL connection = new ConnectMySQL();
            Connection conn = connection.getConnection();
            String query = "SELECT c.customer_id, c.full_name, c.phone, c.email, c.gender, c.country, c.address, " +
                    "rec.full_name AS receptionist, c.created_at, c.updated_at " +
                    "FROM Customers c " +
                    "LEFT JOIN Receptionists rec ON c.receptionist_id = rec.receptionist_id";
            Statement stmt = conn.createStatement();
            ResultSet rs = stmt.executeQuery(query);

            while (rs.next()) {
                Vector<Object> row = new Vector<>();
                row.add(rs.getInt("customer_id"));
                row.add(rs.getString("full_name"));
                row.add(rs.getString("phone"));
                row.add(rs.getString("email"));
                row.add(rs.getString("gender"));
                row.add(rs.getString("country"));
                row.add(rs.getString("address"));
                row.add(rs.getString("receptionist"));
                row.add(rs.getTimestamp("created_at"));
                row.add(rs.getTimestamp("updated_at"));
                customersModel.addRow(row);
            }
            conn.close();
        } catch (Exception e) {
            e.printStackTrace();
            JOptionPane.showMessageDialog(this, "Ошибка загрузки клиентов.", "Ошибка", JOptionPane.ERROR_MESSAGE);
        }
    }

    // Dialog to Add New Customer
    private void openAddCustomerDialog() {
        JDialog dialog = new JDialog(this, "Добавить Клиента", true);
        dialog.setSize(500, 600);
        dialog.setLocationRelativeTo(this);
        dialog.setLayout(new GridBagLayout());

        GridBagConstraints gbc = new GridBagConstraints();
        gbc.insets = new Insets(10,10,10,10);
        gbc.fill = GridBagConstraints.HORIZONTAL;

        // Полное имя
        JLabel nameLabel = new JLabel("Полное имя:");
        gbc.gridx = 0;
        gbc.gridy = 0;
        dialog.add(nameLabel, gbc);

        JTextField nameField = new JTextField(20);
        gbc.gridx = 1;
        dialog.add(nameField, gbc);

        // Телефон
        JLabel phoneLabel = new JLabel("Телефон:");
        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(phoneLabel, gbc);

        JTextField phoneField = new JTextField(20);
        gbc.gridx = 1;
        dialog.add(phoneField, gbc);

        // Email
        JLabel emailLabel = new JLabel("Email:");
        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(emailLabel, gbc);

        JTextField emailField = new JTextField(20);
        gbc.gridx = 1;
        dialog.add(emailField, gbc);

        // Пол
        JLabel genderLabel = new JLabel("Пол:");
        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(genderLabel, gbc);

        JComboBox<String> genderComboBox = new JComboBox<>(new String[]{"Мужской", "Женский"});
        gbc.gridx = 1;
        dialog.add(genderComboBox, gbc);

        // Страна
        JLabel countryLabel = new JLabel("Страна:");
        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(countryLabel, gbc);

        JTextField countryField = new JTextField(20);
        gbc.gridx = 1;
        dialog.add(countryField, gbc);

        // Адрес
        JLabel addressLabel = new JLabel("Адрес:");
        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(addressLabel, gbc);

        JTextField addressField = new JTextField(20);
        gbc.gridx = 1;
        dialog.add(addressField, gbc);

        // Buttons
        JButton saveButton = new JButton("Сохранить");
        JButton cancelButton = new JButton("Отмена");

        JPanel buttonPanel = new JPanel();
        buttonPanel.add(saveButton);
        buttonPanel.add(cancelButton);

        gbc.gridx = 0;
        gbc.gridy++;
        gbc.gridwidth = 2;
        dialog.add(buttonPanel, gbc);

        // Action Listeners
        saveButton.addActionListener(e -> {
            String fullName = nameField.getText().trim();
            String phone = phoneField.getText().trim();
            String email = emailField.getText().trim();
            String gender = (String) genderComboBox.getSelectedItem();
            String country = countryField.getText().trim();
            String address = addressField.getText().trim();

            if (fullName.isEmpty() || phone.isEmpty() || gender.isEmpty()) {
                JOptionPane.showMessageDialog(dialog, "Пожалуйста, заполните все обязательные поля.", "Ошибка", JOptionPane.ERROR_MESSAGE);
                return;
            }

            try {
                ConnectMySQL connection = new ConnectMySQL();
                Connection conn = connection.getConnection();

                String query = "INSERT INTO Customers (full_name, phone, email, gender, country, address, receptionist_id, created_at, updated_at) " +
                        "VALUES (?, ?, ?, ?, ?, ?, ?, NOW(), NOW())";
                PreparedStatement pstmt = conn.prepareStatement(query);
                pstmt.setString(1, fullName);
                pstmt.setString(2, phone);
                pstmt.setString(3, email.isEmpty() ? null : email);
                pstmt.setString(4, gender);
                pstmt.setString(5, country.isEmpty() ? null : country);
                pstmt.setString(6, address.isEmpty() ? null : address);
                pstmt.setInt(7, receptionistId);

                pstmt.executeUpdate();
                conn.close();

                JOptionPane.showMessageDialog(dialog, "Клиент успешно добавлен.");
                dialog.dispose();
                loadCustomers();
            } catch (SQLIntegrityConstraintViolationException ex) {
                JOptionPane.showMessageDialog(dialog, "Такой телефон или email уже существуют!", "Ошибка", JOptionPane.ERROR_MESSAGE);
            } catch (Exception ex) {
                ex.printStackTrace();
                JOptionPane.showMessageDialog(dialog, "Ошибка при добавлении клиента.", "Ошибка", JOptionPane.ERROR_MESSAGE);
            }
        });

        cancelButton.addActionListener(e -> dialog.dispose());

        dialog.setVisible(true);
    }

    // Dialog to Edit Selected Customer
    private void openEditCustomerDialog() {
        int selectedRow = customersTable.getSelectedRow();
        if (selectedRow == -1) {
            JOptionPane.showMessageDialog(this, "Пожалуйста, выберите клиента для редактирования.", "Информация", JOptionPane.INFORMATION_MESSAGE);
            return;
        }

        int customerId = (int) customersModel.getValueAt(selectedRow, 0);
        String currentName = (String) customersModel.getValueAt(selectedRow, 1);
        String currentPhone = (String) customersModel.getValueAt(selectedRow, 2);
        String currentEmail = (String) customersModel.getValueAt(selectedRow, 3);
        String currentGender = (String) customersModel.getValueAt(selectedRow, 4);
        String currentCountry = (String) customersModel.getValueAt(selectedRow, 5);
        String currentAddress = (String) customersModel.getValueAt(selectedRow, 6);

        JDialog dialog = new JDialog(this, "Редактировать Клиента", true);
        dialog.setSize(500, 600);
        dialog.setLocationRelativeTo(this);
        dialog.setLayout(new GridBagLayout());

        GridBagConstraints gbc = new GridBagConstraints();
        gbc.insets = new Insets(10,10,10,10);
        gbc.fill = GridBagConstraints.HORIZONTAL;

        // Полное имя
        JLabel nameLabel = new JLabel("Полное имя:");
        gbc.gridx = 0;
        gbc.gridy = 0;
        dialog.add(nameLabel, gbc);

        JTextField nameField = new JTextField(currentName, 20);
        gbc.gridx = 1;
        dialog.add(nameField, gbc);

        // Телефон
        JLabel phoneLabel = new JLabel("Телефон:");
        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(phoneLabel, gbc);

        JTextField phoneField = new JTextField(currentPhone, 20);
        gbc.gridx = 1;
        dialog.add(phoneField, gbc);

        // Email
        JLabel emailLabel = new JLabel("Email:");
        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(emailLabel, gbc);

        JTextField emailField = new JTextField(currentEmail, 20);
        gbc.gridx = 1;
        dialog.add(emailField, gbc);

        // Пол
        JLabel genderLabel = new JLabel("Пол:");
        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(genderLabel, gbc);

        JComboBox<String> genderComboBox = new JComboBox<>(new String[]{"Мужской", "Женский"});
        genderComboBox.setSelectedItem(currentGender);
        gbc.gridx = 1;
        dialog.add(genderComboBox, gbc);

        // Страна
        JLabel countryLabel = new JLabel("Страна:");
        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(countryLabel, gbc);

        JTextField countryField = new JTextField(currentCountry, 20);
        gbc.gridx = 1;
        dialog.add(countryField, gbc);

        // Адрес
        JLabel addressLabel = new JLabel("Адрес:");
        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(addressLabel, gbc);

        JTextField addressField = new JTextField(currentAddress, 20);
        gbc.gridx = 1;
        dialog.add(addressField, gbc);

        // Buttons
        JButton saveButton = new JButton("Сохранить");
        JButton cancelButton = new JButton("Отмена");

        JPanel buttonPanel = new JPanel();
        buttonPanel.add(saveButton);
        buttonPanel.add(cancelButton);

        gbc.gridx = 0;
        gbc.gridy++;
        gbc.gridwidth = 2;
        dialog.add(buttonPanel, gbc);

        // Action Listeners
        saveButton.addActionListener(e -> {
            String fullName = nameField.getText().trim();
            String phone = phoneField.getText().trim();
            String email = emailField.getText().trim();
            String gender = (String) genderComboBox.getSelectedItem();
            String country = countryField.getText().trim();
            String address = addressField.getText().trim();

            if (fullName.isEmpty() || phone.isEmpty() || gender.isEmpty()) {
                JOptionPane.showMessageDialog(dialog, "Пожалуйста, заполните все обязательные поля.", "Ошибка", JOptionPane.ERROR_MESSAGE);
                return;
            }

            try {
                ConnectMySQL connection = new ConnectMySQL();
                Connection conn = connection.getConnection();

                String query = "UPDATE Customers SET full_name = ?, phone = ?, email = ?, gender = ?, country = ?, address = ?, updated_at = NOW() WHERE customer_id = ?";
                PreparedStatement pstmt = conn.prepareStatement(query);
                pstmt.setString(1, fullName);
                pstmt.setString(2, phone);
                pstmt.setString(3, email.isEmpty() ? null : email);
                pstmt.setString(4, gender);
                pstmt.setString(5, country.isEmpty() ? null : country);
                pstmt.setString(6, address.isEmpty() ? null : address);
                pstmt.setInt(7, customerId);

                pstmt.executeUpdate();
                conn.close();

                JOptionPane.showMessageDialog(dialog, "Клиент успешно обновлен.");
                dialog.dispose();
                loadCustomers();
            } catch (SQLIntegrityConstraintViolationException ex) {
                JOptionPane.showMessageDialog(dialog, "Такой телефон или email уже существуют!", "Ошибка", JOptionPane.ERROR_MESSAGE);
            } catch (Exception ex) {
                ex.printStackTrace();
                JOptionPane.showMessageDialog(dialog, "Ошибка при обновлении клиента.", "Ошибка", JOptionPane.ERROR_MESSAGE);
            }
        });

        cancelButton.addActionListener(e -> dialog.dispose());

        dialog.setVisible(true);
    }

    // Delete Selected Customer
    private void deleteSelectedCustomer() {
        int selectedRow = customersTable.getSelectedRow();
        if (selectedRow == -1) {
            JOptionPane.showMessageDialog(this, "Пожалуйста, выберите клиента для удаления.", "Информация", JOptionPane.INFORMATION_MESSAGE);
            return;
        }

        int customerId = (int) customersModel.getValueAt(selectedRow, 0);
        String customerName = (String) customersModel.getValueAt(selectedRow, 1);

        int confirm = JOptionPane.showConfirmDialog(this, "Вы уверены, что хотите удалить клиента \"" + customerName + "\"?", "Подтверждение", JOptionPane.YES_NO_OPTION);
        if (confirm != JOptionPane.YES_OPTION) {
            return;
        }

        try {
            ConnectMySQL connection = new ConnectMySQL();
            Connection conn = connection.getConnection();

            String query = "DELETE FROM Customers WHERE customer_id = ?";
            PreparedStatement pstmt = conn.prepareStatement(query);
            pstmt.setInt(1, customerId);
            pstmt.executeUpdate();
            conn.close();

            JOptionPane.showMessageDialog(this, "Клиент успешно удален.");
            loadCustomers();
        } catch (SQLIntegrityConstraintViolationException ex) {
            JOptionPane.showMessageDialog(this, "Невозможно удалить клиента, так как существуют связанные бронирования.", "Ошибка", JOptionPane.ERROR_MESSAGE);
        } catch (Exception e) {
            e.printStackTrace();
            JOptionPane.showMessageDialog(this, "Ошибка при удалении клиента.", "Ошибка", JOptionPane.ERROR_MESSAGE);
        }
    }

    // Initialization of Rooms Tab
    // Initialization of Rooms Tab
    private void initRoomsTab() {
        JPanel panel = new JPanel(new BorderLayout());

        // Top Panel with Refresh Button
        JPanel topPanel = new JPanel();
        refreshRoomsButton = new JButton("Обновить");
        topPanel.add(refreshRoomsButton);

        panel.add(topPanel, BorderLayout.NORTH);

        // Table for Rooms
        roomsModel = new DefaultTableModel();
        roomsTable = new JTable(roomsModel);
        roomsModel.setColumnIdentifiers(new String[]{
                "ID Номера", "Номер", "Статус", "Цена", "Тип кровати", "Тип номера", "Дата создания", "Дата обновления"
        });

        loadRooms();

        JScrollPane scrollPane = new JScrollPane(roomsTable);
        panel.add(scrollPane, BorderLayout.CENTER);

        // Action Listener for Refresh Button
        refreshRoomsButton.addActionListener(e -> loadRooms());

        tabbedPane.addTab("Номера", panel);
    }

    // Loading Rooms from Database
    private void loadRooms() {
        roomsModel.setRowCount(0);
        try {
            ConnectMySQL connection = new ConnectMySQL();
            Connection conn = connection.getConnection();
            // Обновляем запрос, убирая столбцы 'available', 'admin_id' и 'receptionist_id'
            String query = "SELECT room_id, room_number, status, price, bed_type, room_type, created_at, updated_at FROM Rooms";
            Statement stmt = conn.createStatement();
            ResultSet rs = stmt.executeQuery(query);

            while (rs.next()) {
                Vector<Object> row = new Vector<>();
                row.add(rs.getInt("room_id"));
                row.add(rs.getInt("room_number"));
                row.add(rs.getString("status"));
                row.add(rs.getDouble("price"));
                row.add(rs.getString("bed_type"));
                row.add(rs.getString("room_type"));
                row.add(rs.getTimestamp("created_at"));
                row.add(rs.getTimestamp("updated_at"));
                roomsModel.addRow(row);
            }
            conn.close();
        } catch (Exception e) {
            e.printStackTrace();
            JOptionPane.showMessageDialog(this, "Ошибка загрузки номеров.", "Ошибка", JOptionPane.ERROR_MESSAGE);
        }
    }

    // Initialization of Income Tab
    private void initIncomeTab() {
        JPanel panel = new JPanel(new BorderLayout());

        // Top Panel with Total Income
        JPanel topPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
        totalIncomeLabel = new JLabel("Общий доход: ");
        topPanel.add(totalIncomeLabel);

        panel.add(topPanel, BorderLayout.NORTH);

        // Table for Payments
        paymentsModel = new DefaultTableModel();
        paymentsTable = new JTable(paymentsModel);
        paymentsModel.setColumnIdentifiers(new String[]{
                "ID Платежа", "ID Бронирования", "Сумма", "Дата платежа", "Метод оплаты", "Дата создания"
        });

        loadPayments();

        JScrollPane scrollPane = new JScrollPane(paymentsTable);
        panel.add(scrollPane, BorderLayout.CENTER);

        tabbedPane.addTab("Доходы", panel);
    }

    // Loading Payments and Calculating Total Income
    private void loadPayments() {
        paymentsModel.setRowCount(0);
        double totalIncome = 0.0;
        try {
            ConnectMySQL connection = new ConnectMySQL();
            Connection conn = connection.getConnection();
            String query = "SELECT payment_id, reservation_id, amount, payment_date, payment_method, created_at FROM Payments";
            Statement stmt = conn.createStatement();
            ResultSet rs = stmt.executeQuery(query);

            while (rs.next()) {
                Vector<Object> row = new Vector<>();
                row.add(rs.getInt("payment_id"));
                row.add(rs.getInt("reservation_id"));
                row.add(rs.getDouble("amount"));
                row.add(rs.getDate("payment_date"));
                row.add(rs.getString("payment_method"));
                row.add(rs.getTimestamp("created_at"));
                paymentsModel.addRow(row);
                totalIncome += rs.getDouble("amount");
            }
            conn.close();

            totalIncomeLabel.setText(String.format("Общий доход: %.2f", totalIncome));
        } catch (Exception e) {
            e.printStackTrace();
            JOptionPane.showMessageDialog(this, "Ошибка загрузки платежей.", "Ошибка", JOptionPane.ERROR_MESSAGE);
        }
    }

    // Dialog to Add New Customer
    // (Same as in Reservations tab, can be refactored to avoid duplication)

    // Hashing Password (if needed)
    private String hashPassword(String password) {
        try {
            java.security.MessageDigest md = java.security.MessageDigest.getInstance("SHA-256");
            byte[] hashBytes = md.digest(password.getBytes());

            StringBuilder sb = new StringBuilder();
            for(byte b : hashBytes){
                sb.append(String.format("%02x", b));
            }

            return sb.toString();
        } catch (java.security.NoSuchAlgorithmException e) {
            e.printStackTrace();
            return null;
        }
    }

    // Main Method to Launch Receptionist Dashboard
    public static void main(String[] args) {
        // Set system look and feel for modern UI
        try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } catch (Exception ignored) {}

        // For testing purposes, pass a sample receptionistId
        SwingUtilities.invokeLater(() -> new DashboardReceptionist(1));
    }
}



добавь сюда вкладку управления уборками чтобы при выселении клиента номер в котором он был считался все еще недоступным и оказывался во вкладке уборка и ресепшионист должен будет назначать уборщика чтобы он убрал номер в этом случае должен запускаться таймер уборки допустим 30 минут и по прохождении этого времени номер как бы чист и должен снова оказаться доступным и пропасть из вкладки уборки