#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
================================================================================
Модуль: Плотность заказов (УрФУ)
================================================================================
Анализ эффективности маршрутов и плотности заказов по регионам
================================================================================
"""

from PyQt5.QtWidgets import (
    QWidget, QVBoxLayout, QHBoxLayout, QLabel,
    QLineEdit, QPushButton, QGroupBox, QGridLayout,
    QDoubleSpinBox, QSpinBox, QComboBox, QMessageBox, QFrame,
    QScrollArea, QMainWindow, QApplication, QFileDialog,
    QTableWidget, QTableWidgetItem, QHeaderView, QTextEdit,
    QDialog, QDialogButtonBox, QTextBrowser  # Добавлено для справки
)
from PyQt5.QtCore import Qt, QTimer
from PyQt5.QtGui import QColor, QBrush, QFont, QPixmap, QPainter
from datetime import datetime
import math

# Попытка импорта openpyxl для Excel
try:
    import openpyxl
    from openpyxl.styles import Font, PatternFill, Alignment, Border, Side
    from openpyxl.chart import BarChart, Reference, Series
    EXCEL_AVAILABLE = True
except ImportError:
    EXCEL_AVAILABLE = False


# ========== ДИАЛОГ СПРАВКИ ПО ПЛОТНОСТИ ЗАКАЗОВ ==========

class DensityHelpDialog(QDialog):
    """Справка по использованию калькулятора плотности заказов"""
    
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setWindowTitle("📊 Справка: Плотность заказов")
        self.setMinimumSize(700, 600)
        self.setup_ui()
    
    def setup_ui(self):
        layout = QVBoxLayout(self)
        layout.setSpacing(15)
        
        # Заголовок
        title = QLabel("📊 ПЛОТНОСТЬ ЗАКАЗОВ - РУКОВОДСТВО")
        title.setStyleSheet("""
            font-size: 20px;
            font-weight: bold;
            color: white;
            background-color: #1976D2;
            padding: 12px;
            border-radius: 8px;
            border: 2px solid #0D47A1;
        """)
        title.setAlignment(Qt.AlignCenter)
        layout.addWidget(title)
        
        # Текст справки
        text = QTextBrowser()
        text.setStyleSheet("""
            QTextBrowser {
                background-color: #f9f9f9;
                border: 2px solid #c0c0c0;
                border-radius: 8px;
                padding: 15px;
                font-size: 11pt;
                line-height: 1.6;
            }
        """)
        
        html = """
        <style>
            h2 { color: #1976D2; margin-top: 15px; border-bottom: 2px solid #1976D2; }
            h3 { color: #2E7D32; margin-top: 10px; }
            .note { background-color: #fff3cd; border-left: 4px solid #ffc107; padding: 10px; margin: 10px 0; }
            .example { background-color: #e8f0fe; border-left: 4px solid #1976D2; padding: 10px; margin: 10px 0; }
            table { border-collapse: collapse; width: 100%; margin: 10px 0; }
            th { background-color: #1976D2; color: white; padding: 8px; text-align: left; }
            td { border: 1px solid #ddd; padding: 8px; }
        </style>
        
        <h2>📊 О МЕТОДИКЕ</h2>
        <p><b>Плотность заказов</b> — это показатель, разработанный УрФУ для оценки эффективности 
        логистических маршрутов. Он учитывает:</p>
        <ul>
            <li>Базовую плотность регионов отправления и назначения</li>
            <li>Количество заказов в месяц</li>
            <li>Средний вес заказа</li>
            <li>Средний километраж</li>
            <li>Уровень конкуренции в регионе</li>
        </ul>
        
        <h2>📋 ПАРАМЕТРЫ РАСЧЕТА</h2>
        
        <h3>📍 Регионы</h3>
        <p>В справочнике представлены регионы УрФУ с базовой плотностью:</p>
        <table>
            <tr><th>Регион</th><th>Базовая плотность</th><th>Уровень</th></tr>
            <tr><td>Екатеринбург</td><td>85%</td><td>🟢 ВЫСОКИЙ</td></tr>
            <tr><td>Тюмень</td><td>72%</td><td>🟢 ВЫСОКИЙ</td></tr>
            <tr><td>Челябинск</td><td>68%</td><td>🟡 СРЕДНИЙ</td></tr>
            <tr><td>Курган</td><td>45%</td><td>🟡 СРЕДНИЙ</td></tr>
            <tr><td>Сургут</td><td>38%</td><td>🔴 НИЗКИЙ</td></tr>
            <tr><td>Новый Уренгой</td><td>22%</td><td>🔴 НИЗКИЙ</td></tr>
        </table>
        <p><i>✏️ Можно вводить свои регионы — для них плотность принимается 50%.</i></p>
        
        <h3>📦 Заказов в месяц</h3>
        <p>Чем больше заказов, тем выше плотность. Оптимально: <b>от 50 заказов</b>.</p>
        
        <h3>⚖️ Средний вес заказа</h3>
        <p>Влияет на загрузку транспорта. Оптимально: <b>15-20 тонн</b>.</p>
        
        <h3>📏 Средний километраж</h3>
        <p>Короткие маршруты (до 300 км) дают бóльшую плотность.</p>
        
        <h3>🏢 Уровень конкуренции</h3>
        <ul>
            <li><b>Низкий:</b> +20% к плотности</li>
            <li><b>Средний:</b> базовый уровень</li>
            <li><b>Высокий:</b> -20% к плотности</li>
            <li><b>Очень высокий:</b> -50% к плотности</li>
        </ul>
        
        <h2>📊 ИНТЕРПРЕТАЦИЯ РЕЗУЛЬТАТОВ</h2>
        
        <div class="note">
            <b>🟢 80-100% — ВЫСОКАЯ ПЛОТНОСТЬ</b><br>
            Отличный маршрут! Минимум порожних пробегов, стабильная загрузка.
            Рекомендация: увеличить частоту рейсов, добавить дополнительные точки.
        </div>
        
        <div class="note">
            <b>🟡 40-79% — СРЕДНЯЯ ПЛОТНОСТЬ</b><br>
            Рабочий маршрут с потенциалом роста.
            Рекомендация: проанализировать возможность обратных загрузок.
        </div>
        
        <div class="note">
            <b>🔴 0-39% — НИЗКАЯ ПЛОТНОСТЬ</b><br>
            Высокий риск порожних пробегов.
            Рекомендация: рассмотреть другие направления или кооперацию.
        </div>
        
        <h2>💡 ПРИМЕР РАСЧЕТА</h2>
        <div class="example">
            <b>Маршрут:</b> Екатеринбург → Тюмень<br>
            <b>Заказов:</b> 80 в месяц<br>
            <b>Вес:</b> 18 т<br>
            <b>Километраж:</b> 350 км<br>
            <b>Конкуренция:</b> Средняя<br><br>
            <b>Результат:</b> Плотность 74.5% (СРЕДНЯЯ)<br>
            <i>Маршрут эффективен, но стоит поискать обратную загрузку.</i>
        </div>
        
        <h2>📈 КАРТА ПЛОТНОСТИ</h2>
        <p>Справа отображается текстовая карта, где:</p>
        <ul>
            <li><b>█</b> — высокая плотность</li>
            <li><b>░</b> — низкая плотность</li>
            <li>Топ-5 регионов с их базовой плотностью</li>
        </ul>
        """
        
        text.setHtml(html)
        layout.addWidget(text)
        
        # Кнопка закрытия
        btn = QDialogButtonBox(QDialogButtonBox.Ok)
        btn.accepted.connect(self.accept)
        btn.setStyleSheet("""
            QPushButton {
                background-color: #1976D2;
                color: white;
                border: none;
                border-radius: 5px;
                padding: 8px 20px;
                font-size: 12pt;
                font-weight: bold;
            }
            QPushButton:hover {
                background-color: #1565C0;
            }
        """)
        layout.addWidget(btn)


class OrderDensityModule:
    """Класс модуля для ModuleManager"""

    display_name = "📊 Плотность заказов (УрФУ)"
    description = "Анализ эффективности маршрутов и плотности заказов"

    def __init__(self, main_window):
        self.main_window = main_window
        self.widget = None
        self.window = None

    def run(self):
        """Запуск модуля — открывает интерфейс в отдельном окне"""
        self.widget = OrderDensityWidget(self.main_window, self)

        self.window = QMainWindow()
        self.window.setWindowTitle(f"{self.display_name} - РейсМастер")
        self.window.setWindowIcon(self.main_window.windowIcon())
        self.window.setCentralWidget(self.widget)
        self.window.resize(1600, 1000)
        self.window.setMinimumSize(1400, 900)
        self.window.show()


class OrderDensityWidget(QWidget):
    """Интерфейс калькулятора плотности заказов"""

    # Справочник регионов УрФУ
    REGIONS = {
        "Екатеринбург": {"base_density": 85, "color": "#2E7D32"},
        "Тюмень": {"base_density": 72, "color": "#1976D2"},
        "Челябинск": {"base_density": 68, "color": "#1976D2"},
        "Курган": {"base_density": 45, "color": "#F57C00"},
        "Сургут": {"base_density": 38, "color": "#F57C00"},
        "Нижневартовск": {"base_density": 35, "color": "#F57C00"},
        "Нефтеюганск": {"base_density": 32, "color": "#F57C00"},
        "Новый Уренгой": {"base_density": 22, "color": "#C41E3A"},
        "Ноябрьск": {"base_density": 28, "color": "#F57C00"},
        "Салехард": {"base_density": 15, "color": "#C41E3A"},
        "Ханты-Мансийск": {"base_density": 30, "color": "#F57C00"},
    }

    def __init__(self, main_window, module):
        super().__init__()
        self.main_window = main_window
        self.module = module

        # Данные для сохранения
        self.last_result = ""
        self.last_params = None

        self.setup_ui()
        self.connect_signals()
        self.update_preview()

    def get_region_density(self, region_name):
        """Получает плотность региона (для известных возвращает базовую, для своих - среднюю)"""
        if region_name in self.REGIONS:
            return self.REGIONS[region_name]["base_density"]
        else:
            # Для своих регионов возвращаем среднюю плотность 50%
            return 50

    def setup_ui(self):
        """Создание интерфейса"""
        main_layout = QVBoxLayout(self)
        main_layout.setContentsMargins(0, 0, 0, 0)

        # Создаем область прокрутки для всего окна
        scroll_area = QScrollArea()
        scroll_area.setWidgetResizable(True)
        scroll_area.setFrameShape(QFrame.NoFrame)
        scroll_area.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
        scroll_area.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
        scroll_area.setStyleSheet("""
            QScrollArea {
                border: none;
                background-color: #f0f0f0;
            }
            QScrollBar:vertical {
                border: none;
                background-color: #e0e0e0;
                width: 16px;
                border-radius: 0px;
            }
            QScrollBar::handle:vertical {
                background-color: #c0c0c0;
                min-height: 30px;
                border-radius: 0px;
            }
            QScrollBar::handle:vertical:hover {
                background-color: #a0a0a0;
            }
        """)

        # Контейнер для всего содержимого
        container = QWidget()
        container.setStyleSheet("background-color: #f0f0f0;")
        container_layout = QVBoxLayout(container)
        container_layout.setSpacing(20)
        container_layout.setContentsMargins(25, 25, 25, 25)

        # === ЗАГОЛОВОК С КНОПКОЙ СПРАВКИ ===
        header_layout = QHBoxLayout()
        
        title_label = QLabel("📊 ПЛОТНОСТЬ ЗАКАЗОВ (УрФУ)")
        title_label.setStyleSheet("""
            QLabel {
                font-size: 26px;
                font-weight: bold;
                color: white;
                background-color: #1976D2;
                padding: 12px 20px;
                border-radius: 8px;
                border: 2px solid #0D47A1;
            }
        """)
        title_label.setAlignment(Qt.AlignCenter)
        header_layout.addWidget(title_label, 1)
        
        self.help_btn = QPushButton("📚 СПРАВКА")
        self.help_btn.setFixedSize(150, 50)
        self.help_btn.setStyleSheet("""
            QPushButton {
                background-color: #FFA000;
                color: white;
                border: none;
                border-radius: 8px;
                font-size: 14px;
                font-weight: bold;
            }
            QPushButton:hover {
                background-color: #FF8F00;
            }
        """)
        self.help_btn.clicked.connect(self.show_help)
        header_layout.addWidget(self.help_btn)
        
        container_layout.addLayout(header_layout)

        # === ПАРАМЕТРЫ АНАЛИЗА ===
        params_group = QGroupBox("📋 ПАРАМЕТРЫ АНАЛИЗА")
        params_group.setStyleSheet("""
            QGroupBox {
                font-size: 18px;
                font-weight: bold;
                border: 2px solid #1976D2;
                border-radius: 8px;
                margin-top: 20px;
                padding-top: 25px;
                background-color: white;
            }
            QGroupBox::title {
                subcontrol-origin: margin;
                left: 25px;
                padding: 0 20px 0 20px;
                color: #1976D2;
                background-color: white;
                border: 1px solid #1976D2;
                border-radius: 4px;
            }
        """)
        params_layout = QGridLayout(params_group)
        params_layout.setVerticalSpacing(15)
        params_layout.setHorizontalSpacing(30)
        params_layout.setContentsMargins(30, 30, 30, 30)

        # === ПРОСТЕЙШИЙ СТИЛЬ ДЛЯ КОМБОБОКСОВ (СТРЕЛКИ ТОЧНО БУДУТ) ===
        combo_style = """
            QComboBox {
                font-size: 14px;
                padding: 8px 12px;
                border: 1px solid #c0c0c0;
                border-radius: 4px;
                min-height: 20px;
                background-color: white;
                color: #2C3E50;
            }
            QComboBox:hover {
                border: 1px solid #1976D2;
            }
            QComboBox QAbstractItemView {
                font-size: 14px;
                background-color: white;
                border: 1px solid #c0c0c0;
                selection-background-color: #1976D2;
                selection-color: white;
            }
        """

        # Стиль для SpinBox
        spin_style = """
            QSpinBox, QDoubleSpinBox {
                font-size: 14px;
                padding: 8px 12px;
                border: 1px solid #c0c0c0;
                border-radius: 4px;
                min-height: 20px;
                background-color: white;
                color: #2C3E50;
            }
            QSpinBox:hover, QDoubleSpinBox:hover {
                border: 1px solid #1976D2;
            }
        """

        # Стиль для подписей
        label_style = "font-size: 14px; font-weight: bold; color: #2C3E50; padding: 5px;"

        # Настройка растяжения колонок
        params_layout.setColumnStretch(0, 0)
        params_layout.setColumnStretch(1, 1)

        # Регион отправления
        label = QLabel("📍 Регион отправления:")
        label.setStyleSheet(label_style)
        params_layout.addWidget(label, 0, 0)

        self.start_region = QComboBox()
        self.start_region.setEditable(True)
        self.start_region.addItems(sorted(self.REGIONS.keys()))
        self.start_region.setCurrentText("Екатеринбург")
        self.start_region.setMinimumHeight(40)
        self.start_region.setMinimumWidth(350)
        self.start_region.setStyleSheet(combo_style)
        self.start_region.setMaxVisibleItems(10)
        params_layout.addWidget(self.start_region, 0, 1)

        # Регион назначения
        label = QLabel("📍 Регион назначения:")
        label.setStyleSheet(label_style)
        params_layout.addWidget(label, 1, 0)

        self.end_region = QComboBox()
        self.end_region.setEditable(True)
        self.end_region.addItems(sorted(self.REGIONS.keys()))
        self.end_region.setCurrentText("Тюмень")
        self.end_region.setMinimumHeight(40)
        self.end_region.setMinimumWidth(350)
        self.end_region.setStyleSheet(combo_style)
        self.end_region.setMaxVisibleItems(10)
        params_layout.addWidget(self.end_region, 1, 1)

        # Количество заказов
        label = QLabel("📦 Заказов в месяц:")
        label.setStyleSheet(label_style)
        params_layout.addWidget(label, 2, 0)

        self.monthly_orders = QSpinBox()
        self.monthly_orders.setRange(1, 1000)
        self.monthly_orders.setValue(50)
        self.monthly_orders.setSuffix(" шт")
        self.monthly_orders.setMinimumHeight(40)
        self.monthly_orders.setMinimumWidth(350)
        self.monthly_orders.setStyleSheet(spin_style)
        params_layout.addWidget(self.monthly_orders, 2, 1)

        # Средний вес
        label = QLabel("⚖️ Средний вес заказа:")
        label.setStyleSheet(label_style)
        params_layout.addWidget(label, 3, 0)

        self.avg_weight = QDoubleSpinBox()
        self.avg_weight.setRange(0.1, 100)
        self.avg_weight.setValue(15.0)
        self.avg_weight.setDecimals(1)
        self.avg_weight.setSuffix(" т")
        self.avg_weight.setMinimumHeight(40)
        self.avg_weight.setMinimumWidth(350)
        self.avg_weight.setStyleSheet(spin_style)
        params_layout.addWidget(self.avg_weight, 3, 1)

        # Средний километраж
        label = QLabel("📏 Средний километраж:")
        label.setStyleSheet(label_style)
        params_layout.addWidget(label, 4, 0)

        self.avg_distance = QSpinBox()
        self.avg_distance.setRange(10, 3000)
        self.avg_distance.setValue(350)
        self.avg_distance.setSuffix(" км")
        self.avg_distance.setMinimumHeight(40)
        self.avg_distance.setMinimumWidth(350)
        self.avg_distance.setStyleSheet(spin_style)
        params_layout.addWidget(self.avg_distance, 4, 1)

        # Уровень конкуренции
        label = QLabel("🏢 Уровень конкуренции:")
        label.setStyleSheet(label_style)
        params_layout.addWidget(label, 5, 0)

        self.competition = QComboBox()
        self.competition.addItems(["Низкий", "Средний", "Высокий", "Очень высокий"])
        self.competition.setCurrentIndex(1)
        self.competition.setMinimumHeight(40)
        self.competition.setMinimumWidth(350)
        self.competition.setStyleSheet(combo_style)
        self.competition.setMaxVisibleItems(4)
        params_layout.addWidget(self.competition, 5, 1)

        container_layout.addWidget(params_group)

        # === БЛОК РЕЗУЛЬТАТОВ ===
        results_row = QHBoxLayout()
        results_row.setSpacing(20)

        # Левая колонка - таблица результатов
        left_column = QVBoxLayout()

        results_group = QGroupBox("📊 РЕЗУЛЬТАТЫ АНАЛИЗА")
        results_group.setStyleSheet("""
            QGroupBox {
                font-size: 18px;
                font-weight: bold;
                border: 2px solid #2E7D32;
                border-radius: 8px;
                margin-top: 15px;
                padding-top: 25px;
                background-color: white;
            }
            QGroupBox::title {
                subcontrol-origin: margin;
                left: 25px;
                padding: 0 20px 0 20px;
                color: #2E7D32;
                background-color: white;
                border: 1px solid #2E7D32;
                border-radius: 4px;
            }
        """)
        results_layout = QVBoxLayout(results_group)
        results_layout.setSpacing(15)
        results_layout.setContentsMargins(20, 20, 20, 20)

        # Основной показатель плотности
        self.density_label = QLabel()
        self.density_label.setMinimumHeight(100)
        self.density_label.setStyleSheet("""
            QLabel {
                background-color: #e8f0fe;
                border: 1px solid #2E7D32;
                border-radius: 4px;
                padding: 15px;
                font-size: 14px;
                line-height: 1.6;
            }
        """)
        self.density_label.setWordWrap(True)
        results_layout.addWidget(self.density_label)

        # Таблица детализации
        self.results_table = QTableWidget()
        self.results_table.setColumnCount(4)
        self.results_table.setHorizontalHeaderLabels(["Показатель", "Значение", "Оценка", "Рекомендация"])
        self.results_table.horizontalHeader().setStretchLastSection(True)
        self.results_table.setAlternatingRowColors(True)
        self.results_table.setMinimumHeight(350)
        self.results_table.setStyleSheet("""
            QTableWidget {
                font-size: 13px;
                border: 1px solid #c0c0c0;
                border-radius: 4px;
                background-color: white;
            }
            QHeaderView::section {
                background-color: #e0e0e0;
                color: #2C3E50;
                padding: 8px;
                font-weight: bold;
                font-size: 13px;
                border: 1px solid #c0c0c0;
            }
            QTableWidget::item {
                padding: 5px;
                border: none;
            }
        """)

        # Настройка высоты строк
        self.results_table.verticalHeader().setDefaultSectionSize(40)

        results_layout.addWidget(self.results_table)

        left_column.addWidget(results_group)

        # Правая колонка - карта плотности
        right_column = QVBoxLayout()

        viz_group = QGroupBox("🗺️ КАРТА ПЛОТНОСТИ")
        viz_group.setStyleSheet("""
            QGroupBox {
                font-size: 18px;
                font-weight: bold;
                border: 2px solid #F57C00;
                border-radius: 8px;
                margin-top: 15px;
                padding-top: 25px;
                background-color: white;
            }
            QGroupBox::title {
                subcontrol-origin: margin;
                left: 25px;
                padding: 0 20px 0 20px;
                color: #F57C00;
                background-color: white;
                border: 1px solid #F57C00;
                border-radius: 4px;
            }
        """)
        viz_layout = QVBoxLayout(viz_group)
        viz_layout.setContentsMargins(20, 20, 20, 20)

        self.density_map = QTextEdit()
        self.density_map.setReadOnly(True)
        self.density_map.setMinimumHeight(500)
        self.density_map.setStyleSheet("""
            QTextEdit {
                font-family: 'Courier New', monospace;
                font-size: 14px;
                background-color: #1a2a3a;
                color: #FFD700;
                border: 1px solid #F57C00;
                border-radius: 4px;
                padding: 15px;
                line-height: 1.5;
            }
        """)
        viz_layout.addWidget(self.density_map)

        right_column.addWidget(viz_group)

        # Добавляем колонки
        results_row.addLayout(left_column, 2)
        results_row.addLayout(right_column, 1)

        container_layout.addLayout(results_row)

        # === КНОПКИ ===
        btn_layout = QHBoxLayout()
        btn_layout.setSpacing(10)
        btn_layout.addStretch()

        # Стиль для кнопок
        button_style = """
            QPushButton {
                font-size: 14px;
                font-weight: bold;
                padding: 10px 20px;
                border: 1px solid #a0a0a0;
                border-radius: 4px;
                min-width: 150px;
                background-color: #e0e0e0;
                color: #2C3E50;
            }
            QPushButton:hover {
                background-color: #d0d0d0;
            }
        """

        # Кнопка расчета
        self.calc_btn = QPushButton("🧮 РАССЧИТАТЬ")
        self.calc_btn.setMinimumHeight(40)
        self.calc_btn.setStyleSheet(button_style)
        self.calc_btn.clicked.connect(self.calculate)
        btn_layout.addWidget(self.calc_btn)

        # Кнопка избранного
        self.fav_btn = QPushButton("⭐ В избранное")
        self.fav_btn.setMinimumHeight(40)
        self.fav_btn.setStyleSheet(button_style)
        self.fav_btn.clicked.connect(self.add_to_favorites)
        btn_layout.addWidget(self.fav_btn)

        # Кнопка копирования
        self.copy_btn = QPushButton("📋 Копировать")
        self.copy_btn.setMinimumHeight(40)
        self.copy_btn.setStyleSheet(button_style)
        self.copy_btn.clicked.connect(self.copy_to_max)
        btn_layout.addWidget(self.copy_btn)

        # Кнопка Excel
        self.excel_btn = QPushButton("📊 Excel")
        self.excel_btn.setMinimumHeight(40)
        self.excel_btn.setStyleSheet(button_style)
        self.excel_btn.clicked.connect(self.export_to_excel)
        btn_layout.addWidget(self.excel_btn)

        container_layout.addLayout(btn_layout)

        # Информационная панель
        info_frame = QFrame()
        info_frame.setStyleSheet("""
            QFrame {
                background-color: #fff3cd;
                border: 1px solid #FFC107;
                border-radius: 4px;
                padding: 10px;
            }
        """)
        info_layout = QHBoxLayout(info_frame)
        info_layout.setSpacing(10)

        info_icon = QLabel("💡")
        info_icon.setStyleSheet("font-size: 20px;")
        info_layout.addWidget(info_icon)

        info_text = QLabel(
            "📊 Плотность заказов рассчитывается по методике УрФУ:\n"
            "• 🟢 80-100% — высокая плотность\n"
            "• 🟡 40-79% — средняя плотность\n"
            "• 🔴 0-39% — низкая плотность\n"
            "• ✏️ Можно вводить свои регионы (плотность 50%)\n"
            "• 📚 Нажмите кнопку СПРАВКА для подробного руководства"
        )
        info_text.setWordWrap(True)
        info_text.setStyleSheet("color: #1a2a3a; font-size: 12px; line-height: 1.5;")
        info_layout.addWidget(info_text, 1)

        container_layout.addWidget(info_frame)

        # Добавляем растяжку в конец
        container_layout.addStretch()

        # Устанавливаем контейнер в область прокрутки
        scroll_area.setWidget(container)
        main_layout.addWidget(scroll_area)

    def show_help(self):
        """Показывает справку по модулю"""
        dialog = DensityHelpDialog(self)
        dialog.exec_()

    def connect_signals(self):
        """Подключение сигналов"""
        self.start_region.currentTextChanged.connect(self.update_preview)
        self.end_region.currentTextChanged.connect(self.update_preview)
        self.monthly_orders.valueChanged.connect(self.update_preview)
        self.avg_weight.valueChanged.connect(self.update_preview)
        self.avg_distance.valueChanged.connect(self.update_preview)
        self.competition.currentIndexChanged.connect(self.update_preview)

    def update_preview(self):
        """Обновляет предварительный просмотр"""
        try:
            start = self.start_region.currentText().strip()
            if not start:
                start = "?"

            end = self.end_region.currentText().strip()
            if not end:
                end = "?"

            orders = self.monthly_orders.value()
            weight = self.avg_weight.value()
            distance = self.avg_distance.value()
            comp_idx = self.competition.currentIndex()

            # Получаем плотности регионов
            base_density_start = self.get_region_density(start)
            base_density_end = self.get_region_density(end)
            avg_base = (base_density_start + base_density_end) / 2

            comp_factors = [1.2, 1.0, 0.8, 0.5]
            density = avg_base * (orders / 100) * (weight / 20) * comp_factors[comp_idx]
            density = min(100, max(0, density))

            if density >= 80:
                color = "#2E7D32"
                level = "ВЫСОКАЯ"
            elif density >= 40:
                color = "#F57C00"
                level = "СРЕДНЯЯ"
            else:
                color = "#C41E3A"
                level = "НИЗКАЯ"

            self.density_label.setText(
                f"<b>📊 ПЛОТНОСТЬ ЗАКАЗОВ: <span style='color:{color}; font-size:18px;'>{density:.1f}% ({level})</span></b><br><br>"
                f"📍 Маршрут: {start} → {end}<br>"
                f"📦 Заказов: {orders} в месяц | ⚖️ Вес: {weight:.1f} т | 📏 Пробег: {distance} км"
            )

        except Exception as e:
            self.density_label.setText("⏳ Выберите параметры для расчета")

    def calculate(self):
        """Основной расчет"""
        try:
            start = self.start_region.currentText().strip()
            if not start:
                QMessageBox.warning(self, "Предупреждение", "Укажите регион отправления!")
                return

            end = self.end_region.currentText().strip()
            if not end:
                QMessageBox.warning(self, "Предупреждение", "Укажите регион назначения!")
                return

            orders = self.monthly_orders.value()
            weight = self.avg_weight.value()
            distance = self.avg_distance.value()
            comp_idx = self.competition.currentIndex()

            # Получаем плотности регионов
            base_density_start = self.get_region_density(start)
            base_density_end = self.get_region_density(end)
            avg_base = (base_density_start + base_density_end) / 2

            comp_factors = [1.2, 1.0, 0.8, 0.5]
            comp_names = ["Низкий", "Средний", "Высокий", "Очень высокий"]
            comp_factor = comp_factors[comp_idx]
            comp_name = comp_names[comp_idx]

            distance_factor = max(0.5, min(1.5, 500 / max(distance, 100)))

            density = avg_base * (orders / 100) * (weight / 20) * comp_factor * distance_factor
            density = round(min(100, max(0, density)), 1)

            # Определение уровня
            if density >= 80:
                level = "ВЫСОКАЯ"
                level_color = "#2E7D32"
                level_desc = "Отличная плотность! Маршрут очень эффективен."
                recommendation = "Увеличить частоту рейсов, добавить дополнительные точки"
            elif density >= 40:
                level = "СРЕДНЯЯ"
                level_color = "#F57C00"
                level_desc = "Средняя плотность. Есть потенциал для роста."
                recommendation = "Проанализировать возможность обратных загрузок"
            else:
                level = "НИЗКАЯ"
                level_color = "#C41E3A"
                level_desc = "Низкая плотность. Высок риск порожних пробегов."
                recommendation = "Рассмотреть другие направления или кооперацию"

            efficiency = density / 100
            empty_risk = max(0, 100 - density) / 100

            # Заполнение таблицы
            self.results_table.setRowCount(6)

            results = [
                ("Плотность заказов", f"{density}%", level, level_desc),
                ("Эффективность маршрута", f"{efficiency:.2f}", "Коэф. использования", f"{efficiency*100:.0f}% загрузки"),
                ("Риск порожняка", f"{empty_risk:.0%}", "Вероятность",
                 f"{'Высокий' if empty_risk>0.3 else 'Средний' if empty_risk>0.15 else 'Низкий'}"),
                ("Конкуренция", comp_name, "В регионе",
                 f"{'Очень высокая' if comp_idx==3 else 'Высокая' if comp_idx==2 else 'Средняя' if comp_idx==1 else 'Низкая'}"),
                ("Оптимальная частота", f"{int(orders * efficiency)} рейсов", "В месяц",
                 f"{'Можно увеличить' if efficiency<0.8 else 'Оптимально'}"),
                ("Рекомендация", recommendation, "Действия", "Для повышения эффективности")
            ]

            for row, (param, value, assessment, rec) in enumerate(results):
                for col, text in enumerate([param, value, assessment, rec]):
                    item = QTableWidgetItem(text)
                    if row == 0:
                        item.setBackground(QColor(level_color))
                        item.setForeground(QBrush(QColor("white")))
                        font = QFont()
                        font.setBold(True)
                        item.setFont(font)
                    self.results_table.setItem(row, col, item)

            self.results_table.resizeColumnsToContents()

            # Обновление карты
            self.update_density_map(start, end, density)

            # Сохранение результатов
            self.last_result = f"{density}% ({level})"
            self.last_params = {
                "start": start,
                "end": end,
                "orders": orders,
                "weight": weight,
                "distance": distance,
                "competition": comp_name,
                "density": density,
                "level": level,
                "recommendation": recommendation,
                "base_start": base_density_start,
                "base_end": base_density_end
            }

            self.save_to_history()

        except Exception as e:
            QMessageBox.critical(self, "Ошибка", f"Ошибка при расчете: {str(e)}")

    def update_density_map(self, start, end, density):
        """Обновляет текстовую карту"""
        map_text = "📊 КАРТА ПЛОТНОСТИ ЗАКАЗОВ (УрФУ)\n"
        map_text += "═" * 60 + "\n\n"

        # Гистограмма
        bar_length = int(density / 2)
        bar = "█" * bar_length + "░" * (50 - bar_length)

        if density >= 80:
            status = "ВЫСОКАЯ 🟢"
        elif density >= 40:
            status = "СРЕДНЯЯ 🟡"
        else:
            status = "НИЗКАЯ 🔴"

        map_text += f"ТЕКУЩИЙ МАРШРУТ: {start} → {end}\n"
        map_text += f"ПЛОТНОСТЬ: {density}% ({status})\n"
        map_text += f"[{bar}] {density}%\n\n"
        map_text += "═" * 60 + "\n\n"

        # Топ-5 регионов
        map_text += "ТОП-5 РЕГИОНОВ ПО ПЛОТНОСТИ:\n"
        sorted_regions = sorted(self.REGIONS.items(), key=lambda x: x[1]["base_density"], reverse=True)

        for region, data in sorted_regions[:5]:
            bar_len = int(data["base_density"] / 2)
            bar = "█" * bar_len
            map_text += f"{region:15} [{bar:25}] {data['base_density']}%\n"

        map_text += "\n" + "═" * 60 + "\n"
        map_text += "█ - высокая плотность  ░ - низкая плотность\n"
        map_text += "✏️ Можно вводить свои регионы (плотность 50%)"

        self.density_map.setText(map_text)

    def save_to_history(self):
        """Сохраняет в историю"""
        if self.main_window and hasattr(self.main_window, 'history_manager') and self.last_params:
            calculation = {
                "id": datetime.now().strftime("%Y%m%d%H%M%S"),
                "date": datetime.now().strftime("%d.%m.%Y %H:%M"),
                "module": "📊 Плотность заказов (УрФУ)",
                "description": f"{self.last_params['start']} → {self.last_params['end']}: {self.last_params['density']}%",
                "result": self.last_result,
                "params": self.last_params
            }
            self.main_window.history_manager.add_to_history(calculation)
            if hasattr(self.main_window, 'favorites_widget'):
                self.main_window.favorites_widget.refresh()

    def add_to_favorites(self):
        """Добавляет в избранное"""
        if not self.last_params:
            QMessageBox.warning(self, "Предупреждение", "Сначала выполните расчет!")
            return

        calculation = {
            "id": datetime.now().strftime("%Y%m%d%H%M%S"),
            "date": datetime.now().strftime("%d.%m.%Y %H:%M"),
            "module": "📊 Плотность заказов (УрФУ)",
            "description": f"{self.last_params['start']} → {self.last_params['end']}: {self.last_params['density']}%",
            "result": self.last_result,
            "params": self.last_params
        }

        if self.main_window and hasattr(self.main_window, 'history_manager'):
            if self.main_window.history_manager.add_to_favorites(calculation):
                QMessageBox.information(self, "Готово", "⭐ Расчет добавлен в избранное!")
                if hasattr(self.main_window, 'favorites_widget'):
                    self.main_window.favorites_widget.refresh()
            else:
                QMessageBox.information(self, "Инфо", "Этот расчет уже в избранном")

    def copy_to_max(self):
        """Копирует в буфер"""
        if not self.last_params:
            QMessageBox.warning(self, "Предупреждение", "Сначала выполните расчет!")
            return

        p = self.last_params

        message = f"""📊 ПЛОТНОСТЬ ЗАКАЗОВ (УрФУ)

📅 Дата: {datetime.now().strftime('%d.%m.%Y %H:%M')}
📍 Маршрут: {p['start']} → {p['end']}
📦 Заказов: {p['orders']} в месяц
⚖️ Вес: {p['weight']} т
📏 Пробег: {p['distance']} км

📊 ПЛОТНОСТЬ: {p['density']}% ({p['level']})
🏢 Конкуренция: {p['competition']}

💡 РЕКОМЕНДАЦИЯ:
{p['recommendation']}

🔗 Код расчёта: {datetime.now().strftime('%Y%m%d%H%M%S')}
🌐 mirom.tech"""

        QApplication.clipboard().setText(message)
        QMessageBox.information(self, "Готово", "✅ Результат скопирован в буфер обмена")

    def export_to_excel(self):
        """Экспорт в Excel"""
        if not self.last_params:
            QMessageBox.warning(self, "Предупреждение", "Сначала выполните расчет!")
            return

        if not EXCEL_AVAILABLE:
            QMessageBox.warning(self, "Ошибка", "Установите openpyxl: pip install openpyxl")
            return

        try:
            filename, _ = QFileDialog.getSaveFileName(
                self, "Сохранить расчет",
                f"density_{datetime.now().strftime('%Y%m%d_%H%M%S')}.xlsx",
                "Excel Files (*.xlsx)"
            )
            if not filename:
                return

            p = self.last_params
            wb = openpyxl.Workbook()
            ws = wb.active
            ws.title = "Плотность заказов"

            # Заголовок
            ws.merge_cells('A1:D1')
            ws['A1'] = "📊 ПЛОТНОСТЬ ЗАКАЗОВ (УрФУ) - ДЕТАЛЬНЫЙ АНАЛИЗ"
            ws['A1'].font = Font(size=16, bold=True, color="FFFFFF")
            ws['A1'].fill = PatternFill(start_color="1976D2", end_color="1976D2", fill_type="solid")
            ws['A1'].alignment = Alignment(horizontal="center")

            # Дата
            ws.merge_cells('A2:D2')
            ws['A2'] = f"Дата расчета: {datetime.now().strftime('%d.%m.%Y %H:%M')}"
            ws['A2'].font = Font(size=11, italic=True)
            ws['A2'].alignment = Alignment(horizontal="right")

            # Параметры
            ws.merge_cells('A4:D4')
            ws['A4'] = "📋 ПАРАМЕТРЫ АНАЛИЗА"
            ws['A4'].font = Font(size=14, bold=True)

            params = [
                ("Регион отправления:", p['start']),
                ("Регион назначения:", p['end']),
                ("Заказов в месяц:", f"{p['orders']} шт"),
                ("Средний вес:", f"{p['weight']} т"),
                ("Средний пробег:", f"{p['distance']} км"),
                ("Конкуренция:", p['competition']),
            ]

            for i, (label, value) in enumerate(params):
                ws[f'A{5+i}'] = label
                ws[f'A{5+i}'].font = Font(bold=True, size=11)
                ws[f'B{5+i}'] = value
                ws[f'B{5+i}'].font = Font(size=11)

            # Результаты
            row = 5 + len(params) + 2
            ws.merge_cells(f'A{row}:D{row}')
            ws[f'A{row}'] = "📊 РЕЗУЛЬТАТЫ"
            ws[f'A{row}'].font = Font(size=14, bold=True)

            # Цвет для плотности
            if p['density'] >= 80:
                density_color = "2E7D32"
            elif p['density'] >= 40:
                density_color = "F57C00"
            else:
                density_color = "C41E3A"

            results = [
                ("Плотность заказов:", f"{p['density']}% ({p['level']})"),
                ("Рекомендация:", p['recommendation']),
            ]

            for i, (label, value) in enumerate(results):
                ws[f'A{row+1+i}'] = label
                ws[f'A{row+1+i}'].font = Font(bold=True, size=11)
                cell = ws[f'B{row+1+i}']
                cell.value = value
                cell.font = Font(size=11)
                if i == 0:
                    cell.font = Font(color=density_color, bold=True, size=11)

            # Автоширина
            ws.column_dimensions['A'].width = 25
            ws.column_dimensions['B'].width = 35
            ws.column_dimensions['C'].width = 5
            ws.column_dimensions['D'].width = 5

            wb.save(filename)
            QMessageBox.information(self, "Готово", f"✅ Файл сохранен:\n{filename}")

        except Exception as e:
            QMessageBox.critical(self, "Ошибка", f"Ошибка экспорта: {str(e)}")