Загрузка данных


import os
import tkinter as tk
from tkinter import messagebox, ttk

# ------------------------------------
import pandas as pd
from openpyxl import Workbook
from openpyxl.styles import Border, PatternFill, Protection, Side
from openpyxl.utils.dataframe import dataframe_to_rows

# --- ИСПРАВЛЕННЫЙ ИМПОРТ ---
# Теперь мы импортируем обе необходимые функции из базы данных
from modules.database_module import list_groups, list_indicators


def create_excel_template(groups_codes, output_filename):
    """
    Функция создаёт шаблон Excel-файла для заданных групп и сохраняет его.
    Теперь она берет значения ячеек из базы данных.
    """

    def protect_and_format(ws, start_col, matrix_size):
        blue_fill = PatternFill(
            start_color="ADD8E6", end_color="ADD8E6", fill_type="solid"
        )
        green_fill = PatternFill(
            start_color="90EE90", end_color="90EE90", fill_type="solid"
        )
        yellow_fill = PatternFill(
            start_color="FFFF00", end_color="FFFF00", fill_type="solid"
        )

        protection_locked = Protection(locked=True)
        protection_unlocked = Protection(locked=False)

        ws.protection.enable()

        for i in range(matrix_size):
            for j in range(i + 1, matrix_size):
                cell = ws.cell(row=i + 2, column=start_col + j)
                cell.fill = blue_fill
                cell.protection = protection_unlocked

        for i in range(matrix_size):
            for j in range(i):
                cell = ws.cell(row=i + 2, column=start_col + j)
                cell.fill = green_fill
                cell.protection = protection_locked

        for i in range(matrix_size):
            cell = ws.cell(row=i + 2, column=start_col + i)
            cell.fill = yellow_fill
            cell.protection = protection_locked

    def apply_borders(ws, start_col, matrix_size):
        thin_border = Border(
            left=Side(style="thin"),
            right=Side(style="thin"),
            top=Side(style="thin"),
            bottom=Side(style="thin"),
        )
        for i in range(matrix_size):
            for j in range(matrix_size):
                cell = ws.cell(row=i + 2, column=start_col + j)
                cell.border = thin_border

    wb = Workbook()
    all_groups = list_groups()

    for group_code in groups_codes:
        try:
            group = next(g for g in all_groups if g.code == group_code)
            indicators = list_indicators(group_code)

            if not indicators:
                continue

            sheet_title = f"{group.name}"
            ws = wb.create_sheet(title=sheet_title)

            # --- ЗАГОЛОВКИ ТАБЛИЦЫ ---
            ws.cell(row=1, column=1, value="№ п/п")
            ws.cell(row=1, column=2, value="Показатель")
            ws.cell(row=1, column=3, value="Код")

            # --- ЗАПОЛНЯЕМ ТАБЛИЦУ ПОКАЗАТЕЛЕЙ ---
            # Получаем список индикаторов один раз и сохраняем в переменную
            indicators_list = list_indicators(group_code)

            # Теперь работаем с сохраненным списком
            for idx, ind in enumerate(indicators_list):
                ws.cell(row=idx + 2, column=1, value=str(idx + 1))
                ws.cell(row=idx + 2, column=2, value=ind.name)
                ws.cell(row=idx + 2, column=3, value=ind.code)

            # --- ПОДГОТОВКА К СОЗДАНИЮ МАТРИЦЫ ---
            start_col = 4
            matrix_start_row = 1

            # Заголовки столбцов матрицы (коды показателей)
            for col_idx, label in enumerate([ind.code for ind in indicators]):
                ws.cell(row=matrix_start_row, column=start_col + col_idx, value=label)

            matrix_size = len(indicators)

            # --- СОЗДАЕМ СЛОВАРЬ ДЛЯ БЫСТРОГО ПОИСКА ЗНАЧЕНИЙ ИЗ БАЗЫ ---
            # Ключ: (row_index, col_index), Значение: значение из базы
            matrix_data_dict = {}
            for ind in indicators:
                for entry in ind.group.matrices:
                    # В базе индексы с 0, в Excel строки с 2 (из-за заголовков)
                    matrix_data_dict[(entry.row, entry.col)] = entry.value

            # --- ЗАПОЛНЯЕМ ЯЧЕЙКИ МАТРИЦЫ ДАННЫМИ ИЗ БАЗЫ ---
            for r_idx in range(matrix_size):
                for c_idx in range(matrix_size):
                    # Ищем значение в нашем словаре
                    db_value = matrix_data_dict.get((r_idx, c_idx))

                    if db_value is not None:
                        # Если значение в базе есть (не None) — пишем его
                        ws.cell(
                            row=matrix_start_row + r_idx + 1,
                            column=start_col + c_idx,
                            value=float(db_value),
                        )
                    elif r_idx == c_idx:
                        # Если значения нет и это диагональ — пишем 1.0
                        ws.cell(
                            row=matrix_start_row + r_idx + 1,
                            column=start_col + c_idx,
                            value=1.0,
                        )
                    else:
                        # Если значения нет и это не диагональ — оставляем
                        # пустой
                        ws.cell(
                            row=matrix_start_row + r_idx + 1,
                            column=start_col + c_idx,
                            value="",
                        )

            # Применяем стили и защиту
            protect_and_format(ws, start_col, matrix_size)
            apply_borders(ws, start_col, matrix_size)

        except StopIteration:
            pass
        except Exception as e:
            print(f"Ошибка при обработке группы '{group_code}': {e}")

    # Удаляем стандартный пустой лист 'Sheet'
    if "Sheet" in wb.sheetnames:
        del wb["Sheet"]

    # Сохраняем рабочую книгу
    wb.save(output_filename)


class ExportMatrixWindow(tk.Toplevel):
    def __init__(self, parent):
        super().__init__(parent)
        self.title("Создание файла для эксперта")
        self.geometry("450x200")

        main_frame = ttk.Frame(self)
        main_frame.pack(padx=10, pady=10, fill="both", expand=True)

        self.groups = []
        self.selected_groups = []
        self.num_experts = tk.IntVar()

        tk.Label(main_frame, text="Группа:").grid(row=0, column=0, sticky="w")
        self.group_var = tk.StringVar()
        self.combobox = ttk.Combobox(
            main_frame, textvariable=self.group_var, state="readonly"
        )
        self.combobox.grid(row=0, column=1, padx=(5, 10), sticky="ew")

        self.refresh_groups()

        add_group_btn = ttk.Button(
            main_frame, text="Добавить группу", command=self.add_group
        )
        add_group_btn.grid(row=0, column=2, padx=(0, 10), sticky="e")

        tk.Label(main_frame, text="Выбранные группы:").grid(row=1, column=0, sticky="w")
        self.selected_groups_text = tk.Text(main_frame, width=30, height=4)
        self.selected_groups_text.grid(
            row=1, column=1, columnspan=2, pady=(5, 10), sticky="ew"
        )

        tk.Label(main_frame, text="Количество экспертов:").grid(
            row=2, column=0, sticky="w"
        )
        self.experts_count_entry = ttk.Entry(main_frame, textvariable=self.num_experts)
        self.experts_count_entry.grid(row=2, column=1, sticky="w")

        remove_group_btn = ttk.Button(
            main_frame, text="Удалить группу", command=self.remove_group
        )
        remove_group_btn.grid(row=2, column=2, sticky="e")

        export_btn = ttk.Button(
            main_frame, text="Экспортировать в Excel", command=self.export_to_excel
        )
        export_btn.grid(row=3, column=1, pady=(10, 0))

    def refresh_groups(self):
        self.groups = [grp.name for grp in list_groups()]
        self.combobox.config(values=self.groups)

    def add_group(self):
        group_name = self.group_var.get()
        if group_name and group_name.strip():
            self.selected_groups.append(group_name)
            self.selected_groups_text.insert(tk.END, f"{group_name}\n")

    def remove_group(self):
        if len(self.selected_groups) > 0:
            last_group = self.selected_groups.pop(-1)
            current_text = self.selected_groups_text.get("1.0", tk.END).strip()
            updated_text = "\n".join(
                line for line in current_text.split("\n") if line != last_group
            )
            self.selected_groups_text.delete("1.0", tk.END)
            self.selected_groups_text.insert(tk.END, updated_text)

    def export_to_excel(self):
        """Логика экспорта в Excel (ИСПРАВЛЕННАЯ ВЕРСИЯ)."""
        # Получаем список названий групп из текстового поля
        selected_group_names = (
            self.selected_groups_text.get("1.0", tk.END).strip().split("\n")
        )

        # --- ЭТОТ БЛОК ТЕПЕРЬ ВЫПОЛНЯЕТСЯ ТОЛЬКО ОДИН РАЗ ---
        # Составляем список кодов групп на основе выбранных названий
        groups_codes = []
        all_db_groups = list_groups()
        for name in selected_group_names:
            if name:  # Проверяем, что строка не пустая
                group = next((g for g in all_db_groups if g.name == name), None)
                if group:
                    groups_codes.append(group.code)

        # Если список пуст, выходим
        if not groups_codes:
            messagebox.showwarning("Предупреждение", "Не выбрано ни одной группы.")
            return
        # ----------------------------------------------------

        # Получаем количество экспертов
        try:
            num_experts = int(self.num_experts.get())
            if num_experts <= 0:
                raise ValueError
        except Exception:
            messagebox.showerror(
                "Ошибка", "Количество экспертов должно быть положительным числом."
            )
            return

        # Каталог для сохранения файлов экспертов
        experts_folder = os.path.join(os.path.dirname(__file__), "..", "experts")
        os.makedirs(experts_folder, exist_ok=True)

        # Генерируем файлы для каждого эксперта, используя уже готовый список
        # groups_codes
        for expert_num in range(1, num_experts + 1):
            output_filename = os.path.join(experts_folder, f"Эксперт_{expert_num}.xlsx")
            create_excel_template(groups_codes, output_filename)

        messagebox.showinfo(
            title="Экспорт завершён",
            message=f"Успешно создано {num_experts} файлов экспертов.\n\nРасположение файлов:\n{experts_folder}",
        )