// 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 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(1000, 700);
        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[]{"Free", "Busy"});
        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[]{"Free", "Busy"});
        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", "Номер", "Доступен", "Статус", "Цена", "Тип кровати", "Тип номера", "Админ ID", "Ресепшионист 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, available, status, price, bed_type, room_type, admin_id, receptionist_id, 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.getBoolean("available") ? "Да" : "Нет");
                row.add(rs.getString("status"));
                row.add(rs.getDouble("price")); // Изменено на getDouble
                row.add(rs.getString("bed_type"));
                row.add(rs.getString("room_type"));
                row.add(rs.getObject("admin_id") != null ? rs.getInt("admin_id") : "NULL");
                row.add(rs.getObject("receptionist_id") != null ? rs.getInt("receptionist_id") : "NULL");
                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, 600);
        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 availableLabel = new JLabel("Доступен:");
        JCheckBox availableCheck = new JCheckBox("Да", true);
        JLabel statusLabel = new JLabel("Статус:");
        JComboBox<String> statusComboBox = new JComboBox<>(new String[]{"Available", "Occupied", "Maintenance"});
        JLabel priceLabel = new JLabel("Цена:");
        JTextField priceField = new JTextField(20);
        JLabel bedTypeLabel = new JLabel("Тип кровати:");
        JComboBox<String> bedTypeComboBox = new JComboBox<>(new String[]{"Single", "Double", "Queen", "King", "Twin"});
        JLabel roomTypeLabel = new JLabel("Тип номера:");
        JTextField roomTypeField = new JTextField(20);
        JLabel adminIdLabel = new JLabel("ID Администратора:");
        JTextField adminIdField = new JTextField(20);
        JLabel receptionistIdLabel = new JLabel("ID Ресепшиониста:");
        JTextField receptionistIdField = new JTextField(20);

        // Кнопки
        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(availableLabel, gbc);
        gbc.gridx = 1;
        dialog.add(availableCheck, 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(roomTypeField, gbc);

        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(adminIdLabel, gbc);
        gbc.gridx = 1;
        dialog.add(adminIdField, gbc);

        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(receptionistIdLabel, gbc);
        gbc.gridx = 1;
        dialog.add(receptionistIdField, 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();
            boolean available = availableCheck.isSelected();
            String status = (String) statusComboBox.getSelectedItem();
            String priceStr = priceField.getText().trim();
            String bedType = (String) bedTypeComboBox.getSelectedItem();
            String roomType = roomTypeField.getText().trim();
            String adminIdStr = adminIdField.getText().trim();
            String receptionistIdStr = receptionistIdField.getText().trim();

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

            try {
                int roomNumber = Integer.parseInt(roomNumberStr);
                double price = Double.parseDouble(priceStr);
                Integer adminId = adminIdStr.isEmpty() ? null : Integer.parseInt(adminIdStr);
                Integer receptionistId = receptionistIdStr.isEmpty() ? null : Integer.parseInt(receptionistIdStr);

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

                String query = "INSERT INTO Rooms (room_number, available, status, price, bed_type, room_type, admin_id, receptionist_id, created_at, updated_at) "
                        + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, NOW(), NOW())";
                PreparedStatement pstmt = conn.prepareStatement(query);
                pstmt.setInt(1, roomNumber);
                pstmt.setBoolean(2, available);
                pstmt.setString(3, status);
                pstmt.setDouble(4, price);
                pstmt.setString(5, bedType);
                pstmt.setString(6, roomType);
                if (adminId != null) {
                    pstmt.setInt(7, adminId);
                } else {
                    pstmt.setNull(7, Types.INTEGER);
                }
                if (receptionistId != null) {
                    pstmt.setInt(8, receptionistId);
                } else {
                    pstmt.setNull(8, Types.INTEGER);
                }

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

                JOptionPane.showMessageDialog(dialog, "Номер добавлен успешно.");
                dialog.dispose();
                loadRooms();
            } catch (NumberFormatException ex) {
                JOptionPane.showMessageDialog(dialog, "Пожалуйста, введите корректные числовые значения для номера, цены и ID.", "Ошибка", JOptionPane.ERROR_MESSAGE);
            } catch (SQLIntegrityConstraintViolationException ex) {
                JOptionPane.showMessageDialog(dialog, "Номер комнаты уже существует или указанные admin_id/receptionist_id не существуют!", "Ошибка", 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 availableStr = (String) roomsModel.getValueAt(selectedRow, 2);
        String status = (String) roomsModel.getValueAt(selectedRow, 3);
        Object priceObj = roomsModel.getValueAt(selectedRow, 4);
        double price = 0.0;
        if (priceObj instanceof Double) {
            price = (Double) priceObj;
        } else if (priceObj instanceof Number) {
            price = ((Number) priceObj).doubleValue();
        } else {
            try {
                price = Double.parseDouble(priceObj.toString());
            } catch (NumberFormatException e) {
                e.printStackTrace();
                JOptionPane.showMessageDialog(this, "Некорректное значение цены.", "Ошибка", JOptionPane.ERROR_MESSAGE);
                return;
            }
        }
        String bedType = (String) roomsModel.getValueAt(selectedRow, 5);
        String roomType = (String) roomsModel.getValueAt(selectedRow, 6);
        Object adminIdObj = roomsModel.getValueAt(selectedRow, 7);
        Object receptionistIdObj = roomsModel.getValueAt(selectedRow, 8);

        String adminIdStr = adminIdObj instanceof Integer ? String.valueOf(adminIdObj) : "";
        String receptionistIdStr = receptionistIdObj instanceof Integer ? String.valueOf(receptionistIdObj) : "";

        JDialog dialog = new JDialog(this, "Редактировать Номер", true);
        dialog.setSize(400, 600);
        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 availableLabel = new JLabel("Доступен:");
        JCheckBox availableCheck = new JCheckBox("Да", availableStr.equals("Да"));
        JLabel statusLabel = new JLabel("Статус:");
        JComboBox<String> statusComboBox = new JComboBox<>(new String[]{"Available", "Occupied", "Maintenance"});
        statusComboBox.setSelectedItem(status);
        JLabel priceLabel = new JLabel("Цена:");
        JTextField priceField = new JTextField(String.valueOf(price), 20);
        JLabel bedTypeLabel = new JLabel("Тип кровати:");
        JComboBox<String> bedTypeComboBox = new JComboBox<>(new String[]{"Single", "Double", "Queen", "King", "Twin"});
        bedTypeComboBox.setSelectedItem(bedType);
        JLabel roomTypeLabel = new JLabel("Тип номера:");
        JTextField roomTypeField = new JTextField(roomType, 20);
        JLabel adminIdLabel = new JLabel("ID Администратора:");
        JTextField adminIdField = new JTextField(adminIdStr, 20);
        JLabel receptionistIdLabel = new JLabel("ID Ресепшиониста:");
        JTextField receptionistIdField = new JTextField(receptionistIdStr, 20);

        // Кнопки
        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(availableLabel, gbc);
        gbc.gridx = 1;
        dialog.add(availableCheck, 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(roomTypeField, gbc);

        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(adminIdLabel, gbc);
        gbc.gridx = 1;
        dialog.add(adminIdField, gbc);

        gbc.gridx = 0;
        gbc.gridy++;
        dialog.add(receptionistIdLabel, gbc);
        gbc.gridx = 1;
        dialog.add(receptionistIdField, 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();
            boolean available = availableCheck.isSelected();
            String currentStatus = (String) statusComboBox.getSelectedItem();
            String priceStr = priceField.getText().trim();
            String bedTypeNew = (String) bedTypeComboBox.getSelectedItem();
            String roomTypeNew = roomTypeField.getText().trim();
            String adminIdNewStr = adminIdField.getText().trim();
            String receptionistIdNewStr = receptionistIdField.getText().trim();

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

            try {
                int roomNumberParsed = Integer.parseInt(roomNumberStr);
                double priceParsed = Double.parseDouble(priceStr);
                Integer adminIdNew = adminIdNewStr.isEmpty() ? null : Integer.parseInt(adminIdNewStr);
                Integer receptionistIdNew = receptionistIdNewStr.isEmpty() ? null : Integer.parseInt(receptionistIdNewStr);

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

                String query = "UPDATE Rooms SET room_number = ?, available = ?, status = ?, price = ?, bed_type = ?, room_type = ?, admin_id = ?, receptionist_id = ?, updated_at = NOW() WHERE room_id = ?";
                PreparedStatement pstmt = conn.prepareStatement(query);
                pstmt.setInt(1, roomNumberParsed);
                pstmt.setBoolean(2, available);
                pstmt.setString(3, currentStatus);
                pstmt.setDouble(4, priceParsed);
                pstmt.setString(5, bedTypeNew);
                pstmt.setString(6, roomTypeNew);
                if (adminIdNew != null) {
                    pstmt.setInt(7, adminIdNew);
                } else {
                    pstmt.setNull(7, Types.INTEGER);
                }
                if (receptionistIdNew != null) {
                    pstmt.setInt(8, receptionistIdNew);
                } else {
                    pstmt.setNull(8, Types.INTEGER);
                }
                pstmt.setInt(9, roomId);

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

                JOptionPane.showMessageDialog(dialog, "Номер обновлен успешно.");
                dialog.dispose();
                loadRooms();
            } catch (NumberFormatException ex) {
                JOptionPane.showMessageDialog(dialog, "Пожалуйста, введите корректные числовые значения для номера, цены и ID.", "Ошибка", JOptionPane.ERROR_MESSAGE);
            } catch (SQLIntegrityConstraintViolationException ex) {
                JOptionPane.showMessageDialog(dialog, "Номер комнаты уже существует или указанные admin_id/receptionist_id не существуют!", "Ошибка", 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));
    }
}













// 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 (?, ?, ?, ?, 'Booked', ?, ?, 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();
            String query = "SELECT room_number FROM Rooms WHERE available = TRUE AND status = 'Available'";
            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[]{"Booked", "Checked-in", "Checked-out", "Cancelled"});
        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("Cancelled")) {
            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 = 'Cancelled', 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
    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("Checked-in")) {
            JOptionPane.showMessageDialog(this, "Клиент уже заселен.", "Информация", JOptionPane.INFORMATION_MESSAGE);
            return;
        }

        if (!status.equals("Booked")) {
            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 = 'Checked-in', updated_at = NOW() WHERE reservation_id = ?";
            PreparedStatement pstmt1 = conn.prepareStatement(updateReservation);
            pstmt1.setInt(1, reservationId);
            pstmt1.executeUpdate();

            // Обновление статуса номера
            String updateRoom = "UPDATE Rooms SET available = FALSE, status = 'Occupied' 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("Checked-in")) {
            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 = 'Checked-out', updated_at = NOW() WHERE reservation_id = ?";
            PreparedStatement pstmt1 = conn.prepareStatement(updateReservation);
            pstmt1.setInt(1, reservationId);
            pstmt1.executeUpdate();

            // Обновление статуса номера
            String updateRoom = "UPDATE Rooms SET available = TRUE, status = 'Available' 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[]{"Male", "Female", "Other"});
        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[]{"Male", "Female", "Other"});
        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
    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 Номера", "Номер", "Доступен", "Статус", "Цена", "Тип кровати", "Тип номера", "Админ ID", "Ресепшионист 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();
            String query = "SELECT room_id, room_number, available, status, price, bed_type, room_type, admin_id, receptionist_id, 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.getBoolean("available") ? "Да" : "Нет");
                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.getObject("admin_id") != null ? rs.getInt("admin_id") : "NULL");
                row.add(rs.getObject("receptionist_id") != null ? rs.getInt("receptionist_id") : "NULL");
                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));
    }
}





















// 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 JComboBox<String> roleComboBox;
    private JTextField nameField, passportField, addressField, phoneField, emailField, loginField;
    private JPasswordField passwordField;
    private JTextField regCodeField;
    private JLabel regCodeLabel; // Объявляем как поле класса
    private JCheckBox showPasswordCheck;
    private JButton signupButton, cancelButton;
    private JButton loginLink;

    // Предопределенный код регистрации для администратора
    private static final String ADMIN_REG_CODE = "ADMIN2023"; // Измените этот код на нужный вам

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

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

        // Выбор роли
        JLabel roleLabel = new JLabel("Роль:");
        gbc.gridx = 0;
        gbc.gridy = 0;
        gbc.insets = new Insets(5,5,5,5);
        panel.add(roleLabel, gbc);

        roleComboBox = new JComboBox<>(new String[]{"Ресепшионист", "Администратор"});
        gbc.gridx = 1;
        panel.add(roleComboBox, gbc);
        roleComboBox.addActionListener(this);

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

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

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

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

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

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

        // Телефон
        JLabel phoneLabel = new JLabel("Телефон:");
        gbc.gridx = 0;
        gbc.gridy = 4;
        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 = 5;
        panel.add(emailLabel, gbc);

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

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

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

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

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

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

        // Поле для кода регистрации (только для администратора)
        regCodeLabel = new JLabel("Код регистрации:");
        gbc.gridx = 0;
        gbc.gridy = 9;
        regCodeLabel.setVisible(false); // Изначально скрыто
        panel.add(regCodeLabel, gbc);

        regCodeField = new JTextField(20);
        gbc.gridx = 1;
        regCodeField.setVisible(false); // Изначально скрыто
        panel.add(regCodeField, gbc);

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

        cancelButton = new JButton("Отмена");
        gbc.gridy = 11;
        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 = 12;
        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 == roleComboBox) {
            String selectedRole = (String) roleComboBox.getSelectedItem();
            boolean isAdmin = selectedRole.equals("Администратор");

            // Показать или скрыть поле кода регистрации
            regCodeLabel.setVisible(isAdmin);
            regCodeField.setVisible(isAdmin);
            this.revalidate();
            this.repaint();
        }

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

        if (source == signupButton) {
            String role = (String) roleComboBox.getSelectedItem();
            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();
            String regCode = regCodeField.getText().trim();

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

            if (role.equals("Администратор")) {
                if (regCode.isEmpty()) {
                    JOptionPane.showMessageDialog(this, "Пожалуйста, введите код регистрации для администратора.", "Ошибка", JOptionPane.ERROR_MESSAGE);
                    return;
                }
                if (!regCode.equals(ADMIN_REG_CODE)) {
                    JOptionPane.showMessageDialog(this, "Неверный код регистрации.", "Ошибка", JOptionPane.ERROR_MESSAGE);
                    return;
                }
            }

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

                String tableName = role.equals("Администратор") ? "Administrators" : "Receptionists";
                String query;
                if (role.equals("Администратор")) {
                    query = "INSERT INTO Administrators (full_name, passport_number, address, phone_number, email, login, password, registration_code, created_at, updated_at) "
                            + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, NOW(), NOW())";
                } else {
                    // Для ресепшиониста admin_id должен быть указан администратором
                    // Здесь мы предполагаем, что администратор с admin_id = 1 существует
                    // В реальной системе лучше выбирать или определять администратора динамически
                    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, passportNumber);
                pstmt.setString(3, address);
                pstmt.setString(4, phone);
                pstmt.setString(5, email);
                pstmt.setString(6, login);
                pstmt.setString(7, hashPassword(password));

                if (role.equals("Администратор")) {
                    pstmt.setString(8, regCode);
                } else {
                    // Устанавливаем admin_id. Предполагаем, что администратор с admin_id = 1 существует
                    pstmt.setInt(8, 1); // Измените это значение в соответствии с вашей логикой
                }

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

            } 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();
    }
}














-- Создание базы данных
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
) VALUES (
    'Иванов Иван Иванович',
    '4510 123456',
    'г. Москва, ул. Ленина, д. 1, кв. 1',
    '+7(999)123-45-67',
    'ivanov@hotel.ru',
    'admin',
    '$2a$12$LQv3c1yqBWVHxkd0LHAkCOYz6TtxMQJqhN8/LewandQ3REH3P5DOK' -- хешированный пароль "admin123"
);












-- Добавление комнат
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);


поменяй коды все что надо для полноценной функциональности  
также я хочу чтобы в окне регистрации администратор только мог сам зарегистрироваться а уже потом он сможет регистрировать ресепшионистов чтобы они могли заходить в свой dashboard

напиши полные коды для этого