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

This script directly fixes the domain creation functionality in DecentraBrowser
by patching the create_domain_dialog and register_domain methods with a more
robust implementation that handles central server communication properly.

Usage:
    python domain_creation_fix.py
"""

import os
import sys
import shutil
import re
import json

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

def fix_create_domain_dialog(main_window_py):
    """Fix the create_domain_dialog method in MainWindow class."""
    with open(main_window_py, 'r', encoding='utf-8') as f:
        content = f.read()
    
    # Find the entire create_domain_dialog method
    method_pattern = r'def create_domain_dialog\(self\):.*?(?=\n    def |\Z)'
    match = re.search(method_pattern, content, re.DOTALL)
    
    if not match:
        print("Could not find create_domain_dialog method")
        return False
    
    old_method = match.group(0)
    
    # Create the new method with a robust implementation
    new_method = """def create_domain_dialog(self):
        
        dialog = QDialog(self)
        dialog.setWindowTitle("Create Domain")
        dialog.setMinimumSize(400, 350)
        
        layout = QVBoxLayout()
        
        # Domain name inputs
        name_layout = QFormLayout()
        
        prefix_input = QLineEdit()
        main_input = QLineEdit()
        suffix_input = QLineEdit()
        
        name_layout.addRow("Prefix:", prefix_input)
        name_layout.addRow("Main:", main_input)
        name_layout.addRow("Suffix:", suffix_input)
        
        # Domain title
        title_input = QLineEdit()
        name_layout.addRow("Title:", title_input)
        
        # Port
        port_spin = QSpinBox()
        port_spin.setMinimum(1024)
        port_spin.setMaximum(65535)
        port_spin.setValue(8844)
        name_layout.addRow("Port:", port_spin)
        
        # Status indicator
        status_label = QLabel("")
        status_label.setStyleSheet("color: gray;")
        
        # Create buttons
        button_layout = QHBoxLayout()
        check_button = QPushButton("Check Availability")
        create_button = QPushButton("Create Domain")
        create_button.setEnabled(False)  # Disabled until checked
        
        button_layout.addWidget(check_button)
        button_layout.addWidget(create_button)
        
        def check_availability():
            prefix = prefix_input.text()
            main = main_input.text()
            suffix = suffix_input.text()
            
            if not prefix or not main or not suffix:
                QMessageBox.warning(dialog, "Error", "All domain name parts are required")
                return
            
            # Create a temporary domain
            temp_domain = Domain(
                prefix=prefix,
                main=main,
                suffix=suffix,
                ip=get_local_ip(),
                port=port_spin.value()
            )
            
            # Show checking status
            status_label.setText("Checking domain availability...")
            status_label.setStyleSheet("color: blue;")
            dialog.repaint()  # Force UI update
            
            # Check availability with central server
            try:
                # Direct check with central server
                import requests
                check_url = f"http://jcmc.serveminecraft.net/cent.php?check={temp_domain.full_name}"
                response = requests.get(check_url, timeout=10)
                
                if response.status_code == 200:
                    try:
                        data = response.json()
                        if data.get('available') is True:
                            # Domain is available
                            status_label.setText("✓ Domain is available!")
                            status_label.setStyleSheet("color: green; font-weight: bold;")
                            create_button.setEnabled(True)
                        else:
                            # Domain not available
                            reason = data.get('reason', 'Domain is already taken')
                            status_label.setText(f"✗ Not available: {reason}")
                            status_label.setStyleSheet("color: red;")
                            create_button.setEnabled(False)
                    except:
                        # Fallback for non-JSON response
                        if "available" in response.text.lower():
                            status_label.setText("✓ Domain is available!")
                            status_label.setStyleSheet("color: green; font-weight: bold;")
                            create_button.setEnabled(True)
                        else:
                            status_label.setText("✗ Domain is not available")
                            status_label.setStyleSheet("color: red;")
                            create_button.setEnabled(False)
                else:
                    # HTTP error
                    status_label.setText(f"⚠ Server error: HTTP {response.status_code}")
                    status_label.setStyleSheet("color: orange;")
                    create_button.setEnabled(False)
            except Exception as e:
                # Network error
                status_label.setText(f"⚠ Connection error: {str(e)}")
                status_label.setStyleSheet("color: orange;")
                create_button.setEnabled(False)
        
        check_button.clicked.connect(check_availability)
        
        def create_domain():
            prefix = prefix_input.text()
            main = main_input.text()
            suffix = suffix_input.text()
            title = title_input.text()
            port = port_spin.value()
            
            if not prefix or not main or not suffix:
                QMessageBox.warning(dialog, "Error", "All domain name parts are required")
                return
            
            # Create domain
            domain = Domain(
                prefix=prefix,
                main=main,
                suffix=suffix,
                ip=get_local_ip(),
                port=port
            )
            domain.title = title
            
            # Show registering status
            status_label.setText("Registering domain...")
            status_label.setStyleSheet("color: blue;")
            dialog.repaint()  # Force UI update
            
            # Register with central server directly
            try:
                import requests
                register_url = f"http://jcmc.serveminecraft.net/cent.php?register={domain.full_name}&ip={domain.ip}&port={port}"
                if title:
                    register_url += f"&title={title}"
                
                response = requests.get(register_url, timeout=10)
                
                if response.status_code == 200:
                    try:
                        data = response.json()
                        if data.get('success') is True:
                            # Successfully registered with central server
                            # Now register locally
                            
                            # Add to DDNS
                            self.ddns.add_entry(domain.full_name, domain.ip, domain.port)
                            
                            # Store as my domain
                            self.my_domain = domain
                            
                            # Start domain server if not running
                            if not self.domain_server.is_running():
                                self.domain_server.domain = domain
                                self.domain_server.port = port
                                self.domain_server.start()
                                
                                # Update status
                                self.update_server_status()
                            
                            self.statusBar.showMessage(f"Domain {domain.full_name} created and registered", 3000)
                            dialog.accept()
                            
                            # Refresh domains
                            self.refresh_domains()
                        else:
                            # Registration failed
                            error = data.get('error', 'Unknown error from central server')
                            QMessageBox.warning(dialog, "Error", f"Failed to register domain: {error}")
                    except:
                        # Fallback for non-JSON response
                        if "success" in response.text.lower():
                            # Assume success if the word appears in response
                            
                            # Add to DDNS
                            self.ddns.add_entry(domain.full_name, domain.ip, domain.port)
                            
                            # Store as my domain
                            self.my_domain = domain
                            
                            # Start domain server if not running
                            if not self.domain_server.is_running():
                                self.domain_server.domain = domain
                                self.domain_server.port = port
                                self.domain_server.start()
                                
                                # Update status
                                self.update_server_status()
                            
                            self.statusBar.showMessage(f"Domain {domain.full_name} created and registered", 3000)
                            dialog.accept()
                            
                            # Refresh domains
                            self.refresh_domains()
                        else:
                            QMessageBox.warning(dialog, "Error", f"Failed to register domain: {response.text}")
                else:
                    # HTTP error
                    QMessageBox.warning(dialog, "Error", f"Failed to register domain: HTTP {response.status_code}")
            except Exception as e:
                # Network error
                QMessageBox.warning(dialog, "Error", f"Network error registering domain: {str(e)}")
        
        create_button.clicked.connect(create_domain)
        
        # Add widgets to layout
        layout.addLayout(name_layout)
        layout.addWidget(status_label)
        layout.addLayout(button_layout)
        
        dialog.setLayout(layout)
        dialog.exec_()"""
    
    # Replace the old method with the new one
    updated_content = content.replace(old_method, new_method)
    
    # Write the updated content
    with open(main_window_py, 'w', encoding='utf-8') as f:
        f.write(updated_content)
    
    print(f"Fixed create_domain_dialog method in {main_window_py}")
    return True

def fix_register_domain(client_py):
    """Fix the register_domain method in NetworkClient class."""
    with open(client_py, 'r', encoding='utf-8') as f:
        content = f.read()
    
    # Find the register_domain method
    method_pattern = r'def register_domain\(self, domain\):.*?(?=\n    def |\Z)'
    match = re.search(method_pattern, content, re.DOTALL)
    
    if not match:
        print("Could not find register_domain method")
        return False
    
    old_method = match.group(0)
    
    # Create the new method
    new_method = """def register_domain(self, domain):
        
        try:
            # Prepare domain data
            domain_name = domain.full_name
            domain_data = domain.to_dict()
            
            # Log registration attempt
            logger.info(f"Attempting to register domain: {domain_name}")
            
            # Direct registration with central server
            register_url = f"http://jcmc.serveminecraft.net/cent.php?register={domain_name}&ip={domain.ip}&port={domain.port}"
            if domain.title:
                register_url += f"&title={domain.title}"
            
            # Log the URL
            logger.info(f"Registration URL: {register_url}")
            
            # Send request directly to central server
            try:
                response = requests.get(register_url, timeout=15)
                
                # Log the response
                logger.info(f"Central server response code: {response.status_code}")
                logger.info(f"Central server response text: {response.text[:200]}")
                
                if response.status_code == 200:
                    try:
                        data = response.json()
                        if data.get('success'):
                            logger.info(f"Domain {domain_name} registered successfully with central server")
                            return True, data.get('message', 'Success')
                        else:
                            logger.error(f"Failed to register with central server: {data.get('error', 'Unknown error')}")
                            return False, data.get('error', 'Unknown error')
                    except json.JSONDecodeError:
                        # Check if response contains "success"
                        if "success" in response.text.lower():
                            logger.info(f"Domain {domain_name} registered successfully (text response)")
                            return True, "Success (text response)"
                        else:
                            logger.error(f"Failed to register: {response.text}")
                            return False, f"Registration failed: {response.text}"
                else:
                    logger.error(f"Failed to register domain: HTTP {response.status_code}")
                    return False, f"HTTP Error: {response.status_code}"
            except requests.RequestException as e:
                logger.error(f"Network error registering with central server: {str(e)}")
                return False, f"Network error: {str(e)}"
                
        except Exception as e:
            logger.error(f"Unexpected error registering domain: {str(e)}")
            return False, f"Error: {str(e)}"
"""
    
    # Replace the old method with the new one
    updated_content = content.replace(old_method, new_method)
    
    # Write the updated content
    with open(client_py, 'w', encoding='utf-8') as f:
        f.write(updated_content)
    
    print(f"Fixed register_domain method in {client_py}")
    return True

def add_direct_ddns_methods(ddns_py):
    """Add direct central server communication methods to DDNS class."""
    with open(ddns_py, 'r', encoding='utf-8') as f:
        content = f.read()
    
    # Find a good place to add our methods
    add_entry_pattern = r'def add_entry\(self, domain, ip, port\):.*?(?=\n    def|\Z)'
    match = re.search(add_entry_pattern, content, re.DOTALL)
    
    if not match:
        print("Could not find add_entry method in DDNS class")
        return False
    
    add_entry_method = match.group(0)
    add_entry_end = content.find(add_entry_method) + len(add_entry_method)
    
    # Create direct communication methods
    direct_methods = """
    def register_with_central(self, domain, ip, port, title=None):
        
        try:
            import requests
            
            # Build registration URL
            register_url = f"http://jcmc.serveminecraft.net/cent.php?register={domain}&ip={ip}&port={port}"
            if title:
                register_url += f"&title={title}"
            
            # Send request
            response = requests.get(register_url, timeout=15)
            
            if response.status_code == 200:
                try:
                    data = response.json()
                    if data.get('success'):
                        return True, "Domain registered with central server"
                    else:
                        return False, data.get('error', 'Registration failed')
                except:
                    if "success" in response.text.lower():
                        return True, "Domain registered with central server"
                    else:
                        return False, f"Registration failed: {response.text}"
            else:
                return False, f"HTTP error: {response.status_code}"
        except Exception as e:
            return False, f"Error: {str(e)}"
    
    def check_availability_central(self, domain):
        
        try:
            import requests
            
            # Build check URL
            check_url = f"http://jcmc.serveminecraft.net/cent.php?check={domain}"
            
            # Send request
            response = requests.get(check_url, timeout=10)
            
            if response.status_code == 200:
                try:
                    data = response.json()
                    if data.get('available') is True:
                        return True, "Domain is available"
                    else:
                        return False, data.get('reason', 'Domain is not available')
                except:
                    if "available" in response.text.lower():
                        return True, "Domain is available"
                    else:
                        return False, "Domain is not available"
            else:
                return False, f"HTTP error: {response.status_code}"
        except Exception as e:
            return False, f"Error: {str(e)}"
"""
    
    # Insert our methods
    updated_content = content[:add_entry_end] + direct_methods + content[add_entry_end:]
    
    # Also update the add_entry method to try registering with central server
    updated_add_entry = add_entry_method.replace(
        'self.save()',
        """self.save()
        
        # Try to register with central server
        self.register_with_central(domain, ip, port)"""
    )
    
    updated_content = updated_content.replace(add_entry_method, updated_add_entry)
    
    # Write the updated content
    with open(ddns_py, 'w', encoding='utf-8') as f:
        f.write(updated_content)
    
    print(f"Added direct central server methods to DDNS class in {ddns_py}")
    return True

def main():
    """Main function to fix domain creation."""
    # 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")
    ddns_py = os.path.join(base_dir, "shared", "ddns.py")
    
    if not all(os.path.exists(f) for f in [main_window_py, client_py, ddns_py]):
        print("Error: Required files not found.")
        return 1
    
    # Create backups
    backup_file(main_window_py)
    backup_file(client_py)
    backup_file(ddns_py)
    
    # Fix create_domain_dialog in MainWindow
    fix_create_domain_dialog(main_window_py)
    
    # Fix register_domain in NetworkClient
    fix_register_domain(client_py)
    
    # Add direct central server methods to DDNS
    add_direct_ddns_methods(ddns_py)
    
    print("\nDomain creation fix applied successfully!")
    print("\nThe fix includes:")
    print("1. A completely rewritten domain creation dialog with better error handling")
    print("2. Direct communication with the central server for domain registration")
    print("3. Visual feedback on domain availability status")
    print("4. Improved logging to help diagnose issues")
    
    print("\nPlease restart DecentraBrowser to apply the changes.")
    
    return 0

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