#!/usr/bin/env python3
"""
DecentraBrowser Domain Refresh Fix

This script fixes issues with domain creation not properly updating in the UI.
It ensures that when a domain is created, it immediately appears in the domain list.

Usage:
    python domain_refresh_fix.py
"""

import os
import sys
import shutil
import re

def backup_file(file_path):
    """Create a backup of a file before modifying it."""
    backup_path = file_path + '.refresh.bak'
    print(f"Creating backup: {backup_path}")
    shutil.copy2(file_path, backup_path)
    return backup_path

def fix_domain_creation_refresh(main_window_py):
    """Fix domain creation to properly refresh the UI."""
    with open(main_window_py, 'r', encoding='utf-8') as f:
        content = f.read()
    
    # 1. First, check if refresh_domains is correctly called after domain creation
    create_domain_dialog_pattern = r'def create_domain_dialog\(self\):.*?dialog\.accept\(\).*?(?=\n\s*# Refresh domains|\n\s*self\.refresh_domains|\n\s*def )'
    match = re.search(create_domain_dialog_pattern, content, re.DOTALL)
    
    if match:
        create_dialog_code = match.group(0)
        
        # Check if refresh_domains is called
        if "self.refresh_domains()" not in create_dialog_code:
            print("Adding domain refresh call after creation")
            # Add refresh call
            updated_dialog = create_dialog_code + "\n            # Refresh domains to show newly created domain\n            self.refresh_domains()\n"
            content = content.replace(create_dialog_code, updated_dialog)
    
    # 2. Next, enhance the refresh_domains method to ensure proper UI updating
    refresh_domains_pattern = r'def refresh_domains\(self\):.*?(?=\n    def|\Z)'
    match = re.search(refresh_domains_pattern, content, re.DOTALL)
    
    if match:
        refresh_method = match.group(0)
        
        # Check if it's updating the domain table
        if "update_domains_table" not in refresh_method:
            print("Refresh domains method doesn't update the domain table - adding this functionality")
            
            # Add proper domain table update
            updated_refresh = """def refresh_domains(self):
        
        try:
            # Show refreshing status
            if hasattr(self, 'statusBar') and callable(getattr(self, 'statusBar')):
                self.statusBar().showMessage("Refreshing domains...", 1000)
            
            # Get domains from DDNS
            success, result = self.network_client.get_domains()
            
            if success:
                # Update domains table
                self.update_domains_table(success, result)
                
                # Log success
                print(f"Domains refreshed - found {len(result)} domains")
                
                # Update status bar
                if hasattr(self, 'statusBar') and callable(getattr(self, 'statusBar')):
                    self.statusBar().showMessage(f"Found {len(result)} domains", 3000)
            else:
                # Log failure
                print(f"Failed to refresh domains: {result}")
                
                # Update status bar
                if hasattr(self, 'statusBar') and callable(getattr(self, 'statusBar')):
                    self.statusBar().showMessage(f"Failed to refresh domains: {result}", 3000)
                
                # Still try to update with empty list to clear previous data
                self.update_domains_table(False, [])
        except Exception as e:
            # Log error
            print(f"Error refreshing domains: {str(e)}")
            
            # Update status bar
            if hasattr(self, 'statusBar') and callable(getattr(self, 'statusBar')):
                self.statusBar().showMessage(f"Error refreshing domains: {str(e)}", 5000)"""
            
            content = content.replace(refresh_method, updated_refresh)
        else:
            print("Refresh domains method already updates the domain table")
    
    # 3. Enhance update_domains_table method for better error handling and UI feedback
    update_table_pattern = r'def update_domains_table\(self, success, result\):.*?(?=\n    def|\Z)'
    match = re.search(update_table_pattern, content, re.DOTALL)
    
    if match:
        update_table_method = match.group(0)
        
        # Check if the method needs improvements
        if "self.domains_table.setRowCount(0)" not in update_table_method:
            print("Enhancing update_domains_table method for better UI refresh")
            
            updated_table_method = """def update_domains_table(self, success, result):
        
        try:
            # Clear the table first
            self.domains_table.setRowCount(0)
            
            if not success:
                # Show error if we failed to get domains
                if hasattr(self, 'statusBar') and callable(getattr(self, 'statusBar')):
                    self.statusBar().showMessage(f"Failed to get domains: {result}", 5000)
                return
            
            # Process domains
            domains = result
            
            if not domains:
                # No domains to display
                if hasattr(self, 'statusBar') and callable(getattr(self, 'statusBar')):
                    self.statusBar().showMessage("No domains found", 3000)
                return
            
            # Add domains to table
            for i, domain in enumerate(domains):
                # Insert row
                self.domains_table.insertRow(i)
                
                # Get DDNS info
                in_ddns = self.ddns.has_entry(domain.full_name)
                
                # Domain name
                self.domains_table.setItem(i, 0, QTableWidgetItem(domain.full_name))
                
                # IP and Port
                ip_port = f"{domain.ip}:{domain.port}"
                self.domains_table.setItem(i, 1, QTableWidgetItem(ip_port))
                
                # Title
                title = domain.title if domain.title else ""
                self.domains_table.setItem(i, 2, QTableWidgetItem(title))
                
                # Status
                status = "ONLINE" if self.network_client.is_domain_online(domain) else "OFFLINE"
                status_item = QTableWidgetItem(status)
                status_item.setForeground(QBrush(QColor("green" if status == "ONLINE" else "red")))
                self.domains_table.setItem(i, 3, status_item)
                
                # Actions cell
                actions_widget = QWidget()
                actions_layout = QHBoxLayout(actions_widget)
                actions_layout.setContentsMargins(2, 2, 2, 2)
                
                # Different actions based on whether domain is in DDNS
                if in_ddns:
                    btn_connect = QPushButton("Connect")
                    btn_connect.setProperty("domain", domain.full_name)
                    btn_connect.clicked.connect(self.connect_to_domain)
                    
                    btn_p2p = QPushButton("P2P")
                    btn_p2p.setProperty("domain", domain.full_name)
                    btn_p2p.clicked.connect(self.p2p_connect)
                    
                    btn_unregister = QPushButton("Unregister")
                    btn_unregister.setProperty("domain", domain.full_name)
                    btn_unregister.clicked.connect(self.unregister_domain)
                    
                    actions_layout.addWidget(btn_connect)
                    actions_layout.addWidget(btn_p2p)
                    actions_layout.addWidget(btn_unregister)
                else:
                    btn_add = QPushButton("Add to DDNS")
                    btn_add.setProperty("domain", domain.full_name)
                    btn_add.clicked.connect(self.add_to_ddns)
                    
                    actions_layout.addWidget(btn_add)
                
                self.domains_table.setCellWidget(i, 4, actions_widget)
                
            # Resize columns to content
            self.domains_table.resizeColumnsToContents()
            
            # Show success message with domain count
            if hasattr(self, 'statusBar') and callable(getattr(self, 'statusBar')):
                self.statusBar().showMessage(f"Found {len(domains)} domains", 3000)
                
        except Exception as e:
            # Log the error
            print(f"Error updating domains table: {str(e)}")
            
            # Show error in status bar
            if hasattr(self, 'statusBar') and callable(getattr(self, 'statusBar')):
                self.statusBar().showMessage(f"Error updating domains table: {str(e)}", 5000)"""
            
            content = content.replace(update_table_method, updated_table_method)
        else:
            print("update_domains_table method already has good refresh logic")
    
    # 4. Ensure network_client.get_domains properly queries both local and central server
    # We'll need to check the NetworkClient class
    with open(main_window_py, 'w', encoding='utf-8') as f:
        f.write(content)
    
    print(f"Updated domain refresh logic in {main_window_py}")
    return True

def fix_network_client_get_domains(client_py):
    """Ensure network_client.get_domains properly syncs with central server."""
    if not os.path.exists(client_py):
        print(f"NetworkClient file not found at {client_py}")
        return False
    
    with open(client_py, 'r', encoding='utf-8') as f:
        content = f.read()
    
    # Find the get_domains method
    get_domains_pattern = r'def get_domains\(self(?:\, .*?)?\):.*?(?=\n    def|\Z)'
    match = re.search(get_domains_pattern, content, re.DOTALL)
    
    if not match:
        print("Could not find get_domains method in NetworkClient")
        return False
    
    get_domains_method = match.group(0)
    
    # Check if it syncs with central server before returning results
    if "sync_domains_with_central_server" not in get_domains_method and hasattr(self, 'sync_domains_with_central_server'):
        print("Enhancing get_domains to sync with central server")
        
        # Create improved get_domains method
        improved_get_domains = """def get_domains(self):
        
        try:
            # First sync with central server if possible
            if hasattr(self, 'sync_domains_with_central_server'):
                try:
                    logger.info("Syncing domains with central server before retrieving domain list")
                    sync_result, sync_message = self.sync_domains_with_central_server()
                    if not sync_result:
                        logger.warning(f"Failed to sync with central server: {sync_message}")
                except Exception as e:
                    logger.error(f"Error syncing with central server: {str(e)}")
            
            # Get domains from DDNS
            entries = self.ddns.list_entries()
            domains = []
            
            for domain_name, entry in entries.items():
                # Create domain object
                domain = Domain(
                    prefix=domain_name.split('.')[0],
                    main=domain_name.split('.')[1],
                    suffix=domain_name.split('.')[2],
                    ip=entry['ip'],
                    port=entry['port']
                )
                
                # Add title if available
                if 'title' in entry:
                    domain.title = entry['title']
                
                domains.append(domain)
            
            return True, domains
        except Exception as e:
            logger.error(f"Error getting domains: {str(e)}")
            return False, str(e)"""
        
        # Update the content
        content = content.replace(get_domains_method, improved_get_domains)
        
        # Write the updated content
        with open(client_py, 'w', encoding='utf-8') as f:
            f.write(content)
        
        print(f"Enhanced get_domains method in {client_py}")
    else:
        print("get_domains method appears to already sync with central server")
    
    return True

def add_explicit_domain_refresh_button(main_window_py):
    """Add an explicit refresh button to the domains tab for easier testing."""
    with open(main_window_py, 'r', encoding='utf-8') as f:
        content = f.read()
    
    # Find the setup_domains_tab method
    setup_pattern = r'def setup_domains_tab\(self\):.*?(?=\n    def|\Z)'
    match = re.search(setup_pattern, content, re.DOTALL)
    
    if not match:
        print("Could not find setup_domains_tab method")
        return False
    
    setup_method = match.group(0)
    
    # Check if a refresh button already exists
    if "refresh_btn = QPushButton" in setup_method:
        print("Refresh button already exists in domains tab")
        return True
    
    # Find a good place to add the refresh button
    table_pattern = r'(# Create domains table.*?self\.domains_table\.setHorizontalHeaderLabels\(\[.*?\]\))'
    match = re.search(table_pattern, setup_method, re.DOTALL)
    
    if not match:
        print("Could not find a place to add refresh button")
        return False
    
    table_code = match.group(1)
    
    # Add refresh button
    refresh_button_code = table_code + """
        
        # Add refresh button
        refresh_layout = QHBoxLayout()
        refresh_layout.addStretch()
        
        refresh_btn = QPushButton("Refresh Domains")
        refresh_btn.clicked.connect(self.refresh_domains)
        refresh_layout.addWidget(refresh_btn)
        
        layout.addLayout(refresh_layout)"""
    
    # Update the content
    updated_setup = setup_method.replace(table_code, refresh_button_code)
    content = content.replace(setup_method, updated_setup)
    
    # Write the updated content
    with open(main_window_py, 'w', encoding='utf-8') as f:
        f.write(content)
    
    print(f"Added explicit domain refresh button to {main_window_py}")
    return True

def add_debug_logging(main_window_py, client_py):
    """Add more debug logging to help diagnose domain refresh issues."""
    files_to_update = [(main_window_py, "MainWindow"), (client_py, "NetworkClient")]
    
    for file_path, class_name in files_to_update:
        if not os.path.exists(file_path):
            print(f"{file_path} not found, skipping debug logging")
            continue
        
        with open(file_path, 'r', encoding='utf-8') as f:
            content = f.read()
        
        # Add more print statements to key methods
        methods_to_log = [
            {"name": "create_domain", "message": f"{class_name}: Creating domain"},
            {"name": "refresh_domains", "message": f"{class_name}: Refreshing domains"},
            {"name": "update_domains_table", "message": f"{class_name}: Updating domains table"}
        ]
        
        updated_content = content
        
        for method in methods_to_log:
            method_pattern = f'def {method["name"]}\\(self.*?\\):.*?\\n        '
            match = re.search(method_pattern, content)
            
            if match:
                method_start = match.group(0)
                new_method_start = method_start + f'print("{method["message"]}...")\n        '
                updated_content = updated_content.replace(method_start, new_method_start)
        
        # Write the updated content
        with open(file_path, 'w', encoding='utf-8') as f:
            f.write(updated_content)
        
        print(f"Added debug logging to {file_path}")
    
    return True

def main():
    """Main function."""
    # Find DecentraBrowser installation directory
    base_dir = None
    possible_paths = [
        os.path.join(".", "decentrabrowser"),
        os.path.join("..", "decentrabrowser"),
        os.path.join(os.path.dirname(os.path.abspath(__file__)), "decentrabrowser")
    ]
    
    for path in possible_paths:
        if os.path.isdir(path):
            base_dir = path
            break
    
    if not base_dir:
        print("Error: Could not find DecentraBrowser directory.")
        print("Please run this script from the same directory as the 'decentrabrowser' folder.")
        return 1
    
    print(f"Found DecentraBrowser at: {base_dir}")
    
    # Target files
    main_window_py = os.path.join(base_dir, "client", "gui", "main_window.py")
    client_py = os.path.join(base_dir, "client", "network", "client.py")
    
    if not os.path.exists(main_window_py):
        print(f"Error: {main_window_py} not found.")
        return 1
    
    if not os.path.exists(client_py):
        print(f"Warning: {client_py} not found. Will only fix MainWindow.")
    
    # Create backups
    backup_file(main_window_py)
    if os.path.exists(client_py):
        backup_file(client_py)
    
    # Fix domain creation refresh
    fix_domain_creation_refresh(main_window_py)
    
    # Fix NetworkClient get_domains method
    if os.path.exists(client_py):
        fix_network_client_get_domains(client_py)
    
    # Add explicit domain refresh button
    add_explicit_domain_refresh_button(main_window_py)
    
    # Add debug logging
    add_debug_logging(main_window_py, client_py)
    
    print("\nDomain refresh fix applied successfully!")
    print("\nThis fix includes:")
    print("1. Enhanced domain refresh after creation")
    print("2. Improved domain table updates")
    print("3. Added explicit refresh button to domains tab")
    print("4. Added debug logging to help diagnose issues")
    
    print("\nPlease restart DecentraBrowser to apply the changes.")
    
    return 0

if __name__ == "__main__":
    sys.exit(main())
