"""
GUI application for rateloader.

Implements Phase 7 of the rateloader project: GUI (tkinter) interface.
Provides tabs for Settings, Export Mailer, Price Export, Rate Loader, and Logs.
"""

import tkinter as tk
from tkinter import ttk, messagebox, filedialog, scrolledtext
import threading
import time
import os
import sys
from typing import Dict, Any, Optional, List
from datetime import datetime

# Add parent directory to path for imports
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

from core.config import get_config, reload_config
from core.task_queue import get_task_queue, enqueue_task, get_queue_status
from core.scheduler import get_scheduler, get_scheduler_status
from core.http_server import get_http_server, start_server, stop_server, is_server_running
from core.logger import get_logger_manager
from core.tasks import ExportMailerTask, PriceExportTask, DatabaseInitializationTask, create_database_init_task
from core.database_schema import DatabaseSchemaManager, execute_sql_schema, validate_database_schema
from core.ip_manager import get_ip_manager

# Import translations
from gui.translations import get_text, get_tooltip


class RateLoaderGUI:
    """Main GUI application for rateloader."""
    
    def __init__(self):
        """Initialize the GUI application."""
        self.root = tk.Tk()
        self.root.title(get_text("title"))
        self.root.geometry("800x600")
        self.root.minsize(700, 500)
        
        # Set application icon
        self._set_app_icon()
        
        # Initialize backend components
        self.config = get_config()
        self.task_queue = get_task_queue()
        self.scheduler = get_scheduler()
        self.http_server = get_http_server()
        self.logger_manager = get_logger_manager()
        self.ip_manager = get_ip_manager()
        
        # GUI state variables
        self.is_closing = False
        self.auto_refresh_enabled = tk.BooleanVar(value=True)
        self.selected_log_file = tk.StringVar(value="rateloader.log")
        
        # Auto-start server variable (initialized early for auto-start logic)
        # Force config reload to get latest value
        self.config = reload_config()
        self.auto_start_server_var = tk.BooleanVar(value=self.config.get_int('auto_start_server', fallback=1) == 1)
        
        # Status tracking
        self.last_export_mailer_run = None
        self.last_price_export_run = None
        
        # Setup GUI
        self._setup_menu()
        self._setup_main_layout()
        self._setup_status_bar()
        
        # Start background threads
        self._start_background_threads()
        
        # Auto-start server if enabled
        self._auto_start_server_if_enabled()
        
        # Start GUI update loop
        self._schedule_gui_updates()
        
        # Handle window closing
        self.root.protocol("WM_DELETE_WINDOW", self._on_closing)
    
    def _set_app_icon(self):
        """Set the application icon."""
        try:
            # Try to load icon from different possible locations
            icon_paths = [
                "logo.ico",  # Current directory
                os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "logo.ico"),  # Project root
            ]
            
            for icon_path in icon_paths:
                if os.path.exists(icon_path):
                    self.root.iconbitmap(icon_path)
                    break
            # If no icon found, silently continue (tkinter will use default)
        except Exception as e:
            # Silently fail if icon cannot be loaded
            pass
    
    def _setup_menu(self):
        """Setup the menu bar."""
        menubar = tk.Menu(self.root)
        self.root.config(menu=menubar)

        # File menu
        file_menu = tk.Menu(menubar, tearoff=0)
        menubar.add_cascade(label=get_text("menu_file"), menu=file_menu)
        file_menu.add_command(label=get_text("menu_exit"), command=self._on_closing)

        # Help menu
        help_menu = tk.Menu(menubar, tearoff=0)
        menubar.add_cascade(label=get_text("menu_help"), menu=help_menu)
        help_menu.add_command(label=get_text("menu_about"), command=self._show_about)
        help_menu.add_separator()
        help_menu.add_command(label=get_text("tab_rate_loader"), command=lambda: self._show_help("rate_loader"))
        help_menu.add_command(label=get_text("tab_export_mailer"), command=lambda: self._show_help("export_mailer"))
        help_menu.add_command(label=get_text("tab_price_export"), command=lambda: self._show_help("price_export"))
        help_menu.add_command(label=get_text("tab_database_schema"), command=lambda: self._show_help("database_schema"))
        help_menu.add_command(label=get_text("tab_ip_management"), command=lambda: self._show_help("ip_management"))
        help_menu.add_command(label=get_text("tab_settings"), command=lambda: self._show_help("settings"))
        help_menu.add_command(label=get_text("tab_logs"), command=lambda: self._show_help("logs"))
    
    def _setup_main_layout(self):
        """Setup the main layout with tabs."""
        # Create notebook for tabs
        self.notebook = ttk.Notebook(self.root)
        self.notebook.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
        
        # Create tabs in requested order:
        # 1. Rate Loader (first)
        # 2. Export Mailer
        # 3. Price Export
        # 4. Database Schema
        # 5. Settings (before logs)
        # 6. Logs (last)
        self._create_rate_loader_tab()
        self._create_export_mailer_tab()
        self._create_price_export_tab()
        self._create_database_schema_tab()
        self._create_ip_management_tab()
        self._create_settings_tab()
        self._create_logs_tab()
    
    def _setup_status_bar(self):
        """Setup the status bar."""
        self.status_frame = ttk.Frame(self.root)
        self.status_frame.pack(fill=tk.X, side=tk.BOTTOM)

        self.status_label = ttk.Label(self.status_frame, text=get_text("status_ready"), relief=tk.SUNKEN)
        self.status_label.pack(fill=tk.X, side=tk.LEFT, padx=2, pady=2)

        self.time_label = ttk.Label(self.status_frame, text="", relief=tk.SUNKEN)
        self.time_label.pack(fill=tk.X, side=tk.RIGHT, padx=2, pady=2)
    
    def _create_settings_tab(self):
        """Create the Settings tab."""
        self.settings_frame = ttk.Frame(self.notebook)
        self.notebook.add(self.settings_frame, text=get_text("tab_settings"))
        
        # Create scrollable frame
        canvas = tk.Canvas(self.settings_frame)
        scrollbar = ttk.Scrollbar(self.settings_frame, orient="vertical", command=canvas.yview)
        scrollable_frame = ttk.Frame(canvas)
        
        scrollable_frame.bind(
            "<Configure>",
            lambda e: canvas.configure(scrollregion=canvas.bbox("all"))
        )
        
        canvas.create_window((0, 0), window=scrollable_frame, anchor="nw")
        canvas.configure(yscrollcommand=scrollbar.set)
        
        # Settings sections
        self.settings_vars = {}
        sections = {
            get_text("oracle_settings"): ["oracleconnectstring", "nls_lang", "file_encoding"],
            get_text("export_mailer_settings"): ["hotel_key", "url", "block-url", "sendfrom", "sendto", "mailserver", "port", "pwd", "ssl", "compress_attachments", "auto_update_sql"],
            get_text("price_export_settings"): ["api_url", "token", "months", "deeper_logging"],
            get_text("rate_loader_settings"): ["server_port"],
            get_text("scheduler_settings"): ["schedule_hours", "enable_price_export_scheduling"]
        }

        row = 0
        for section_name, keys in sections.items():
            # Section header
            ttk.Label(scrollable_frame, text=f"{section_name} Settings:",
                      font=("Arial", 10, "bold")).grid(row=row, column=0, columnspan=3, sticky="w", pady=(10, 5))
            row += 1

            for key in keys:
                ttk.Label(scrollable_frame, text=get_text(key) + ":").grid(row=row, column=0, sticky="w", padx=(20, 5))

                if key in ["ssl", "compress_attachments", "auto_update_sql", "enable_price_export_scheduling"]:
                    # Use checkboxes for boolean settings
                    var = tk.BooleanVar(value=self.config.get_int(key, fallback=0) == 1)
                    self.settings_vars[key] = var
                    checkbox = ttk.Checkbutton(scrollable_frame, variable=var, text=get_text(key))
                    checkbox.grid(row=row, column=1, sticky="w", padx=5)
                    # Add tooltip
                    self._add_tooltip(checkbox, get_tooltip(key))
                else:
                    var = tk.StringVar(value=self.config.get(key))
                    self.settings_vars[key] = var
                    entry = ttk.Entry(scrollable_frame, textvariable=var, width=50)
                    entry.grid(row=row, column=1, sticky="ew", padx=5)
                    # Add tooltip
                    self._add_tooltip(entry, get_tooltip(key))

                row += 1
            
            # Separator
            ttk.Separator(scrollable_frame, orient="horizontal").grid(row=row, column=0, columnspan=3, sticky="ew", pady=10)
            row += 1
        
        # Buttons
        button_frame = ttk.Frame(scrollable_frame)
        button_frame.grid(row=row, column=0, columnspan=3, pady=10)

        ttk.Button(button_frame, text=get_text("save_apply"), command=self._save_settings).pack(side=tk.LEFT, padx=5)
        ttk.Button(button_frame, text=get_text("reload"), command=self._reload_settings).pack(side=tk.LEFT, padx=5)
        
        # Configure grid weights
        scrollable_frame.columnconfigure(1, weight=1)
        
        # Pack canvas and scrollbar
        canvas.pack(side="left", fill="both", expand=True)
        scrollbar.pack(side="right", fill="y")
    
    def _create_export_mailer_tab(self):
        """Create the Export Mailer tab."""
        self.export_mailer_frame = ttk.Frame(self.notebook)
        self.notebook.add(self.export_mailer_frame, text=get_text("tab_export_mailer"))

        # Control section
        control_frame = ttk.LabelFrame(self.export_mailer_frame, text=get_text("control"), padding=10)
        control_frame.pack(fill=tk.X, padx=10, pady=10)

        ttk.Button(control_frame, text=get_text("run_now"), command=self._run_export_mailer).pack(side=tk.LEFT, padx=5)

        # Status section
        status_frame = ttk.LabelFrame(self.export_mailer_frame, text=get_text("status"), padding=10)
        status_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)

        self.export_mailer_status = scrolledtext.ScrolledText(status_frame, height=15, state=tk.DISABLED)
        self.export_mailer_status.pack(fill=tk.BOTH, expand=True)

        # Progress section
        progress_frame = ttk.LabelFrame(self.export_mailer_frame, text=get_text("progress"), padding=10)
        progress_frame.pack(fill=tk.X, padx=10, pady=10)

        self.export_mailer_progress = ttk.Progressbar(progress_frame, mode='indeterminate')
        self.export_mailer_progress.pack(fill=tk.X, padx=5, pady=5)

        self.export_mailer_last_run = ttk.Label(progress_frame, text=get_text("last_run") + " " + get_text("never"))
        self.export_mailer_last_run.pack(anchor="w")
    
    def _create_price_export_tab(self):
        """Create the Price Export tab."""
        self.price_export_frame = ttk.Frame(self.notebook)
        self.notebook.add(self.price_export_frame, text=get_text("tab_price_export"))

        # Control section
        control_frame = ttk.LabelFrame(self.price_export_frame, text=get_text("control"), padding=10)
        control_frame.pack(fill=tk.X, padx=10, pady=10)

        ttk.Button(control_frame, text=get_text("run_now"), command=self._run_price_export).pack(side=tk.LEFT, padx=5)

        # Deeper logging checkbox
        self.price_export_deeper_logging_var = tk.BooleanVar(value=self.config.get_bool("deeper_logging", fallback=False))
        ttk.Checkbutton(control_frame, text=get_text("enable_deeper_logging"),
                        variable=self.price_export_deeper_logging_var,
                        command=self._on_price_export_deeper_logging_changed).pack(side=tk.LEFT, padx=20)

        # Status section
        status_frame = ttk.LabelFrame(self.price_export_frame, text=get_text("status"), padding=10)
        status_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)

        self.price_export_status = scrolledtext.ScrolledText(status_frame, height=15, state=tk.DISABLED)
        self.price_export_status.pack(fill=tk.BOTH, expand=True)

        # Progress section
        progress_frame = ttk.LabelFrame(self.price_export_frame, text=get_text("progress"), padding=10)
        progress_frame.pack(fill=tk.X, padx=10, pady=10)

        self.price_export_progress = ttk.Progressbar(progress_frame, mode='indeterminate')
        self.price_export_progress.pack(fill=tk.X, padx=5, pady=5)

        self.price_export_last_run = ttk.Label(progress_frame, text=get_text("last_run") + " " + get_text("never"))
        self.price_export_last_run.pack(anchor="w")

    def _create_database_schema_tab(self):
        """Create the Database Schema tab."""
        self.database_schema_frame = ttk.Frame(self.notebook)
        self.notebook.add(self.database_schema_frame, text=get_text("tab_database_schema"))

        # Control section
        control_frame = ttk.LabelFrame(self.database_schema_frame, text=get_text("schema_management"), padding=10)
        control_frame.pack(fill=tk.X, padx=10, pady=10)

        ttk.Button(control_frame, text=get_text("execute_schema"), command=self._execute_database_schema).pack(side=tk.LEFT, padx=5)
        ttk.Button(control_frame, text=get_text("validate_schema"), command=self._validate_database_schema).pack(side=tk.LEFT, padx=5)
        ttk.Button(control_frame, text=get_text("parse_schema"), command=self._parse_schema_file).pack(side=tk.LEFT, padx=5)
        ttk.Button(control_frame, text=get_text("generate_schema"), command=self._generate_schema_from_model).pack(side=tk.LEFT, padx=5)

        # SQL File section
        file_frame = ttk.Frame(control_frame)
        file_frame.pack(fill=tk.X, pady=(10, 0))

        ttk.Label(file_frame, text=get_text("sql_file") + ":").pack(side=tk.LEFT, padx=5)
        self.schema_file_var = tk.StringVar(value="")  # Empty means use embedded schema
        self.schema_file_entry = ttk.Entry(file_frame, textvariable=self.schema_file_var, width=30)
        self.schema_file_entry.pack(side=tk.LEFT, padx=5)
        ttk.Button(file_frame, text=get_text("browse"), command=self._browse_schema_file).pack(side=tk.LEFT, padx=5)

        # Embedded schema checkbox
        self.use_embedded_var = tk.BooleanVar(value=True)
        ttk.Checkbutton(file_frame, text=get_text("use_embedded_schema"),
                        variable=self.use_embedded_var,
                        command=self._on_embedded_schema_changed).pack(side=tk.LEFT, padx=20)

        # Status section
        status_frame = ttk.LabelFrame(self.database_schema_frame, text=get_text("status"), padding=10)
        status_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)

        self.database_schema_status = scrolledtext.ScrolledText(status_frame, height=15, state=tk.DISABLED)
        self.database_schema_status.pack(fill=tk.BOTH, expand=True)

        # Progress section
        progress_frame = ttk.LabelFrame(self.database_schema_frame, text=get_text("progress"), padding=10)
        progress_frame.pack(fill=tk.X, padx=10, pady=10)

        self.database_schema_progress = ttk.Progressbar(progress_frame, mode='indeterminate')
        self.database_schema_progress.pack(fill=tk.X, padx=5, pady=5)

        self.database_schema_last_run = ttk.Label(progress_frame, text=get_text("last_run") + " " + get_text("never"))
        self.database_schema_last_run.pack(anchor="w")
    
    def _create_rate_loader_tab(self):
        """Create the Rate Loader tab."""
        self.rate_loader_frame = ttk.Frame(self.notebook)
        self.notebook.add(self.rate_loader_frame, text=get_text("tab_rate_loader"))

        # Control section
        control_frame = ttk.LabelFrame(self.rate_loader_frame, text=get_text("server_control"), padding=10)
        control_frame.pack(fill=tk.X, padx=10, pady=10)

        # Auto-start checkbox
        self.auto_start_checkbox = ttk.Checkbutton(
            control_frame,
            variable=self.auto_start_server_var,
            text=get_text("auto_start_server"),
            command=self._on_auto_start_changed
        )
        self.auto_start_checkbox.pack(anchor="w", pady=(0, 10))

        # Start/Stop buttons
        button_frame = ttk.Frame(control_frame)
        button_frame.pack(fill=tk.X)

        self.start_server_btn = ttk.Button(button_frame, text=get_text("start_server"), command=self._start_server)
        self.start_server_btn.pack(side=tk.LEFT, padx=5)

        self.stop_server_btn = ttk.Button(button_frame, text=get_text("stop_server"), command=self._stop_server, state=tk.DISABLED)
        self.stop_server_btn.pack(side=tk.LEFT, padx=5)

        # Status section
        status_frame = ttk.LabelFrame(self.rate_loader_frame, text=get_text("server_status"), padding=10)
        status_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)

        self.rate_loader_status = scrolledtext.ScrolledText(status_frame, height=15, state=tk.DISABLED)
        self.rate_loader_status.pack(fill=tk.BOTH, expand=True)

        # Server info
        info_frame = ttk.LabelFrame(self.rate_loader_frame, text=get_text("server_information"), padding=10)
        info_frame.pack(fill=tk.X, padx=10, pady=10)

        self.server_port_label = ttk.Label(info_frame, text=get_text("port") + f": {self.config.get_int('server_port', fallback=8000)}")
        self.server_port_label.pack(anchor="w")

        self.server_connections_label = ttk.Label(info_frame, text=get_text("connections") + ": 0")
        self.server_connections_label.pack(anchor="w")
    
    def _create_logs_tab(self):
        """Create the Logs tab."""
        self.logs_frame = ttk.Frame(self.notebook)
        self.notebook.add(self.logs_frame, text=get_text("tab_logs"))

        # Control section
        control_frame = ttk.Frame(self.logs_frame)
        control_frame.pack(fill=tk.X, padx=10, pady=10)

        ttk.Label(control_frame, text=get_text("log_file") + ":").pack(side=tk.LEFT, padx=5)

        log_files = [get_text("log_file_rateloader")]
        self.log_file_combo = ttk.Combobox(control_frame, textvariable=self.selected_log_file, values=log_files, state="readonly")
        self.log_file_combo.pack(side=tk.LEFT, padx=5)
        self.log_file_combo.bind("<<ComboboxSelected>>", self._on_log_file_changed)

        ttk.Checkbutton(control_frame, text=get_text("auto_refresh"), variable=self.auto_refresh_enabled).pack(side=tk.LEFT, padx=20)
        ttk.Button(control_frame, text=get_text("refresh"), command=self._refresh_logs).pack(side=tk.LEFT, padx=5)
        ttk.Button(control_frame, text=get_text("clear_log"), command=self._clear_log).pack(side=tk.LEFT, padx=5)

        # Log display
        log_frame = ttk.LabelFrame(self.logs_frame, text=get_text("log_content"), padding=10)
        log_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)

        self.log_display = scrolledtext.ScrolledText(log_frame, height=20, state=tk.DISABLED)
        self.log_display.pack(fill=tk.BOTH, expand=True)
    
    def _create_ip_management_tab(self):
        """Create the IP Management tab."""
        self.ip_management_frame = ttk.Frame(self.notebook)
        self.notebook.add(self.ip_management_frame, text=get_text("tab_ip_management"))

        # Global access control
        global_frame = ttk.LabelFrame(self.ip_management_frame, text=get_text("global_access_control"), padding=10)
        global_frame.pack(fill=tk.X, padx=10, pady=10)

        self.global_access_var = tk.StringVar(value="allowed")
        ttk.Radiobutton(global_frame, text=get_text("allowed_blacklist"),
                        variable=self.global_access_var, value="allowed",
                        command=self._on_global_access_changed).pack(side=tk.LEFT, padx=5)
        ttk.Radiobutton(global_frame, text=get_text("restricted_whitelist"),
                        variable=self.global_access_var, value="restricted",
                        command=self._on_global_access_changed).pack(side=tk.LEFT, padx=5)

        # IP list
        list_frame = ttk.LabelFrame(self.ip_management_frame, text=get_text("ip_addresses"), padding=10)
        list_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)

        # Create treeview for IP list
        columns = (get_text("ip_address"), get_text("status"), get_text("last_seen"), get_text("requests"), get_text("last_request"))
        self.ip_tree = ttk.Treeview(list_frame, columns=columns, show="headings", height=15)

        for col in columns:
            self.ip_tree.heading(col, text=col)
            self.ip_tree.column(col, width=120)

        # Scrollbar for treeview
        scrollbar = ttk.Scrollbar(list_frame, orient=tk.VERTICAL, command=self.ip_tree.yview)
        self.ip_tree.configure(yscrollcommand=scrollbar.set)

        self.ip_tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)

        # Action buttons
        button_frame = ttk.Frame(self.ip_management_frame)
        button_frame.pack(fill=tk.X, padx=10, pady=10)

        ttk.Button(button_frame, text=get_text("toggle_selected"), command=self._toggle_selected_ip).pack(side=tk.LEFT, padx=5)
        ttk.Button(button_frame, text=get_text("remove_selected"), command=self._remove_selected_ip).pack(side=tk.LEFT, padx=5)
        ttk.Button(button_frame, text=get_text("refresh"), command=self._refresh_ip_list).pack(side=tk.LEFT, padx=5)
        ttk.Button(button_frame, text=get_text("export_list"), command=self._export_ip_list).pack(side=tk.LEFT, padx=5)

        # Status bar
        self.ip_status_label = ttk.Label(self.ip_management_frame, text=get_text("total_ips") + ": 0 | " + get_text("allowed") + ": 0 | " + get_text("restricted") + ": 0")
        self.ip_status_label.pack(fill=tk.X, padx=10, pady=5)

        # Initial load of IP list
        self._refresh_ip_list()
    
    def _start_background_threads(self):
        """Start background threads for task queue and scheduler."""
        # Start task queue
        if not self.task_queue.is_running():
            self.task_queue.start()
        
        # Start scheduler
        if not self.scheduler.is_running():
            self.scheduler.start()
        
        # Set IP manager in HTTP server
        if self.http_server:
            self.http_server.set_ip_manager(self.ip_manager)
    
    def _schedule_gui_updates(self):
        """Schedule periodic GUI updates."""
        if not self.is_closing:
            self._update_status()
            self._update_time()
            self._refresh_logs_if_enabled()
            self.root.after(1000, self._schedule_gui_updates)  # Update every second
    
    def _update_status(self):
        """Update status displays."""
        try:
            # Update main status bar
            queue_status = get_queue_status()
            scheduler_status = get_scheduler_status()
            server_running = is_server_running()
            
            status_text = f"Queue: {queue_status['queue_length']} tasks | "
            status_text += f"Scheduler: {'Running' if scheduler_status['running'] else 'Stopped'} | "
            status_text += f"Server: {'Running' if server_running else 'Stopped'}"
            
            self.status_label.config(text=status_text)
            
            # Update Rate Loader status
            if hasattr(self, 'rate_loader_status'):
                self.rate_loader_status.config(state=tk.NORMAL)
                self.rate_loader_status.delete(1.0, tk.END)
                self.rate_loader_status.insert(tk.END, f"Server Status: {'Running' if server_running else 'Stopped'}\n\n")
                self.rate_loader_status.insert(tk.END, f"Queue Status:\n{queue_status}\n\n")
                self.rate_loader_status.insert(tk.END, f"Scheduler Status:\n{scheduler_status}")
                self.rate_loader_status.config(state=tk.DISABLED)
            
            # Update server buttons
            if server_running:
                self.start_server_btn.config(state=tk.DISABLED)
                self.stop_server_btn.config(state=tk.NORMAL)
            else:
                self.start_server_btn.config(state=tk.NORMAL)
                self.stop_server_btn.config(state=tk.DISABLED)
                
        except Exception as e:
            self._show_error(get_text("error_updating_status") + f": {str(e)}")
    
    def _update_time(self):
        """Update time display."""
        current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        self.time_label.config(text=current_time)
    
    def _refresh_logs_if_enabled(self):
        """Refresh logs if auto-refresh is enabled."""
        if self.auto_refresh_enabled.get():
            self._refresh_logs()
    
    def _save_settings(self):
        """Save settings to configuration file."""
        try:
            for key, var in self.settings_vars.items():
                if key in ["ssl", "compress_attachments", "auto_update_sql", "enable_price_export_scheduling"]:
                    # Convert boolean to "1"/"0" string for boolean settings
                    value = "1" if var.get() else "0"
                else:
                    value = var.get()
                self.config.set(key, value)

            messagebox.showinfo(get_text("settings_saved"))
            self._update_status()

        except Exception as e:
            self._show_error(get_text("error_saving_settings") + f": {str(e)}")
    
    def _reload_settings(self):
        """Reload settings from configuration file."""
        try:
            reload_config()
            self.config = get_config()

            # Update GUI variables
            for key, var in self.settings_vars.items():
                if key in ["ssl", "compress_attachments", "auto_update_sql", "enable_price_export_scheduling", "deeper_logging"]:
                    # Convert "1"/"0" string to boolean for boolean checkboxes
                    var.set(self.config.get_int(key, fallback=0) == 1)
                else:
                    var.set(self.config.get(key))

            # Update Price Export deeper logging checkbox
            if hasattr(self, 'price_export_deeper_logging_var'):
                self.price_export_deeper_logging_var.set(self.config.get_bool("deeper_logging", fallback=False))

            messagebox.showinfo(get_text("settings_reloaded"))

        except Exception as e:
            self._show_error(get_text("error_reloading_settings") + f": {str(e)}")
    
    def _run_export_mailer(self):
        """Run ExportMailer task."""
        try:
            task = ExportMailerTask()
            if enqueue_task(task):
                self.export_mailer_progress.start()
                self.last_export_mailer_run = datetime.now()
                self.export_mailer_last_run.config(text=get_text("last_run") + f": {self.last_export_mailer_run.strftime('%Y-%m-%d %H:%M:%S')}")
                self._log_to_export_mailer(get_text("task_enqueued"))
            else:
                self._show_error(get_text("error_running_export_mailer"))

        except Exception as e:
            self._show_error(get_text("error_running_export_mailer") + f": {str(e)}")
    
    def _run_price_export(self):
        """Run PriceExport task."""
        try:
            task = PriceExportTask()
            if enqueue_task(task):
                self.price_export_progress.start()
                self.last_price_export_run = datetime.now()
                self.price_export_last_run.config(text=get_text("last_run") + f": {self.last_price_export_run.strftime('%Y-%m-%d %H:%M:%S')}")
                self._log_to_price_export(get_text("task_enqueued"))
            else:
                self._show_error(get_text("error_running_price_export"))

        except Exception as e:
            self._show_error(get_text("error_running_price_export") + f": {str(e)}")

    def _execute_database_schema(self):
        """Execute database schema from SQL file or embedded schema."""
        try:
            if self.use_embedded_var.get():
                sql_file = None  # Use embedded schema
                source_desc = "embedded schema"
            else:
                sql_file = self.schema_file_var.get()
                if not sql_file or not os.path.exists(sql_file):
                    self._show_error(f"SQL file not found: {sql_file}")
                    return
                source_desc = f"file: {sql_file}"

            task = create_database_init_task(sql_file, validate_only=False)
            if enqueue_task(task):
                self.database_schema_progress.start()
                self.database_schema_last_run.config(text=f"Last run: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
                self._log_to_database_schema(f"Database schema execution task enqueued for {source_desc}")
            else:
                self._show_error("Failed to enqueue database schema task")

        except Exception as e:
            self._show_error(f"Error executing database schema: {str(e)}")

    def _validate_database_schema(self):
        """Validate database schema against SQL file or embedded schema."""
        try:
            if self.use_embedded_var.get():
                sql_file = None  # Use embedded schema
                source_desc = "embedded schema"
            else:
                sql_file = self.schema_file_var.get()
                if not sql_file or not os.path.exists(sql_file):
                    self._show_error(f"SQL file not found: {sql_file}")
                    return
                source_desc = f"file: {sql_file}"

            task = create_database_init_task(sql_file, validate_only=True)
            if enqueue_task(task):
                self.database_schema_progress.start()
                self.database_schema_last_run.config(text=f"Last run: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
                self._log_to_database_schema(f"Database schema validation task enqueued for {source_desc}")
            else:
                self._show_error("Failed to enqueue database schema validation task")

        except Exception as e:
            self._show_error(f"Error validating database schema: {str(e)}")

    def _parse_schema_file(self):
        """Parse and display schema file structure or embedded schema."""
        try:
            if self.use_embedded_var.get():
                sql_file = None  # Use embedded schema
                source_desc = "embedded schema"
            else:
                sql_file = self.schema_file_var.get()
                if not sql_file or not os.path.exists(sql_file):
                    self._show_error(f"SQL file not found: {sql_file}")
                    return
                source_desc = f"file: {sql_file}"

            # Parse the schema
            manager = DatabaseSchemaManager(sql_file)
            graph = manager.parse_sql_file()

            # Display results
            self._log_to_database_schema(f"Parsed {len(graph.objects)} objects from {source_desc}:")
            for obj_name, obj in graph.objects.items():
                self._log_to_database_schema(f"  {obj.object_type.value.upper()}: {obj_name} (line {obj.line_number})")
                if obj.dependencies:
                    deps_str = ", ".join(obj.dependencies)
                    self._log_to_database_schema(f"    Dependencies: {deps_str}")

            # Show execution order
            try:
                execution_order = graph.get_execution_order()
                self._log_to_database_schema(f"\nExecution order ({len(execution_order)} objects):")
                for i, obj_name in enumerate(execution_order, 1):
                    obj = graph.objects[obj_name]
                    self._log_to_database_schema(f"  {i:2d}. {obj.object_type.value.upper()}: {obj_name}")
            except Exception as e:
                self._log_to_database_schema(f"Could not determine execution order: {str(e)}")

        except Exception as e:
            self._show_error(f"Error parsing schema: {str(e)}")

    def _generate_schema_from_model(self):
        """Generate SQL schema from application data model."""
        try:
            # Create a sample data model based on the application's structure
            # This demonstrates the schema generation capability
            data_model = self._create_sample_data_model()

            # Generate schema
            manager = DatabaseSchemaManager()
            generated_sql = manager.generate_schema_from_model(data_model)

            # Display results
            self._log_to_database_schema("Generated SQL schema from data model:")
            self._log_to_database_schema("=" * 50)
            for line in generated_sql.split('\n'):
                if line.strip():  # Only log non-empty lines
                    self._log_to_database_schema(line)
            self._log_to_database_schema("=" * 50)
            self._log_to_database_schema("Schema generation completed successfully")

        except Exception as e:
            self._show_error(f"Error generating schema from model: {str(e)}")

    def _create_sample_data_model(self):
        """Create a sample data model based on application structure."""
        return {
            "sequences": [
                "price_export_seq",
                "export_mailer_seq",
                "task_queue_seq"
            ],
            "tables": {
                "price_export_log": {
                    "columns": [
                        {"name": "id", "type": "NUMBER", "nullable": False},
                        {"name": "date_processed", "type": "DATE", "nullable": False},
                        {"name": "status", "type": "VARCHAR2(20)", "nullable": False, "default": "'pending'"},
                        {"name": "json_data", "type": "CLOB", "nullable": True},
                        {"name": "error_message", "type": "VARCHAR2(500)", "nullable": True},
                        {"name": "created_at", "type": "TIMESTAMP", "nullable": False, "default": "SYSTIMESTAMP"}
                    ],
                    "primary_key": ["id"],
                    "indexes": [
                        {"name": "idx_price_export_date", "columns": ["date_processed"], "unique": False},
                        {"name": "idx_price_export_status", "columns": ["status"], "unique": False}
                    ]
                },
                "export_mailer_log": {
                    "columns": [
                        {"name": "id", "type": "NUMBER", "nullable": False},
                        {"name": "hotel_key", "type": "VARCHAR2(50)", "nullable": False},
                        {"name": "export_type", "type": "VARCHAR2(20)", "nullable": False},  # 'main' or 'blocks'
                        {"name": "file_path", "type": "VARCHAR2(500)", "nullable": True},
                        {"name": "file_size", "type": "NUMBER", "nullable": True},
                        {"name": "status", "type": "VARCHAR2(20)", "nullable": False, "default": "'pending'"},
                        {"name": "email_sent", "type": "CHAR(1)", "nullable": False, "default": "'N'"},
                        {"name": "created_at", "type": "TIMESTAMP", "nullable": False, "default": "SYSTIMESTAMP"}
                    ],
                    "primary_key": ["id"],
                    "indexes": [
                        {"name": "idx_export_mailer_hotel", "columns": ["hotel_key"], "unique": False},
                        {"name": "idx_export_mailer_status", "columns": ["status"], "unique": False}
                    ]
                },
                "task_queue": {
                    "columns": [
                        {"name": "id", "type": "NUMBER", "nullable": False},
                        {"name": "task_type", "type": "VARCHAR2(50)", "nullable": False},
                        {"name": "status", "type": "VARCHAR2(20)", "nullable": False, "default": "'queued'"},
                        {"name": "priority", "type": "NUMBER", "nullable": False, "default": "1"},
                        {"name": "parameters", "type": "CLOB", "nullable": True},
                        {"name": "result", "type": "CLOB", "nullable": True},
                        {"name": "error_message", "type": "VARCHAR2(1000)", "nullable": True},
                        {"name": "created_at", "type": "TIMESTAMP", "nullable": False, "default": "SYSTIMESTAMP"},
                        {"name": "started_at", "type": "TIMESTAMP", "nullable": True},
                        {"name": "completed_at", "type": "TIMESTAMP", "nullable": True}
                    ],
                    "primary_key": ["id"],
                    "indexes": [
                        {"name": "idx_task_queue_status", "columns": ["status"], "unique": False},
                        {"name": "idx_task_queue_type", "columns": ["task_type"], "unique": False},
                        {"name": "idx_task_queue_priority", "columns": ["priority"], "unique": False}
                    ]
                },
                "ip_access_log": {
                    "columns": [
                        {"name": "id", "type": "NUMBER", "nullable": False},
                        {"name": "ip_address", "type": "VARCHAR2(45)", "nullable": False},
                        {"name": "request_type", "type": "VARCHAR2(50)", "nullable": False},
                        {"name": "status", "type": "VARCHAR2(20)", "nullable": False, "default": "'allowed'"},
                        {"name": "user_agent", "type": "VARCHAR2(500)", "nullable": True},
                        {"name": "request_count", "type": "NUMBER", "nullable": False, "default": "1"},
                        {"name": "first_seen", "type": "TIMESTAMP", "nullable": False, "default": "SYSTIMESTAMP"},
                        {"name": "last_seen", "type": "TIMESTAMP", "nullable": False, "default": "SYSTIMESTAMP"}
                    ],
                    "primary_key": ["id"],
                    "indexes": [
                        {"name": "idx_ip_access_ip", "columns": ["ip_address"], "unique": False},
                        {"name": "idx_ip_access_status", "columns": ["status"], "unique": False}
                    ]
                }
            },
            "views": {
                "active_tasks": "SELECT * FROM task_queue WHERE status IN ('queued', 'running')",
                "failed_exports": "SELECT * FROM price_export_log WHERE status = 'failed' ORDER BY created_at DESC",
                "recent_ip_activity": "SELECT * FROM ip_access_log WHERE last_seen >= SYSDATE - 1 ORDER BY last_seen DESC"
            }
        }

    def _browse_schema_file(self):
        """Browse for SQL schema file."""
        try:
            file_path = filedialog.askopenfilename(
                title="Select SQL Schema File",
                filetypes=[("SQL files", "*.sql"), ("All files", "*.*")],
                initialdir="docs"
            )
            if file_path:
                self.schema_file_var.set(file_path)
        except Exception as e:
            self._show_error(f"Error browsing for file: {str(e)}")

    def _on_embedded_schema_changed(self):
        """Toggle enabling/disabling custom schema file input."""
        use_embedded = self.use_embedded_var.get()
        state = tk.DISABLED if use_embedded else tk.NORMAL
        self.schema_file_entry.config(state=state)
        if use_embedded:
            self.schema_file_var.set("")
    
    def _start_server(self):
        """Start HTTP server."""
        try:
            if start_server():
                self._log_to_rate_loader("HTTP server started successfully")
            else:
                self._show_error("Failed to start HTTP server")
                
        except Exception as e:
            self._show_error(get_text("error_starting_server") + f": {str(e)}")
    
    def _stop_server(self):
        """Stop HTTP server."""
        try:
            if stop_server():
                self._log_to_rate_loader("HTTP server stopped successfully")
            else:
                self._show_error("Failed to stop HTTP server")
                
        except Exception as e:
            self._show_error(get_text("error_stopping_server") + f": {str(e)}")
    
    def _on_auto_start_changed(self):
        """Handle auto-start checkbox state change."""
        try:
            # Save the checkbox state to configuration
            value = "1" if self.auto_start_server_var.get() else "0"
            self.config.set("auto_start_server", value)
            self._log_to_rate_loader(f"Auto-start server setting updated to: {'Enabled' if self.auto_start_server_var.get() else 'Disabled'}")
        except Exception as e:
            self._show_error(f"Error saving auto-start setting: {str(e)}")

    def _on_price_export_deeper_logging_changed(self):
        """Handle price export deeper logging checkbox state change."""
        try:
            # Save the checkbox state to configuration
            value = "1" if self.price_export_deeper_logging_var.get() else "0"
            self.config.set("deeper_logging", value)
            self._log_to_price_export(f"Deeper logging setting updated to: {'Enabled' if self.price_export_deeper_logging_var.get() else 'Disabled'}")
        except Exception as e:
            self._show_error(f"Error saving deeper logging setting: {str(e)}")
    
    def _auto_start_server_if_enabled(self):
        """Auto-start server if enabled in configuration."""
        try:
            if self.auto_start_server_var.get():
                self._log_to_rate_loader("Auto-starting server as configured...")
                if start_server():
                    self._log_to_rate_loader("Server auto-started successfully")
                else:
                    self._log_to_rate_loader("Failed to auto-start server")
        except Exception as e:
            self._log_to_rate_loader(f"Error during server auto-start: {str(e)}")
    
    def _on_log_file_changed(self, event=None):
        """Handle log file selection change."""
        self._refresh_logs()
    
    def _refresh_logs(self):
        """Refresh log display."""
        try:
            log_file = self.selected_log_file.get()
            log_path = os.path.join("log", log_file)
            
            if os.path.exists(log_path):
                with open(log_path, 'r', encoding='utf-8') as f:
                    lines = f.readlines()
                    # Show last 100 lines
                    last_lines = lines[-100:] if len(lines) > 100 else lines
                    
                    self.log_display.config(state=tk.NORMAL)
                    self.log_display.delete(1.0, tk.END)
                    self.log_display.insert(tk.END, ''.join(last_lines))
                    self.log_display.config(state=tk.DISABLED)
                    self.log_display.see(tk.END)
            else:
                self.log_display.config(state=tk.NORMAL)
                self.log_display.delete(1.0, tk.END)
                self.log_display.insert(tk.END, f"Log file not found: {log_path}")
                self.log_display.config(state=tk.DISABLED)
                
        except Exception as e:
            self._show_error(get_text("error_refreshing_logs") + f": {str(e)}")
    
    def _clear_log(self):
        """Clear selected log file."""
        try:
            log_file = self.selected_log_file.get()
            log_path = os.path.join("log", log_file)
            
            if messagebox.askyesno(get_text("confirm_clear_log"), get_text("confirm_clear_log") + f" {log_file}?"):
                with open(log_path, 'w', encoding='utf-8') as f:
                    f.write("")
                self._refresh_logs()
                messagebox.showinfo(get_text("clear_log"), get_text("log_cleared") + f" {log_file}")
                
        except Exception as e:
            self._show_error(get_text("error_clearing_log") + f": {str(e)}")
    
    def _log_to_export_mailer(self, message):
        """Log message to Export Mailer status."""
        timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        self.export_mailer_status.config(state=tk.NORMAL)
        self.export_mailer_status.insert(tk.END, f"[{timestamp}] {message}\n")
        self.export_mailer_status.config(state=tk.DISABLED)
        self.export_mailer_status.see(tk.END)
    
    def _log_to_price_export(self, message):
        """Log message to Price Export status."""
        timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        self.price_export_status.config(state=tk.NORMAL)
        self.price_export_status.insert(tk.END, f"[{timestamp}] {message}\n")
        self.price_export_status.config(state=tk.DISABLED)
        self.price_export_status.see(tk.END)

    def _log_to_database_schema(self, message):
        """Log message to Database Schema status."""
        timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        self.database_schema_status.config(state=tk.NORMAL)
        self.database_schema_status.insert(tk.END, f"[{timestamp}] {message}\n")
        self.database_schema_status.config(state=tk.DISABLED)
        self.database_schema_status.see(tk.END)
    
    def _log_to_rate_loader(self, message):
        """Log message to Rate Loader status."""
        timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        if hasattr(self, 'rate_loader_status'):
            self.rate_loader_status.config(state=tk.NORMAL)
            self.rate_loader_status.insert(tk.END, f"[{timestamp}] {message}\n")
            self.rate_loader_status.config(state=tk.DISABLED)
            self.rate_loader_status.see(tk.END)
    
    def _show_error(self, message):
        """Show error message."""
        messagebox.showerror(get_text("error"), message)
    
    def _show_about(self):
        """Show about dialog."""
        messagebox.showinfo(get_text("about_title"), get_text("about_text"))

    def _show_help(self, tab_name):
        """Show help for a specific tab."""
        help_key = f"help_{tab_name}"
        help_text = get_text(help_key)
        if help_text:
            messagebox.showinfo(f"Справка - {get_text(f'tab_{tab_name}')}", help_text)
        else:
            messagebox.showinfo("Справка", f"Справка для раздела '{get_text(f'tab_{tab_name}')}' недоступна.")

    def _add_tooltip(self, widget, text):
        """Add tooltip to widget."""
        if not text:
            return

        def show_tooltip(event):
            tooltip = tk.Toplevel()
            tooltip.wm_overrideredirect(True)
            tooltip.wm_geometry(f"+{event.x_root+10}+{event.y_root+10}")

            label = tk.Label(tooltip, text=text, background="#ffffe0", relief="solid", borderwidth=1, wraplength=300, justify="left")
            label.pack()

            def hide_tooltip():
                tooltip.destroy()

            widget.tooltip = tooltip
            widget.after(5000, hide_tooltip)  # Hide after 5 seconds

        def hide_tooltip(event):
            if hasattr(widget, 'tooltip'):
                widget.tooltip.destroy()

        widget.bind("<Enter>", show_tooltip)
        widget.bind("<Leave>", hide_tooltip)
    
    def _on_closing(self):
        """Handle window closing."""
        if self.is_closing:
            return
            
        self.is_closing = True
        
        try:
            # Stop background components
            self.task_queue.stop()
            self.scheduler.stop()
            self.http_server.stop()
            
            # Close GUI
            self.root.destroy()
            
        except Exception as e:
            print(f"Error during shutdown: {str(e)}")
            self.root.destroy()
    
    def _on_global_access_changed(self):
        """Handle global access mode change."""
        try:
            new_mode = self.global_access_var.get()
            if hasattr(self, 'ip_manager') and self.ip_manager:
                self.ip_manager.set_global_access(new_mode)
                self._log_to_ip_management(f"Global access mode changed to: {new_mode}")
        except Exception as e:
            self._show_error(f"Error changing global access mode: {str(e)}")

    def _toggle_selected_ip(self):
        """Toggle status of selected IP address."""
        try:
            selection = self.ip_tree.selection()
            if not selection:
                messagebox.showwarning(get_text("select_ip_to_toggle"), get_text("select_ip_to_toggle"))
                return
            
            item = self.ip_tree.item(selection[0])
            ip_address = item['values'][0]
            current_status = item['values'][1]
            
            new_status = "restricted" if current_status == "allowed" else "allowed"
            
            if hasattr(self, 'ip_manager') and self.ip_manager:
                self.ip_manager.set_ip_status(ip_address, new_status)
                self._refresh_ip_list()
                self._log_to_ip_management(f"IP {ip_address} status changed to: {new_status}")
        except Exception as e:
            self._show_error(f"Error toggling IP status: {str(e)}")

    def _remove_selected_ip(self):
        """Remove selected IP address from tracking."""
        try:
            selection = self.ip_tree.selection()
            if not selection:
                messagebox.showwarning(get_text("select_ip_to_remove"), get_text("select_ip_to_remove"))
                return
            
            item = self.ip_tree.item(selection[0])
            ip_address = item['values'][0]
            
            if messagebox.askyesno(get_text("confirm_remove_ip"), get_text("confirm_remove_ip") + f" {ip_address}?"):
                if hasattr(self, 'ip_manager') and self.ip_manager:
                    self.ip_manager.remove_ip(ip_address)
                    self._refresh_ip_list()
                    self._log_to_ip_management(f"IP {ip_address} removed from tracking")
        except Exception as e:
            self._show_error(f"Error removing IP: {str(e)}")

    def _refresh_ip_list(self):
        """Refresh IP address list."""
        try:
            # Clear existing items
            for item in self.ip_tree.get_children():
                self.ip_tree.delete(item)
            
            if hasattr(self, 'ip_manager') and self.ip_manager:
                ips = self.ip_manager.get_all_ips()
                global_access = ips.get('global_access', 'allowed')
                
                # Update global access radio buttons
                self.global_access_var.set(global_access)
                
                allowed_count = 0
                restricted_count = 0
                
                for ip_address, data in ips.get('ips', {}).items():
                    status = data.get('status', 'allowed')
                    last_seen = data.get('last_seen', 'Never')
                    request_count = data.get('request_count', 0)
                    last_request = data.get('last_request_type', 'N/A')
                    
                    self.ip_tree.insert("", tk.END, values=(
                        ip_address, status, last_seen, request_count, last_request
                    ))
                    
                    if status == 'allowed':
                        allowed_count += 1
                    else:
                        restricted_count += 1
                
                total_count = allowed_count + restricted_count
                self.ip_status_label.config(
                    text=f"Total IPs: {total_count} | Allowed: {allowed_count} | Restricted: {restricted_count}"
                )
        except Exception as e:
            self._show_error(get_text("error_refreshing_ip_list") + f": {str(e)}")

    def _export_ip_list(self):
        """Export IP list to CSV file."""
        try:
            import csv
            
            if not hasattr(self, 'ip_manager') or not self.ip_manager:
                messagebox.showwarning(get_text("export_list"), get_text("ip_manager_not_available"))
                return
            
            file_path = filedialog.asksaveasfilename(
                defaultextension=".csv",
                filetypes=[("CSV files", "*.csv"), ("All files", "*.*")]
            )
            
            if file_path:
                ips = self.ip_manager.get_all_ips()
                
                with open(file_path, 'w', newline='', encoding='utf-8') as csvfile:
                    writer = csv.writer(csvfile)
                    writer.writerow(['IP Address', 'Status', 'First Seen', 'Last Seen', 'Request Count', 'Last Request Type'])
                    
                    for ip_address, data in ips.get('ips', {}).items():
                        writer.writerow([
                            ip_address,
                            data.get('status', 'allowed'),
                            data.get('first_seen', ''),
                            data.get('last_seen', ''),
                            data.get('request_count', 0),
                            data.get('last_request_type', '')
                        ])
                
                messagebox.showinfo(get_text("export_list"), get_text("export_list") + f" {file_path}")
                self._log_to_ip_management(f"IP list exported to {file_path}")
        except Exception as e:
            self._show_error(get_text("error_exporting_ip_list") + f": {str(e)}")

    def _log_to_ip_management(self, message):
        """Log message to IP Management status."""
        timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        self.logger_manager.info(f"[IPMANAGER] {timestamp} - {message}")
    
    def run(self):
        """Run the GUI application."""
        try:
            self.root.mainloop()
        except Exception as e:
            print(f"GUI error: {str(e)}")


def main():
    """Main entry point for GUI application."""
    try:
        app = RateLoaderGUI()
        app.run()
    except Exception as e:
        print(f"Failed to start GUI: {str(e)}")
        messagebox.showerror("Startup Error", f"Failed to start GUI: {str(e)}")


if __name__ == "__main__":
    main()
