# yourapp/utils.py
import os
import subprocess
import re
import shutil
import stat
import pwd
import grp
from datetime import datetime
from django.contrib import messages
from users.database import *  # Import your function
from django.db import connection
from .models import * 
from .function import * 
from users.panellogger import *
from django.conf import settings
# Path to the OpenLiteSpeed configuration file for listeners
LISTENER_CONFIG_FILE = "/usr/local/lsws/conf/httpd_config.conf"
logger = CpLogger()


def manage_listener_mapping(action, domain):
    """Manage domain mappings in the OpenLiteSpeed listener configuration."""
    try:
        with open(LISTENER_CONFIG_FILE, 'r') as file:
            lines = file.readlines()

        new_lines = []
        in_listener_block = False
        mapping_found = False

        for line in lines:
            if 'listener Default {' in line:
                in_listener_block = True

            # Adjust the map line format to remove extra spaces
            if in_listener_block:
                if action == "remove" and f"  map                     {domain} " in line:
                    mapping_found = True
                    continue

                if action == "add" and f"  map                     {domain} " in line:
                    mapping_found = True
                    

            new_lines.append(line)

            if '}' in line and in_listener_block:
                # Add the map if it's not found for 'add' action
                if action == "add" and not mapping_found:
                    new_lines.insert(-1, f"  map                     {domain} {domain}\n")
                in_listener_block = False

        # Write the modified lines back to the configuration file
        with open(LISTENER_CONFIG_FILE, 'w') as file:
            file.writelines(new_lines)

        # Fixing the syntax issue in the print statement
        print(f"Mapping for '{domain}' {'added' if action == 'add' else 'removed'} successfully.")
        return True

    except Exception as e:
        print(f"Error managing listener mapping: {e}")
        return False



def manage_ssl_listener_mapping(action, domain):
    """Manage domain mappings in the OpenLiteSpeed listener configuration."""
    try:
        with open(LISTENER_CONFIG_FILE, 'r') as file:
            lines = file.readlines()

        new_lines = []
        in_listener_block = False
        mapping_found = False

        for line in lines:
            if 'listener SSL {' in line:
                in_listener_block = True

            # Adjust the map line format to remove extra spaces
            if in_listener_block:
                if action == "remove" and f"  map                     {domain} " in line:
                    mapping_found = True
                    continue

                if action == "add" and f"  map                     {domain} " in line:
                    mapping_found = True
                    

            new_lines.append(line)

            if '}' in line and in_listener_block:
                # Add the map if it's not found for 'add' action
                if action == "add" and not mapping_found:
                    new_lines.insert(-1, f"  map                     {domain} {domain}\n")
                in_listener_block = False

        # Write the modified lines back to the configuration file
        with open(LISTENER_CONFIG_FILE, 'w') as file:
            file.writelines(new_lines)
            
        add_ipv6_ssl_listener()
        print(f"Mapping for '{domain}' {'added' if action == 'add' else 'removed'} successfully.")
        return True

    except Exception as e:
        print(f"Error managing SSL listener mapping: {e}")
        return False


    except Exception as e:
        print(f"Error managing listener mapping: {e}")
        return False


def add_ipv6_ssl_listener():
    # Read current config
    with open(LISTENER_CONFIG_FILE, "r") as f:
        config_text = f.read()

    # Remove any existing SSL IPv6 block
    config_text = re.sub(r"\n*listener\s+SSL\s+IPv6\s*{[^}]+}", "", config_text, flags=re.DOTALL)

    # Find the original SSL listener block
    pattern_ssl = r"(listener\s+SSL\s*{[^}]+})"
    match_ssl = re.search(pattern_ssl, config_text, re.DOTALL)
    if not match_ssl:
        raise ValueError("No SSL listener block found")

    old_block = match_ssl.group(1)

    # Create new SSL IPv6 block
    new_block = old_block.replace("listener SSL", "listener SSL IPv6", 1)
    new_block = new_block.replace("address                 *:", "address                 [ANY]:")

    # Insert new block immediately after old block, only once
    new_config = config_text.replace(old_block, old_block.rstrip() + "\n" + new_block.lstrip())

    # Write back updated config
    with open(LISTENER_CONFIG_FILE, "w") as f:
        f.write(new_config)
    add_ipv6_panel_listener()
    print("listener SSL IPv6 successfully overwritten in httpd_config.conf")


def add_ipv6_panel_listener():
    # Read current config
    with open(LISTENER_CONFIG_FILE, "r") as f:
        config_text = f.read()

    # Remove any existing panel IPv6 block
    config_text = re.sub(r"\n*listener\s+panel\s+IPv6\s*{[^}]+}", "", config_text, flags=re.DOTALL)

    # Find the original panel listener block
    pattern_ssl = r"(listener\s+panel\s*{[^}]+})"
    match_ssl = re.search(pattern_ssl, config_text, re.DOTALL)
    if not match_ssl:
        raise ValueError("No panel listener block found")

    old_block = match_ssl.group(1)

    # Create new panel IPv6 block
    new_block = old_block.replace("listener panel", "listener panel IPv6", 1)
    new_block = new_block.replace("address                 *:", "address                 [ANY]:")

    # Insert new block immediately after old block, only once
    new_config = config_text.replace(old_block, old_block.rstrip() + "\n" + new_block.lstrip())

    # Write back updated config
    with open(LISTENER_CONFIG_FILE, "w") as f:
        f.write(new_config)

    print("listener panel IPv6 successfully overwritten in httpd_config.conf")


def preview_mapping(action, domain):
    """Manage domain mappings in the OpenLiteSpeed listener configuration."""
    try:
        with open(LISTENER_CONFIG_FILE, 'r') as file:
            lines = file.readlines()

        new_lines = []
        in_listener_block = False
        mapping_found = False

        for line in lines:
            if 'listener Default {' in line:
                in_listener_block = True

            # Adjust the map line format to remove extra spaces
            if in_listener_block:
                
                if action == "add" and f"  map                     {domain} " in line:
                    mapping_found = True
                   

            new_lines.append(line)

            if '}' in line and in_listener_block:
                # Add the map if it's not found for 'add' action
                if action == "add" and not mapping_found:
                    new_lines.insert(-1, f"  map                     {domain} *\n")
                in_listener_block = False

        # Write the modified lines back to the configuration file
        with open(LISTENER_CONFIG_FILE, 'w') as file:
            file.writelines(new_lines)

        # Fixing the syntax issue in the print statement
        print(f"Mapping for '{domain}' {'added' if action == 'add' else 'removed'} successfully.")
        return True

    except Exception as e:
        print(f"Error managing listener mapping: {e}")
        return False



def ssl_preview_mapping(action, domain):
    """Manage domain mappings in the OpenLiteSpeed listener configuration."""
    try:
        with open(LISTENER_CONFIG_FILE, 'r') as file:
            lines = file.readlines()

        new_lines = []
        in_listener_block = False
        mapping_found = False

        for line in lines:
            if 'listener SSL {' in line:
                in_listener_block = True

            # Adjust the map line format to remove extra spaces
            if in_listener_block:
                
                if action == "add" and f"  map                     {domain} " in line:
                    mapping_found = True
                    

            new_lines.append(line)

            if '}' in line and in_listener_block:
                # Add the map if it's not found for 'add' action
                if action == "add" and not mapping_found:
                    new_lines.insert(-1, f"  map                     {domain} *\n")
                in_listener_block = False

        # Write the modified lines back to the configuration file
        with open(LISTENER_CONFIG_FILE, 'w') as file:
            file.writelines(new_lines)

        # Fixing the syntax issue in the print statement
        print(f"Mapping for '{domain}' {'added' if action == 'add' else 'removed'} successfully.")
        return True

    except Exception as e:
        print(f"Error managing listener mapping: {e}")
        return False


def manage_preview_virtual_host():
   
    config_file_path = "/usr/local/lsws/conf/httpd_config.conf"
    domain_name = "preview"
    vhost_directory = f"/usr/local/lsws/conf/vhosts/{domain_name}"
    vhost_file_path = os.path.join(vhost_directory, "vhconf.conf")
    if not os.path.isfile(vhost_file_path):
        create_preview_vhost_file()
    
    
    vhost_config = f"""
virtualhost preview {{
  vhRoot                  Example/
  configFile              conf/vhosts/preview/vhconf.conf
  allowSymbolLink         1
  enableScript            1
  restrained              1
}}
"""

    # Read the existing configuration to check for the virtual host
    try:
        with open(config_file_path, "r") as config_file:
            config_content = config_file.read()

            # Check if the virtual host block exists by looking for 'virtualhost <domain_name>'
            if f"virtualhost {domain_name} " in config_content:
                print(f"Virtual host for '{domain_name}' already exists.")  # Debug message
                return True  # Indicate that the virtual host already exists

    except FileNotFoundError:
        print("Configuration file does not exist.")  # Debug message
        return False  # Indicate failure
    except Exception as e:
        print(f"Error reading config file: {str(e)}")  # Debug message
        return False  # Indicate failure

    # If not found, append the new virtual host configuration
    try:
        with open(config_file_path, "a") as config_file:
            config_file.write(vhost_config.strip() + "\n")  # Ensure a new line at the end
            print(f"Added virtual host for '{domain_name}'.")  # Debug message
            return True  # Indicate success
    except Exception as e:
        print(f"Error writing to config file: {str(e)}")  # Debug message
        return False  # Indicate failure



def create_preview_vhost_file():
    """Create a vhost directory and configuration file for the specified domain."""
    domain_name = "preview"
    vhost_directory = f"/usr/local/lsws/conf/vhosts/{domain_name}"
    vhost_file_path = os.path.join(vhost_directory, "vhconf.conf")
    
    if not os.path.exists(vhost_directory):
        try:
            os.makedirs(vhost_directory)
            print(f"Created directory: {vhost_directory}")
        except Exception as e:
            print(f"Failed to create directory: {str(e)}")
            return False

    # Check if the vhost.conf file exists
    if not os.path.isfile(vhost_file_path):
        try:
            # Create the vhost.conf file with the specified content
            vhost_content = """docRoot                   $VH_ROOT/html/default
enableGzip                1

index  {
  useServer               0
  indexFiles              index.html
  autoIndex               0
  autoIndexURI            /_autoindex/default.php
}

errorpage 404 {
  url                     /error404.html
}

expires  {
  enableExpires           1
}

accessControl  {
  allow                   *
}

context / {
  location                $DOC_ROOT/
  allowBrowse             1

  rewrite  {
    RewriteFile .htaccess
  }
}

rewrite  {
  enable                  0
  logLevel                0
}

scripthandler  {
  add                     lsapi:lsphp lsphp
}

"""
            with open(vhost_file_path, "w") as vhost_file:
                vhost_file.write(vhost_content)

            print(f"Created vhost file: {vhost_file_path}")
            return True
        except Exception as e:
            print(f"Failed to create vhost file: {str(e)}")
            return False
    else:
        print(f"Vhost file '{vhost_file_path}' already exists.")
        return False


def update_context_block(context_name, path):
    vhost_directory = "/usr/local/lsws/conf/vhosts/preview"
    conf_path = os.path.join(vhost_directory, "vhconf.conf")
    name, block = get_single_extprocessor_block(context_name)
    php_preview_mapping(name)
    context_header = f"context /~{context_name} {{"
    context_footer = "}"
    name_header = f"extprocessor {name} {{"

    new_block = f"""{context_header}
  location                {path}
  allowBrowse             1
  indexFiles              index.php, index.html
  
  accessControl  {{
    allow                 *
  }}

  rewrite  {{
  enable                  1
  autoLoadHtaccess        1
  RewriteRule ^.*\.php$ - [H=application/x-httpd-{name}]
  }}

  addDefaultCharset       off

  phpIniOverride  {{
    php_admin_value open_basedir "/tmp:{path}"
  }}
{context_footer}
"""

    try:
        # Read current file if exists
        if os.path.exists(conf_path):
            with open(conf_path, "r") as f:
                lines = f.readlines()
        else:
            lines = []

        # Remove old context block
        inside_block = False
        new_lines = []
        for line in lines:
            if line.strip().startswith(context_header):
                inside_block = True
                continue
            if inside_block and line.strip() == context_footer:
                inside_block = False
                continue
            if not inside_block:
                new_lines.append(line)

        # Remove old extprocessor block
        lines = new_lines
        inside_block = False
        final_lines = []
        for line in lines:
            if line.strip().startswith(name_header):
                inside_block = True
                continue
            if inside_block and line.strip() == context_footer:
                inside_block = False
                continue
            if not inside_block:
                final_lines.append(line)

        # Combine everything
        updated_content = "".join(final_lines).rstrip() + "\n\n" + new_block + "\n\n" + block

        # Write back to file
        with open(conf_path, "w") as f:
            f.write(updated_content)
           

        print(f"Updated context and extprocessor for /{context_name} in {conf_path}")
        return True

    except Exception as e:
        print(f"Error updating context: {str(e)}")
        return False


def get_single_extprocessor_block(domain_name):
    vhost_directory = f"/usr/local/lsws/conf/vhosts/{domain_name}" 
    vhost_file_path = os.path.join(vhost_directory, "vhost.conf")
    if not os.path.isfile(vhost_file_path):
        print(f"File not found: {vhost_file_path}")
        return None, None

    with open(vhost_file_path, "r") as f:
        content = f.read()

    match = re.search(r"extprocessor\s+(\S+)\s*\{.*?\n\}", content, re.DOTALL)
    if match:
        name = match.group(1)
        block = match.group(0).strip()
        return name, block

    return None, None



def php_preview_mapping(name):
    vhost_directory = "/usr/local/lsws/conf/vhosts/preview"
    conf_path = os.path.join(vhost_directory, "vhconf.conf")
    action = "add"

    try:
        with open(conf_path, 'r') as file:
            lines = file.readlines()

        new_lines = []
        in_listener_block = False
        mapping_found = False

        for line in lines:
            if 'scripthandler  {' in line:
                in_listener_block = True

            # Adjust the map line format to remove extra spaces
            if in_listener_block:
                
                if action == "add" and f"  add                     lsapi:{name} {name}" in line:
                    mapping_found = True
                    

            new_lines.append(line)

            if '}' in line and in_listener_block:
                # Add the map if it's not found for 'add' action
                if action == "add" and not mapping_found:
                    new_lines.insert(-1, f"  add                     lsapi:{name} {name}\n")
                in_listener_block = False

        # Write the modified lines back to the configuration file
        with open(conf_path, 'w') as file:
            file.writelines(new_lines)

        
        return True

    except Exception as e:
        print(f"Error updating scripthandler mapping: {e}")
        return False

        
def panel_listener_mapping(action, domain):
    """Manage domain mappings in the OpenLiteSpeed listener configuration."""
    try:
        with open(LISTENER_CONFIG_FILE, 'r') as file:
            lines = file.readlines()

        new_lines = []
        in_listener_block = False
        mapping_found = False

        for line in lines:
            if 'listener panel {' in line:
                in_listener_block = True

            # Adjust the map line format to remove extra spaces
            if in_listener_block:
                if action == "remove" and f"  map                     panel_{domain} " in line:
                    mapping_found = True
                    continue

                if action == "add" and f"  map                     panel_{domain} " in line:
                    mapping_found = True
                    

            new_lines.append(line)

            if '}' in line and in_listener_block:
                # Add the map if it's not found for 'add' action
                if action == "add" and not mapping_found:
                    new_lines.insert(-1, f"  map                     panel_{domain} {domain}\n")
                in_listener_block = False

        # Write the modified lines back to the configuration file
        with open(LISTENER_CONFIG_FILE, 'w') as file:
            file.writelines(new_lines)

        print(f"Mapping for '{domain}' {'added' if action == 'add' else 'removed'} successfully.")
        return True

    except Exception as e:
        print(f"Error managing SSL listener mapping: {e}")
        return False


    except Exception as e:
        print(f"Error managing listener mapping: {e}")
        return False



def panel_virtual_host(domain_name):
    """Check if the virtual host exists, and add it if not."""
    config_file_path = "/usr/local/lsws/conf/httpd_config.conf"
    
    # Define the virtual host configuration block
    vhost_config = f"""
virtualhost panel_{domain_name} {{
  vhRoot                  Example/
  configFile              $SERVER_ROOT/conf/vhosts/$VH_NAME/vhost.conf
  allowSymbolLink         1
  enableScript            1
  restrained              1
  setUIDMode              0
}}
"""

    # Read the existing configuration to check for the virtual host
    try:
        with open(config_file_path, "r") as config_file:
            config_content = config_file.read()

            # Check if the virtual host block exists by looking for 'virtualhost <domain_name>'
            if f"virtualhost panel_{domain_name} " in config_content:
                print(f"Virtual host for '{domain_name}' already exists.")  # Debug message
                return True  # Indicate that the virtual host already exists

    except FileNotFoundError:
        print("Configuration file does not exist.")  # Debug message
        return False  # Indicate failure
    except Exception as e:
        print(f"Error reading config file: {str(e)}")  # Debug message
        return False  # Indicate failure

    # If not found, append the new virtual host configuration
    try:
        with open(config_file_path, "a") as config_file:
            config_file.write(vhost_config.strip() + "\n")  # Ensure a new line at the end
            print(f"Added virtual host for '{domain_name}'.")  # Debug message
            return True  # Indicate success
    except Exception as e:
        print(f"Error writing to config file: {str(e)}")  # Debug message
        return False  # Indicate failure
        

def create_panel_vhost_file(domain_name):
    """Create a vhost directory and configuration file for the specified domain."""
    # Paths
    template_path = "/usr/local/lsws/conf/vhosts/mypanel/vhconf.conf"
    vhost_directory = f"/usr/local/lsws/conf/vhosts/panel_{domain_name}"
    vhost_file_path = os.path.join(vhost_directory, "vhost.conf")
    
    

    # Create vhost directory if not exists
    if not os.path.exists(vhost_directory):
        try:
            os.makedirs(vhost_directory)
            print(f"Created directory: {vhost_directory}")
        except Exception as e:
            print(f"Failed to create vhost directory: {str(e)}")
            return False

    # Read template and replace cert lines
    try:
        with open(template_path, 'r') as template_file:
            content = template_file.readlines()

        new_content = []
        for line in content:
            if "keyFile" in line:
                new_content.append(f"  keyFile                 /etc/letsencrypt/live/{domain_name}/privkey.pem\n")
            elif "certFile" in line:
                new_content.append(f"  certFile                /etc/letsencrypt/live/{domain_name}/fullchain.pem\n")
            else:
                new_content.append(line)

        with open(vhost_file_path, 'w') as new_file:
            new_file.writelines(new_content)
            print(f"Created vhost config: {vhost_file_path}")

        return True

    except Exception as e:
        print(f"Error copying or modifying vhost file: {str(e)}")
        return False
    
def get_all_panel_domains_and_create_vhosts():
    base_path = "/usr/local/lsws/conf/vhosts"
    try:
        with os.scandir(base_path) as entries:
            for entry in entries:
                if entry.is_dir() and entry.name.startswith("panel_"):
                    domain = entry.name.replace("panel_", "", 1)
                    create_panel_vhost_file(domain)  # Call your function
    except Exception as e:
        print(f"Error: {e}")

def create_self_signed_ssl(domain, base_ssl_dir="/etc/letsencrypt/live"):
    """
    Create a self-signed SSL certificate for a given domain and store it in the specified SSL directory.

    Args:
        domain (str): The domain for which the SSL certificate is generated.
        base_ssl_dir (str): The base directory for storing SSL certificates (default: /etc/letsencrypt/live).

    Returns:
        dict: Paths to the private key and certificate files if successful, None otherwise.
    """
    try:
        # Define the full paths for the private key and certificate
        private_key_path = f"{base_ssl_dir}/{domain}/privkey.pem"
        certificate_path = f"{base_ssl_dir}/{domain}/fullchain.pem"
        
        # Ensure the directory exists
        os.makedirs(os.path.dirname(private_key_path), exist_ok=True)
        
        # Generate the private key
        subprocess.run(["openssl", "genrsa", "-out", private_key_path, "2048"], check=True)
        
        # Generate the certificate signing request (CSR)
        subprocess.run([
            "openssl", "req", "-new", "-key", private_key_path, "-out", "/tmp/csr.pem",
            "-subj", f"/CN={domain}/O=My Pannel/C=US"  # Update this subject line as needed
        ], check=True)
        
        # Generate the self-signed certificate (valid for 365 days)
        subprocess.run([
            "openssl", "x509", "-req", "-days", "365", "-in", "/tmp/csr.pem", "-signkey", private_key_path, "-out", certificate_path
        ], check=True)
        
        # Clean up the CSR file
        os.remove("/tmp/csr.pem")
        
        print(f"SSL certificate created successfully for {domain}.")
        print(f"Private Key File: {private_key_path}")
        print(f"Certificate File: {certificate_path}")
        print("Chained Certificate: Yes")
        
        return {
            "private_key": private_key_path,
            "certificate": certificate_path,
            "chained": True
        }
    
    except subprocess.CalledProcessError as e:
        print(f"Error occurred while creating SSL certificate: {e}")
        return None

# Usage example:
# create_self_signed_ssl('ols-example.tk')

def manage_virtual_host(domain_name, username):
    """Check if the virtual host exists, and add it if not."""
    config_file_path = "/usr/local/lsws/conf/httpd_config.conf"
    
    # Define the virtual host configuration block
    vhost_config = f"""
virtualhost {domain_name} {{
  vhRoot                  /home/{username}
  configFile              $SERVER_ROOT/conf/vhosts/$VH_NAME/vhost.conf
  allowSymbolLink         1
  enableScript            1
  restrained              1
  user                    {username}
  group                   {username}
}}
"""

    # Read the existing configuration to check for the virtual host
    try:
        with open(config_file_path, "r") as config_file:
            config_content = config_file.read()

            # Check if the virtual host block exists by looking for 'virtualhost <domain_name>'
            if f"virtualhost {domain_name} " in config_content:
                print(f"Virtual host for '{domain_name}' already exists.")  # Debug message
                return True  # Indicate that the virtual host already exists

    except FileNotFoundError:
        print("Configuration file does not exist.")  # Debug message
        return False  # Indicate failure
    except Exception as e:
        print(f"Error reading config file: {str(e)}")  # Debug message
        return False  # Indicate failure

    # If not found, append the new virtual host configuration
    try:
        with open(config_file_path, "a") as config_file:
            config_file.write(vhost_config.strip() + "\n")  # Ensure a new line at the end
            print(f"Added virtual host for '{domain_name}'.")  # Debug message
            return True  # Indicate success
    except Exception as e:
        print(f"Error writing to config file: {str(e)}")  # Debug message
        return False  # Indicate failure


def create_vhost_file(domain_name, username, document_root="public_html"):
    """Create a vhost directory and configuration file for the specified domain."""
    # Define the path for the virtual host directory and configuration file
    vhost_directory = f"/usr/local/lsws/conf/vhosts/{domain_name}"
    vhost_file_path = os.path.join(vhost_directory, "vhost.conf")
    log_directory = f"/home/{username}/logs"
    
    # Check if the virtual host directory exists
    if not os.path.exists(log_directory):
        try:
            os.makedirs(log_directory)  # Create the directory structure
            print(f"Created directory: {log_directory}")  # Debug message
        except Exception as e:
            print(f"Failed to create directory: {str(e)}")  # Debug message
            return False  # Indicate failure

    # Check if the virtual host directory exists
    if not os.path.exists(vhost_directory):
        try:
            os.makedirs(vhost_directory)  # Create the directory structure
            print(f"Created directory: {vhost_directory}")  # Debug message
        except Exception as e:
            print(f"Failed to create directory: {str(e)}")  # Debug message
            return False  # Indicate failure

    # Check if the vhost.conf file exists
    if not os.path.isfile(vhost_file_path):
        try:
            # Create the vhost.conf file with the specified content
            with open(vhost_file_path, "w") as vhost_file:
                vhost_file.write(f"""docRoot                   /home/{username}/{document_root}/
vhDomain                  $VH_NAME
vhAliases                 www.$VH_NAME
adminEmails               
enableGzip                1
enableIpGeo               1

index  {{
  useServer               0
  indexFiles              index.php, index.html
}}

errorlog $VH_ROOT/logs/{domain_name}.error_log {{
  useServer               0
  logLevel                WARN
  rollingSize             10M
}}

accesslog $VH_ROOT/logs/{domain_name}.access_log {{
  useServer               0
  logFormat               "%h %l %u %t \\"%r\\" %>s %b \\"%{{Referer}}i\\" \\"%{{User-Agent}}i\\""
  logHeaders              5
  rollingSize             10M
  keepDays                10  
  compressArchive         1
}}

phpIniOverride  {{
    php_admin_value open_basedir "/tmp:$VH_ROOT"
}}

module cache {{
 storagePath /usr/local/lsws/cachedata/$VH_NAME
}}

scripthandler  {{
  add                     lsapi:lsphp82 php
}}



rewrite  {{
  enable                  1
  autoLoadHtaccess        1
}}

context /.well-known/acme-challenge {{
  location                /usr/local/lsws/{domain_name}/html/.well-known/acme-challenge
  allowBrowse             1
}}

vhssl  {{
  keyFile                 /etc/letsencrypt/live/{domain_name}/privkey.pem
  certFile                /etc/letsencrypt/live/{domain_name}/fullchain.pem
  certChain               1
  sslProtocol             24
  enableECDHE             1
  renegProtection         1
  sslSessionCache         1
  enableSpdy              15
  enableStapling          1
  ocspRespMaxAge          86400
}}
extprocessor lsphp82 {{
  type                    lsapi
  address                 uds://tmp/lshttpd/lsphp82.sock
  maxConns                10
  env                     LSAPI_CHILDREN=10
  initTimeout             60
  retryTimeout            0
  persistConn             1
  pcKeepAliveTimeout      1
  respBuffer              0
  autoStart               1
  path                    /usr/local/lsws/lsphp82/bin/lsphp
  extUser                 {username}
  extGroup                {username}
  memSoftLimit            2047M
  memHardLimit            2047M
  procSoftLimit           400
  procHardLimit           500
}}
""")

            print(f"Created vhost file: {vhost_file_path}")  # Debug message
            
            # Restart OpenLiteSpeed
            try:
                subprocess.run(["sudo", "systemctl", "restart", "openlitespeed"], check=True)
                print("OpenLiteSpeed restarted successfully.")  # Debug message
            except subprocess.CalledProcessError as e:
                print(f"Failed to restart OpenLiteSpeed: {str(e)}")  # Debug message

            return True  # Indicate success
        except Exception as e:
            print(f"Failed to create vhost file: {str(e)}")  # Debug message
            return False  # Indicate failure
    else:
        print(f"Vhost file '{vhost_file_path}' already exists.")  # Debug message
        return False  # Indicate that the file already exists
        

def replace_docroot_in_virtual_conf(conf_file_path, new_docroot_path):
    
    # Check if the configuration file exists
    if not os.path.isfile(conf_file_path):
        print(f"Configuration file {conf_file_path} not found.")
        return False

    try:
        # Read the content of the config file
        with open(conf_file_path, 'r') as file:
            lines = file.readlines()

        # Modify the 'docRoot' line
        for i, line in enumerate(lines):
            if line.strip().startswith('docRoot'):
                # Replace the existing path with the new one
                lines[i] = f"docRoot                   {new_docroot_path}\n"
                break

        # Write the modified content back to the config file
        with open(conf_file_path, 'w') as file:
            file.writelines(lines)

        print(f"docRoot successfully updated to {new_docroot_path} in {conf_file_path}.")
        return True

    except Exception as e:
        print(f"An error occurred: {e}")
        return False

        
def remove_map_from_httpd_config(domain_name):
    LISTENER_CONFIG_FILE = "/usr/local/lsws/conf/httpd_config.conf"
    if not os.path.isfile(LISTENER_CONFIG_FILE):
        print(f"Configuration file {LISTENER_CONFIG_FILE} not found.")
        return False

    try:
        # Read the content of the config file
        with open(LISTENER_CONFIG_FILE, 'r') as file:
            lines = file.readlines()

        # Modify the lines to remove the mapping for the specified domain
        new_lines = []
        for line in lines:
            if not line.strip().startswith('map') or domain_name not in line:
                new_lines.append(line)

        # Write the modified content back to the config file only if changes were made
        if len(new_lines) != len(lines):
            with open(LISTENER_CONFIG_FILE, 'w') as file:
                file.writelines(new_lines)

            print(f"Mapping for domain '{domain_name}' successfully removed from {LISTENER_CONFIG_FILE}.")
            return True  # Return True if mapping was removed

        print(f"No mapping found for domain '{domain_name}' in {LISTENER_CONFIG_FILE}.")
        return False  # Return False if no mapping was found

    except Exception as e:
        print(f"An error occurred: {e}")
        return False
        
def remove_virtual_host_from_httpd_config(domain_name):
    if not os.path.isfile(LISTENER_CONFIG_FILE):
        return f"Configuration file {LISTENER_CONFIG_FILE} not found."

    try:
        with open(LISTENER_CONFIG_FILE, 'r') as file:
            lines = file.readlines()

        # Regular expression to match the start of the virtual host block for the specified domain
        virtual_host_start_pattern = re.compile(
            rf'virtualhost\s+{re.escape(domain_name)}\s*{{',
            re.DOTALL
        )

        new_lines = []
        inside_block = False

        for line in lines:
            # Check if we are entering a virtual host block
            if virtual_host_start_pattern.match(line):
                inside_block = True  # Set the flag to indicate we're inside the block
                continue  # Skip the current line that starts the block

            if inside_block:
                # Check for the closing brace of the virtual host block
                if '}' in line:
                    inside_block = False  # We found the closing brace; exit the block
                    continue  # Skip the line with the closing brace
            
            # If we are not inside a block, keep the line
            if not inside_block:
                new_lines.append(line)

        # Write the modified content back to the config file if a block was removed
        if len(new_lines) < len(lines):
            with open(LISTENER_CONFIG_FILE, 'w') as file:
                file.writelines(new_lines)
                # Restart OpenLiteSpeed
        try:
            subprocess.run(["sudo", "systemctl", "restart", "openlitespeed"], check=True)
            print("OpenLiteSpeed restarted successfully.")  # Debug message
        except subprocess.CalledProcessError as e:
            print(f"Failed to restart OpenLiteSpeed: {str(e)}")  # Debug message
        
            return f"Virtual host for '{domain_name}' and its configuration removed successfully."
        else:
            return f"No matching virtual host found for '{domain_name}'."

    except Exception as e:
        return f"An error occurred: {e}"
        
def remove_domain_folder(domain_name):
    domain_folder = f'/usr/local/lsws/conf/vhosts/{domain_name}'
    
    if os.path.exists(domain_folder):
        try:
            # Remove the domain folder and all its contents
            shutil.rmtree(domain_folder)
            return f"Domain folder '{domain_folder}' and all its contents removed successfully."
        except Exception as e:
            return f"An error occurred while removing the folder: {e}"
    else:
        return f"Domain folder '{domain_folder}' does not exist."    


def add_user_and_set_folder_permissions(username, home_dir, full_path, groupname=None):
    # Use username as groupname if not provided
    if groupname is None:
        groupname = username

    # Step 1: Check if the group exists; create it if not
    try:
        grp.getgrnam(groupname)
        logger.error(f"Group {groupname} already exists.")
    except KeyError:
        # Create the group
        try:
            subprocess.run(['sudo', 'groupadd', groupname], check=True)
            print(f"Group {groupname} added successfully.")
        except subprocess.CalledProcessError as e:
            logger.error(f"Error adding group {groupname}: {e}")
            return False

    # Step 2: Check if the user exists; create it if not
    try:
        pwd.getpwnam(username)
        print(f"User {username} already exists.")
    except KeyError:
        # Add the user and assign it to the group
        try:
            if getattr(settings, "MY_OS_NAME", "linux") == "ubuntu":
                subprocess.run(['sudo', 'adduser', '--disabled-password', '--gecos', '', '--ingroup', groupname, username], check=True)
                
            else:
                subprocess.run(['sudo', 'useradd',  '-g', groupname, '-m', username], check=True)
                
            print(f"User {username} added successfully.")
        except subprocess.CalledProcessError as e:
            logger.error(f"Error adding user {username}: {e}")
            return False

    # Step 3: Create the home directory if it does not exist
    try:
        os.makedirs(home_dir, exist_ok=True)  # Create home directory if it does not exist
        print(f"Created home directory: {home_dir}")
    except Exception as e:
        logger.error(f"Error creating home directory {home_dir}: {e}")
        return False

    # Step 4: Set home directory permissions to 711
    try:
        os.chmod(home_dir, stat.S_IRWXU | stat.S_IXGRP | stat.S_IXOTH)  # 711 (rwx--x--x)
        print(f"Permissions for {home_dir} set to 711.")
    except Exception as e:
        logger.error(f"Error setting permissions for {home_dir}: {e}")
        return False

    # Step 5: Create the document root directory if it does not exist
    try:
        os.makedirs(full_path, exist_ok=True)  # Create the directory and any necessary parent directories
        print(f"Created directory: {full_path}")
    except Exception as e:
        logger.error(f"Error creating directory {full_path}: {e}")
        return False

    # Step 6: Set ownership for the created home directory
    try:
        os.chown(home_dir, pwd.getpwnam(username).pw_uid, grp.getgrnam(groupname).gr_gid)
        print(f"Ownership for {home_dir} set to {username}:{groupname}.")
    except Exception as e:
        logger.error(f"Error setting ownership for {home_dir}: {e}")
        return False

    # Step 7: Set ownership for the created document root directory
    try:
        os.chown(full_path, pwd.getpwnam(username).pw_uid, grp.getgrnam(groupname).gr_gid)
        print(f"Ownership for {full_path} set to {username}:{groupname}.")
    except Exception as e:
        logger.error(f"Error setting ownership for {full_path}: {e}")
        return False

    # Step 8: Set permissions for the created document root directory to 755
    try:
        os.chmod(full_path, stat.S_IRWXU | stat.S_IRGRP | stat.S_IXGRP | stat.S_IROTH | stat.S_IXOTH)  # 755 (rwxr-xr-x)
        print(f"Permissions for {full_path} set to 755.")
    except Exception as e:
        logger.error(f"Error setting permissions for {full_path}: {e}")
        return False

    # Step 9: Ensure the "nobody" group and user exist
    try:
        grp.getgrnam('nobody')
        print("Group 'nobody' already exists.")
    except KeyError:
        # Create the group 'nobody' if it doesn't exist
        try:
            subprocess.run(['sudo', 'groupadd', 'nobody'], check=True)
            print("Group 'nobody' created successfully.")
        except subprocess.CalledProcessError as e:
            logger.error(f"Error creating group 'nobody': {e}")
            return False

    try:
        pwd.getpwnam('nobody')
        print("User 'nobody' already exists.")
    except KeyError:
        # Create the user 'nobody' as a system user with no login shell
        try:
            subprocess.run(['sudo', 'useradd', '-r', '-s', '/usr/sbin/nologin', '-g', 'nobody', 'nobody'], check=True)
            print("User 'nobody' created successfully.")
        except subprocess.CalledProcessError as e:
            logger.error(f"Error creating user 'nobody': {e}")
            return False

    # Step 10: Modify the full path ownership and permissions
    try:
        # Change ownership to 'username:nobody'
        subprocess.run(['sudo', 'chown', '-R', f'{username}:nobody', full_path], check=True)
        print(f"Ownership for {full_path} set to {username}:nobody.")

        # Change permissions to 775
        subprocess.run(['sudo', 'chmod', '-R', '775', full_path], check=True)
        print(f"Permissions for {full_path} set to 775.")
    except subprocess.CalledProcessError as e:
        logger.error(f"Error setting ownership/permissions for {full_path}: {e}")
        return False

    return True
    
def set_permissions_and_ownership(path, username, groupname=None, permissions=None):
    
    if groupname is None:
        groupname = username

    # Validate user and group
    try:
        user_info = pwd.getpwnam(username)
        group_info = grp.getgrnam(groupname)
    except KeyError as e:
        logger.error(e)
        print(f"Error: {e}")
        return False

    def apply_recursively(target_path):
        """
        Applies ownership and permissions to the target path and its contents if it's a directory.
        """
        try:
            # Set ownership
            os.chown(target_path, user_info.pw_uid, group_info.gr_gid)
            print(f"Ownership set for {target_path} to {username}:{groupname}.")

            # Determine and set permissions
            if permissions is None:
                if os.path.isdir(target_path):
                    path_permissions = stat.S_IRWXU | stat.S_IRGRP | stat.S_IXGRP | stat.S_IROTH | stat.S_IXOTH  # 755
                else:
                    path_permissions = stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IROTH  # 644
            else:
                path_permissions = permissions

            os.chmod(target_path, path_permissions)
            print(f"Permissions set for {target_path} to {oct(path_permissions)}.")

            # If it's a directory, recursively apply to contents
            if os.path.isdir(target_path):
                for entry in os.scandir(target_path):
                    apply_recursively(entry.path)
        except Exception as e:
            print(f"Error applying ownership or permissions for {target_path}: {e}")
            return False

    # Start the process for the given path
    apply_recursively(path)
    return True

    
def restart_openlitespeed():
    try:
        os_name = getattr(settings, "MY_OS_NAME", "linux")
        if os_name == "debian":
            subprocess.run(['sudo', 'systemctl', 'restart', 'lsws'], check=True)
        else:
            subprocess.run(['sudo', 'systemctl', 'restart', 'openlitespeed'], check=True)
            
        
        
        print("OpenLiteSpeed has been restarted successfully.")
    except subprocess.CalledProcessError as e:
        print(f"Failed to restart OpenLiteSpeed: {e}")


def get_php_versions():
    php_versions = []
    # Define a regex pattern to match version numbers
    version_pattern = re.compile(r'^\d+(\.\d+)?$')  # Matches versions like 8.1, 7.4, etc.

    # Get all files starting with 'php' in /usr/local/lsws/
    for filename in os.listdir('/usr/local/lsws/'):
        if filename.startswith('lsphp'):
            # Extract the version from the filename
            version = filename.replace('lsphp', '')  # Remove 'lsphp' to get the version number

            # Check if the extracted version matches the version pattern
            if version_pattern.match(version):
                # Add a dot after the first digit
                if '.' not in version:  # If the version does not contain a dot
                    version = f"{version[0]}.{version[1:]}"  # Insert a dot after the first digit
                php_versions.append(version)  # Use version as both value and display label

    # Sort the versions in ascending order
    php_versions.sort(key=lambda x: list(map(int, x.split('.'))))

    return php_versions
    
    
def replace_php_version_in_vhost(domain_name, new_php_version):
    vhost_directory = f"/usr/local/lsws/conf/vhosts/{domain_name}"
    vhost_file_path = os.path.join(vhost_directory, "vhost.conf")
    try:
        # Check if the vHost config file exists
        if not os.path.isfile(vhost_file_path):
            print(f"Configuration file {vhost_file_path} does not exist.")
            return False

        # Read the content of the vHost config file
        with open(vhost_file_path, 'r') as file:
            lines = file.readlines()

        # Define a regex pattern to find the ScriptHandler line
        script_handler_pattern = re.compile(r'^(.*?add\s+lsapi:)(\w+)(\s+php.*)$', re.MULTILINE)

        # Replace the old version in the ScriptHandler line
        for i, line in enumerate(lines):
            if script_handler_pattern.search(line):
                # Replace the version part (after lsapi:) with the new version
                lines[i] = script_handler_pattern.sub(r'\1' + f'{new_php_version}' + r'\3', line)
                print(f"Replaced PHP version in {vhost_file_path}: {line.strip()} -> {lines[i].strip()}")
                break
        else:
            print("No ScriptHandler line found to replace.")
            return False

        # Write the modified content back to the vHost config file
        with open(vhost_file_path, 'w') as file:
            file.writelines(lines)

        return True

    except Exception as e:
        print(f"Error occurred: {e}")
        return False   
        
def replace_extprocessor_socket_and_path(domain_name, new_processor_name, pure_version):
    vhost_directory = f"/usr/local/lsws/conf/vhosts/{domain_name}"
    vhost_file_path = os.path.join(vhost_directory, "vhost.conf")

    try:
        # Check if the vHost config file exists
        if not os.path.isfile(vhost_file_path):
            print(f"Configuration file {vhost_file_path} does not exist.")
            return False

        # Read the content of the vHost config file
        with open(vhost_file_path, 'r') as file:
            lines = file.readlines()

        # Define regex patterns for replacements
        processor_pattern = re.compile(r'^(extprocessor\s+)(\S+)(\s*{)', re.MULTILINE)
        socket_pattern = re.compile(r'(address\s*uds://tmp/lshttpd/)(\S+)(\.sock)', re.MULTILINE)
        # Updated path pattern to allow for multiple spaces after 'path'
        path_pattern = re.compile(r'^(path\s+)(\s*)(.*?)(/bin/lsphp)', re.MULTILINE)

        # Initialize flags to track replacements
        processor_replaced = False
        socket_replaced = False
        path_replaced = False

        # Replace the extprocessor name
        for i, line in enumerate(lines):
            if processor_pattern.search(line):
                lines[i] = processor_pattern.sub(r'\1' + new_processor_name + r'\3', line)
                print(f"Replaced extprocessor name in {vhost_file_path}: {line.strip()} -> {lines[i].strip()}")
                processor_replaced = True
                break  # Exit after the first replacement

        # Replace the socket path
        for i, line in enumerate(lines):
            if socket_pattern.search(line):
                lines[i] = socket_pattern.sub(r'\1' + new_processor_name + r'\3', line)
                print(f"Replaced socket path in {vhost_file_path}: {line.strip()} -> {lines[i].strip()}")
                socket_replaced = True
                break  # Exit after the first replacement

        # Replace the path with pure_version
        for i, line in enumerate(lines):
            if path_pattern.search(line):
                lines[i] = path_pattern.sub(r'\1' + f'\2/usr/local/lsws/{pure_version}' + r'\4', line)  # Keep spaces and update the path directly
                print(f"Replaced path in {vhost_file_path}: {line.strip()} -> {lines[i].strip()}")
                path_replaced = True
                break  # Exit after the first replacement

        # Confirm that all replacements were successful
        if not processor_replaced:
            print("No extprocessor line found to replace.")
        if not socket_replaced:
            print("No socket path line found to replace.")
        if not path_replaced:
            print("No path line found to replace.")

        # Write the modified content back to the vHost config file
        with open(vhost_file_path, 'w') as file:
            file.writelines(lines)
            print(f"Updated {vhost_file_path} successfully.")

        return True

    except Exception as e:
        print(f"Error occurred: {e}")
        return False
        

def replace_path(domain_name, pure_version): 
    vhost_directory = f"/usr/local/lsws/conf/vhosts/{domain_name}"
    vhost_file_path = os.path.join(vhost_directory, "vhost.conf")
    
    # Check if the file exists
    if not os.path.isfile(vhost_file_path):
        print(f"File not found: {vhost_file_path}")
        return

    # Read the file contents
    with open(vhost_file_path, 'r') as file:
        lines = file.readlines()

    # Replace the version in the lines
    updated_lines = []
    for line in lines:
        if "/usr/local/lsws/" in line and "/bin/lsphp" in line:
            # Split the line on '/usr/local/lsws/' and '/bin/lsphp'
            parts = line.split('/usr/local/lsws/')
            if len(parts) > 1:
                left_part = parts[0]  # Everything before the path
                right_part = parts[1]  # Everything after '/usr/local/lsws/'
                
                # Now split right_part on '/bin/lsphp'
                right_parts = right_part.split('/bin/lsphp')
                if len(right_parts) > 1:
                    # Construct the new line
                    new_line = f"{left_part}/usr/local/lsws/{pure_version}/bin/lsphp{right_parts[1]}"
                    updated_lines.append(new_line)
                else:
                    updated_lines.append(line)  # Keep original line if no match
            else:
                updated_lines.append(line)  # Keep original line if no match
        else:
            updated_lines.append(line)  # Keep original line if no match

    # Write the updated lines back to the file
    with open(vhost_file_path, 'w') as file:
        file.writelines(updated_lines)

    print(f"Replaced version in {vhost_file_path}")
    
def change_php_version(domain_name, version_name, version):
    # Construct the full PHP version string
    version_name=version_name.replace('.', '')
    version_string = f"lsphp{version}"  # Correctly construct the version string
    replace_php_version_in_vhost(domain_name, version_name)    
    replace_path(domain_name, version_string)  # Pass the constructed version string
    replace_extprocessor_socket_and_path(domain_name, version_name, version_string) 
    
  
def get_ssl_details(domain_name):
    cert_path = f'/etc/letsencrypt/live/{domain_name}/fullchain.pem'  # Ensure the path is correct
    print(f"Checking certificate path: {cert_path}")  # Debugging line
    
    try:
        # Get expiration date
        expiration_result = subprocess.run(
            ['openssl', 'x509', '-in', cert_path, '-noout', '-enddate'],
            capture_output=True,
            text=True,
            check=True
        )
        expiration_output = expiration_result.stdout.strip()
        print(f"OpenSSL expiration output: {expiration_output}")  # Debugging line

        # Extract the expiration date
        expiration_date_str = expiration_output.split('=')[1]
        expiration_date = datetime.strptime(expiration_date_str, '%b %d %H:%M:%S %Y %Z')
        formatted_date = expiration_date.strftime('%d-%m-%y %I:%M %p')

        # Get certificate type
        key_type_result = subprocess.run(
            ['openssl', 'x509', '-in', cert_path, '-noout', '-text'],
            capture_output=True,
            text=True,
            check=True
        )
        key_type_output = key_type_result.stdout.strip()
        print(f"OpenSSL key type output: {key_type_output}")  # Debugging line

        # Determine the certificate type
        if "RSA Public-Key" in key_type_output:
            cert_type = "RSA"
        elif "EC Public-Key" in key_type_output:
            cert_type = "ECC"
        else:
            cert_type = "Unknown"

        # Get certificate issuer and subject
        issuer_result = subprocess.run(
            ['openssl', 'x509', '-in', cert_path, '-noout', '-issuer'],
            capture_output=True,
            text=True,
            check=True
        )
        issuer_output = issuer_result.stdout.strip()
        print(f"OpenSSL issuer output: {issuer_output}")  # Debugging line

        subject_result = subprocess.run(
            ['openssl', 'x509', '-in', cert_path, '-noout', '-subject'],
            capture_output=True,
            text=True,
            check=True
        )
        subject_output = subject_result.stdout.strip()
        print(f"OpenSSL subject output: {subject_output}")  # Debugging line

        # Extract the issuer and subject values
        issuer_name = issuer_output.split('=')[-1].split()[0]
        subject_name = subject_output.split('=')[-1]

        # Check if the certificate is self-signed
        if issuer_name.strip() == subject_name.strip():
            cert_validity = "Self-signed certificate"
        else:
            cert_validity = get_ssl_issuer_org(cert_path)

        return {
            "expiration_date": formatted_date,
            "certificate_type": cert_type,
            "issuer": issuer_name,
            "certificate_validity": cert_validity
        }
    except subprocess.CalledProcessError as e:
        print(f"Error running OpenSSL: {e.stderr.strip()}")  # Improved error logging
    except IndexError as e:
        print(f"Error parsing output: {e}")  # Log output for parsing errors
    except Exception as e:
        print(f"An unexpected error occurred: {e}")  # General error logging

    # Default values when an error occurs
    return {
        "expiration_date": "Not Available",
        "certificate_type": "Unknown",
        "issuer": "Unknown",
        "certificate_validity": "Invalid or Not Found"
    }
 
def get_ssl_issuer_org(cert_path: str) -> str:
    
    try:
        # Run OpenSSL command to get the issuer details
        result = subprocess.run(
            ["openssl", "x509", "-in", cert_path, "-noout", "-issuer"],
            check=True,
            capture_output=True,
            text=True
        )

        # Extract 'O=' (Organization) using regex
        
        match = re.search(r"O\s*=\s*([^,]+)", result.stdout)
        return match.group(1).strip() if match else "No Organization found"
    
    except subprocess.CalledProcessError as e:
        return f"Error reading certificate: {e.stderr.strip()}"
    except Exception as e:
        return f"Error: {str(e)}"
        
def issue_ssl_certificate(domain: str, webroot_path: str) -> bool:
    command = [
        '/root/.acme.sh/acme.sh',
        '--issue',
        '-d', domain,
        '--cert-file', f'/etc/letsencrypt/live/{domain}/cert.pem',
        '--key-file', f'/etc/letsencrypt/live/{domain}/privkey.pem',
        '--fullchain-file', f'/etc/letsencrypt/live/{domain}/fullchain.pem',
        '-w', webroot_path,
        '--reloadcmd', '/usr/local/lsws/bin/lswsctrl restart',
        '--force',
        '--debug'
    ]

    try:
        # Execute the command
        create_letsencrypt_if_not_exist(domain);
        result = subprocess.run(command, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        email_ssl(domain)
        add_ssl_smtp_mail(domain)
        panel_virtual_host(domain)  # Call to manage_virtual_host             
        panel_listener_mapping("add", domain)
        create_panel_vhost_file(domain) 
        print(result.stdout.decode())
        logger.info(f"SSL issued successfully for {domain}:\n{result.stdout}")
        return True  # Return True if command executes successfully
    except subprocess.CalledProcessError as e:
        logger.error(f"An error occurred while issuing SSL for {domain}:\n{e.stderr}")
        print(f"An error occurred: {e.stderr.decode()}")
        return False  # Return False if command fails     


def email_ssl(domain):
    file_path = '/etc/dovecot/dovecot.conf'
    block = f"""local_name {domain} {{
    ssl_cert = </etc/letsencrypt/live/{domain}/fullchain.pem
    ssl_key = </etc/letsencrypt/live/{domain}/privkey.pem
}}\n"""

    try:
        with open(file_path, 'r') as f:
            content = f.read()

        # Check if the block already exists
        if f"local_name {domain} {{" in content:
            print(f"Block for '{domain}' already exists.")
            return

        # Append the block at the end of the file
        with open(file_path, 'a') as f:
            f.write('\n' + block)

        print(f"Block for '{domain}' added.")
        subprocess.run(["sudo", "systemctl", "restart", "dovecot"], check=True)
    except Exception as e:
        print(f"Error updating file: {e}") 


def add_ssl_smtp_mail(domain):
    key_path = f"/etc/letsencrypt/live/{domain}/privkey.pem"
    cert_path = f"/etc/letsencrypt/live/{domain}/fullchain.pem"
    file_path="/etc/postfix/vmail_ssl.map"
    line_to_add = f"{domain} {key_path} {cert_path}\n"
    changed = False

    try:
        try:
            with open(file_path, "r") as f:
                lines = f.readlines()
                if line_to_add in lines:
                    print("Line already exists. No change made.")
                else:
                    changed = True
        except FileNotFoundError:
            changed = True  # File doesn't exist, will create

        if changed:
            with open(file_path, "a") as f:
                f.write(line_to_add)
            print("Line added.")

        # Step 3: Run postmap -F
        subprocess.run(["postmap", "-F", f"hash:{file_path}"], check=True)
        print("postmap updated.")

        # Step 4: Restart Postfix
        subprocess.run(["systemctl", "restart", "postfix"], check=True)
        print("Postfix restarted.")

    except Exception as e:
        print(f"Error: {e}")        



def restart_pdns():
    try:
        # Execute the command to restart PowerDNS
        subprocess.check_call(['sudo', 'systemctl', 'restart', 'pdns'])
        print("PowerDNS service restarted successfully.")
        return True  # Indicate success
    except subprocess.CalledProcessError as e:
        print(f"Failed to restart PowerDNS: {e}")
        return False  # Indicate failure   


def create_letsencrypt_if_not_exist(domain_name):
    folder_path = f"/etc/letsencrypt/live/{domain_name}"
    
    try:
        # Check if the directory exists, and create it if it doesn't
        if not os.path.exists(folder_path):
            os.makedirs(folder_path)
            print(f"Folder created: {folder_path}")
        else:
            print(f"Folder already exists: {folder_path}")
    except Exception as e:
        print(f"An error occurred while creating the folder: {e}")    


def vhost_action(domain_name, action):
    vhost_directory = f"/usr/local/lsws/conf/vhosts/{domain_name}"
    conf_file_path = os.path.join(vhost_directory, "vhost.conf")
    
    # Check if the configuration file exists
    if not os.path.isfile(conf_file_path):
        print(f"Configuration file {conf_file_path} not found.")
        return False

    try:
        # Read the content of the config file
        with open(conf_file_path, 'r') as file:
            lines = file.readlines()

        old_home_path = None
        new_path = None
        current_path = None
        updated_lines = []
        docRoot_found = False
        main_docRoot_commented = False

        # Define action paths
        action_paths = {
            "suspend": '/usr/local/lsws/Example/html/blocked',
            "bandwidth": '/usr/local/lsws/Example/html/bandwidth'
        }

        # Process each line and modify accordingly
        for line in lines:
            stripped_line = line.strip()

            if 'docRoot' in stripped_line:
                # Check if this is the first occurrence of docRoot
                if not docRoot_found:
                    if stripped_line.startswith('# docRoot'):
                        current_path = stripped_line.split()[-1]
                        main_docRoot_commented = True  # Mark that main path is commented out
                    else:
                        current_path = stripped_line.split()[-1]

                    # If the path starts with /home, backup the path and don't remove it
                    if current_path.startswith("/home"):
                        old_home_path = current_path
                        # Check for current action before disabling the path
                        if action == "restore":
                            # Restore the original path
                            updated_lines.append(f"docRoot                   {old_home_path}\n")
                        else:
                            # Skip further changes if action is already applied
                            if current_path == action_paths.get(action):
                                print(f"Action '{action}' is already applied to {current_path}. Skipping.")
                                return False

                            # Comment out the current path (if it's the main /home path) and set the new action path
                            updated_lines.append(f"# {line.strip()}\n")
                            new_path = action_paths.get(action)
                            updated_lines.append(f"docRoot                   {new_path}\n")
                    elif action == "restore":
                        # If restoring, re-enable the original /home path
                        if old_home_path:
                            updated_lines.append(f"docRoot                   {old_home_path}\n")
                        else:
                            print("No valid path to restore.")
                            return False
                    else:
                        # Comment out the existing docRoot if not already commented
                        if not main_docRoot_commented:
                            updated_lines.append(f"# {line.strip()}\n")
                            main_docRoot_commented = True

                        # Apply the action path (suspend/bandwidth)
                        if action in action_paths:
                            new_path = action_paths[action]
                            updated_lines.append(f"docRoot                   {new_path}\n")
                        else:
                            print(f"Invalid action: {action}")
                            return False

                    docRoot_found = True
                else:
                    # Ignore additional docRoot lines
                    continue
            else:
                # Keep all other lines unchanged
                updated_lines.append(line)

        # If the action is restore and no /home path was found, it's an error
        if action == "restore" and old_home_path is None:
            print("No original /home path found to restore.")
            return False

        # Write the modified content back to the config file
        with open(conf_file_path, 'w') as file:
            file.writelines(updated_lines)

        print(f"docRoot successfully updated in {conf_file_path}.")
        return True

    except Exception as e:
        print(f"An error occurred: {e}")
        return False

