#!/usr/bin/env python3
"""
DecentraBrowser Central Server Domain Check

This script adds functionality to check if a domain is already taken
by querying the central server at jcmc.serveminecraft.net/cent.php.

Usage:
    python central_server_check.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 + '.central.bak'
    print(f"Creating backup: {backup_path}")
    shutil.copy2(file_path, backup_path)
    return backup_path

def add_central_server_check(client_py):
    """Add central server domain check functionality to NetworkClient."""
    with open(client_py, 'r', encoding='utf-8') as f:
        content = f.read()
    
    # Check if the function already exists
    if "check_domain_availability" in content:
        print("Domain availability check already exists in client.py, skipping...")
        return True
    
    # Find a good place to add our new method (before register_domain)
    register_domain_pattern = r'def register_domain\(self, domain\):'
    match = re.search(register_domain_pattern, content)
    
    if not match:
        print("Could not find register_domain method in client.py")
        return False
    
    insert_pos = match.start()
    
    # Create the new check_domain_availability method
    check_method = """
    def check_domain_availability(self, domain):
        
        domain_name = domain
        if isinstance(domain, Domain):
            domain_name = domain.full_name
        
        # Query the central registration server
        try:
            # Construct the query URL
            query_url = f"http://jcmc.serveminecraft.net/cent.php?check={domain_name}"
            
            # Send the request
            response = requests.get(query_url, timeout=10)
            
            if response.status_code == 200:
                # Parse the response
                try:
                    data = response.json()
                    if data.get('available') is True:
                        return True, "Domain is available"
                    else:
                        reason = data.get('reason', 'Domain is already taken')
                        return False, reason
                except json.JSONDecodeError:
                    # Check for simple text response
                    text = response.text.strip().lower()
                    if "available" in text:
                        return True, "Domain is available"
                    else:
                        return False, f"Domain is unavailable: {text}"
            else:
                logger.error(f"Error checking domain availability: HTTP {response.status_code}")
                return False, f"Error checking domain: HTTP {response.status_code}"
                
        except requests.RequestException as e:
            logger.error(f"Network error checking domain availability: {str(e)}")
            return False, f"Network error: {str(e)}"
        
        # Fallback (if we reach here, something unexpected happened)
        return False, "Could not determine domain availability"
    
    """
    
    # Insert the new method
    updated_content = content[:insert_pos] + check_method + content[insert_pos:]
    
    # Now update the register_domain method to use our check
    register_pattern = r'def register_domain\(self, domain\):.*?try:.*?response = requests\.post\('
    register_match = re.search(register_pattern, updated_content, re.DOTALL)
    
    if register_match:
        register_code = register_match.group(0)
        
        # Add domain availability check
        check_code = """def register_domain(self, domain):
        
        # First check if the domain is available
        availability_check, message = self.check_domain_availability(domain)
        if not availability_check:
            logger.error(f"Domain not available: {message}")
            return False, message
            
        try:
            response = requests.post("""
        
        updated_content = updated_content.replace(register_code, check_code)
    else:
        print("Could not find location to update register_domain method")
    
    # Write the updated content
    with open(client_py, 'w', encoding='utf-8') as f:
        f.write(updated_content)
    
    print(f"Added central server domain check to {client_py}")
    return True

def update_create_domain_dialog(main_window_py):
    """Update domain creation dialog to check availability before creating."""
    with open(main_window_py, 'r', encoding='utf-8') as f:
        content = f.read()
    
    # Check if already contains domain check
    if "check_domain_availability" in content:
        print("Create domain dialog already includes availability check, skipping...")
        return True
    
    # Find the create_domain_dialog method
    dialog_pattern = r'def create_domain_dialog\(self\):.*?def create_domain\(\):.*?if not prefix or not main or not suffix:.*?QMessageBox\.warning\(dialog, "Error", "All domain name parts are required"\).*?return'
    match = re.search(dialog_pattern, content, re.DOTALL)
    
    if not match:
        print("Could not find validation code in create_domain_dialog method")
        return False
    
    dialog_code = match.group(0)
    
    # Add domain availability check before creating domain
    check_code = """if not prefix or not main or not suffix:
                QMessageBox.warning(dialog, "Error", "All domain name parts are required")
                return
            
            # Create a temporary domain to check availability
            temp_domain = Domain(
                prefix=prefix,
                main=main,
                suffix=suffix,
                ip="0.0.0.0",  # Temporary IP
                port=0         # Temporary port
            )
            
            # Check domain availability
            self.statusBar.showMessage(f"Checking if {temp_domain.full_name} is available...", 2000)
            availability, message = self.network_client.check_domain_availability(temp_domain)
            
            if not availability:
                QMessageBox.warning(dialog, "Domain Not Available", f"{message}")
                return"""
    
    updated_content = content.replace(dialog_code, dialog_code.replace(
        """if not prefix or not main or not suffix:
                QMessageBox.warning(dialog, "Error", "All domain name parts are required")
                return""",
        check_code
    ))
    
    # Write the updated content
    with open(main_window_py, 'w', encoding='utf-8') as f:
        f.write(updated_content)
    
    print(f"Updated domain creation dialog in {main_window_py}")
    return True

def add_domain_check_button(main_window_py):
    """Add a 'Check Availability' button to the domain creation dialog."""
    with open(main_window_py, 'r', encoding='utf-8') as f:
        content = f.read()
    
    # Check if button already exists
    if "check_domain_button" in content:
        print("Check availability button already exists, skipping...")
        return True
    
    # Find the area where buttons are created in the dialog
    buttons_pattern = r'(# Create button\s*create_button = QPushButton\("Create Domain"\)\s*)'
    match = re.search(buttons_pattern, content)
    
    if not match:
        print("Could not find button creation section in create_domain_dialog")
        return False
    
    buttons_code = match.group(1)
    
    # Add check availability button
    check_button_code = """# Buttons
            buttons_layout = QHBoxLayout()
            
            check_button = QPushButton("Check Availability")
            create_button = QPushButton("Create Domain")
            
            buttons_layout.addWidget(check_button)
            buttons_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 to check
                temp_domain = Domain(
                    prefix=prefix,
                    main=main,
                    suffix=suffix,
                    ip="0.0.0.0",  # Temporary IP
                    port=0         # Temporary port
                )
                
                # Check domain availability
                self.statusBar.showMessage(f"Checking if {temp_domain.full_name} is available...", 2000)
                availability, message = self.network_client.check_domain_availability(temp_domain)
                
                if availability:
                    QMessageBox.information(dialog, "Domain Available", 
                                          f"The domain {temp_domain.full_name} is available!")
                else:
                    QMessageBox.warning(dialog, "Domain Not Available", f"{message}")
            
            check_button.clicked.connect(check_availability)
            """
    
    # Replace button section
    updated_content = content.replace(buttons_code, check_button_code)
    
    # Update layout section to include buttons_layout
    layout_pattern = r'(# Add widgets to layout\s*layout\.addLayout\(name_layout\)\s*layout\.addWidget\(create_button\)\s*)'
    match = re.search(layout_pattern, updated_content)
    
    if match:
        layout_code = match.group(1)
        new_layout_code = """# Add widgets to layout
        layout.addLayout(name_layout)
        layout.addLayout(buttons_layout)
        """
        
        updated_content = updated_content.replace(layout_code, new_layout_code)
    else:
        print("Could not find layout section to update")
        return False
    
    # Write the updated content
    with open(main_window_py, 'w', encoding='utf-8') as f:
        f.write(updated_content)
    
    print(f"Added Check Availability button to domain creation dialog in {main_window_py}")
    return True

def main():
    """Main function to add central server domain check."""
    # 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
    client_py = os.path.join(base_dir, "client", "network", "client.py")
    main_window_py = os.path.join(base_dir, "client", "gui", "main_window.py")
    
    if not os.path.exists(client_py) or not os.path.exists(main_window_py):
        print("Error: Required files not found.")
        return 1
    
    # Create backups
    backup_file(client_py)
    backup_file(main_window_py)
    
    # Add domain check functionality to NetworkClient
    add_central_server_check(client_py)
    
    # Update domain creation dialog to check availability
    update_create_domain_dialog(main_window_py)
    
    # Add check availability button to domain creation dialog
    add_domain_check_button(main_window_py)
    
    print("\nCentral server domain check added successfully!")
    print("\nYou can now:")
    print("1. Check domain availability before creating a domain")
    print("2. Register domains only if they are available on the central server")
    print("\nThe system will connect to jcmc.serveminecraft.net/cent.php to verify domain availability.")
    print("\nPlease restart DecentraBrowser to use the new features.")
    
    return 0

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