import os
import subprocess
import uuid
import yaml
import paramiko
from flask import Flask, jsonify, request, render_template, send_from_directory
from flask_cors import CORS
from flask_jwt_extended import (
    JWTManager, create_access_token,
    jwt_required, get_jwt_identity,
    verify_jwt_in_request
)
from passlib.hash import pbkdf2_sha256
from logging.handlers import RotatingFileHandler
import json
from datetime import datetime, timedelta
import random
import logging
import string
import user_agents
import traceback
from werkzeug.exceptions import BadRequest, NotFound, HTTPException
from apscheduler.schedulers.background import BackgroundScheduler
from jinja2 import Template
import posixpath
from functools import wraps

# Load environment variables for sensitive configurations
from dotenv import load_dotenv
load_dotenv()  # Loads variables from a .env file

# SSH Configuration
SSH_CONFIG = {
    'hostname': os.getenv('SSH_HOSTNAME', 'your_server_ip'),  # Replace with your server IP or hostname
    'port': int(os.getenv('SSH_PORT', 22)),
    'username': os.getenv('SSH_USERNAME', 'your_ssh_username'),
    'password': os.getenv('SSH_PASSWORD'),  # Ensure this is set
    'key_filepath': os.getenv('SSH_KEY_FILEPATH')  # Optional: path to SSH private key
}

# Load the server IP from the environment variable
SERVER_IP = os.getenv('SERVER_IP', 'your_server_ip')  # Replace with your server IP

app = Flask(
    __name__,
    static_folder='static',
    static_url_path='/static',  # Ensure static files are served from /static
    template_folder='templates'
)
CORS(app)

# JWT Configuration
app.config['JWT_SECRET_KEY'] = os.getenv('JWT_SECRET_KEY', 'your_jwt_secret_key_here')  # Set this in environment
app.config['JWT_ACCESS_TOKEN_EXPIRES'] = timedelta(hours=1)
jwt = JWTManager(app)

# Server Plans
SERVER_PLANS = [
    {
        "key": "basic",
        "name": "Базовый",
        "cpu": 2,
        "ram": 4,
        "disk": "50GB",
        "price": 500
    },
    {
        "key": "advanced",
        "name": "Продвинутый",
        "cpu": 4,
        "ram": 8,
        "disk": "100GB",
        "price": 1000
    },
    {
        "key": "premium",
        "name": "Премиум",
        "cpu": 8,
        "ram": 16,
        "disk": "200GB",
        "price": 2000
    }
]

OS_OPTIONS = {
    'win2020': 'Windows Server 2020',
    'win2022': 'Windows Server 2022',
    'win2025': 'Windows Server 2025',
    'win10': 'Windows 10',
    'win11': 'Windows 11'
}

# Define Remote Containers Directory
REMOTE_CONTAINERS_DIR = "/root"

# Initialize IP Pool
IP_POOL_START = [192, 168, 1, 100]  # Starting IP address
current_ip = IP_POOL_START.copy()

DB_LOCK_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'db.json.lock')

# Log directories (local)
LOGS_DIR = 'logs'
if not os.path.exists(LOGS_DIR):
    os.makedirs(LOGS_DIR)

# Helper functions
def generate_unique_ip():
    global current_ip
    if SERVER_IP:
        return SERVER_IP  # Return the fixed IP from env variable

    ip = '.'.join(map(str, current_ip))
    current_ip[3] += 1
    if current_ip[3] > 254:
        current_ip[3] = 1
        current_ip[2] += 1
        if current_ip[2] > 254:
            current_ip[2] = 1
            current_ip[1] += 1
            if current_ip[1] > 254:
                current_ip[1] = 1
                current_ip[0] += 1
                if current_ip[0] > 254:
                    raise Exception("IP Pool Exhausted")
    return ip

def get_remote_server_dir(container_name):
    safe_container_name = ''.join(c for c in container_name if c.isalnum() or c in ('_', '-'))
    return posixpath.join(REMOTE_CONTAINERS_DIR, safe_container_name)

@app.route('/')
def home():
    return render_template('index.html')

@app.route('/admin')
def admin_page():
    return render_template('admin.html')

# Serve favicon
@app.route('/favicon.ico')
def favicon():
    return send_from_directory(os.path.join(app.root_path, 'static'),
                               'favicon.ico', mimetype='image/vnd.microsoft.icon')

def setup_logging():
    formatter = logging.Formatter(
        '[%(asctime)s] %(levelname)s in %(module)s: %(message)s'
    )
    file_handler = RotatingFileHandler(
        os.path.join(LOGS_DIR, 'app.log'),
        maxBytes=1024 * 1024,
        backupCount=10
    )
    file_handler.setFormatter(formatter)
    file_handler.setLevel(logging.INFO)

    error_file_handler = RotatingFileHandler(
        os.path.join(LOGS_DIR, 'error.log'),
        maxBytes=1024 * 1024,
        backupCount=10
    )
    error_file_handler.setFormatter(formatter)
    error_file_handler.setLevel(logging.ERROR)

    app.logger.addHandler(file_handler)
    app.logger.addHandler(error_file_handler)
    app.logger.setLevel(logging.INFO)

    @app.before_request
    def log_request_info():
        app.logger.info(f'Request: {request.method} {request.url} from {request.remote_addr}')
        app.logger.debug(f'Headers: {dict(request.headers)}')

# Error Handlers

from werkzeug.exceptions import HTTPException, NotFound

@app.errorhandler(NotFound)
def handle_404(e):
    app.logger.error(f'404 Error: {request.url} not found.')
    return render_template('404.html'), 404

@app.errorhandler(Exception)
def handle_exception(e):
    if isinstance(e, HTTPException):
        return e
    app.logger.error(f'Unhandled Exception: {str(e)}')
    app.logger.error(traceback.format_exc())
    return jsonify({'error': 'An internal server error occurred'}), 500

def load_db():
    try:
        db_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'db.json')
        if not os.path.exists(db_path):
            with open(db_path, 'w', encoding='utf-8') as f:
                json.dump({'users': {}, 'logs': []}, f, indent=2)
            app.logger.info('Initialized new db.json with default structure.')

        with open(db_path, 'r', encoding='utf-8') as f:
            content = f.read().strip()
            app.logger.debug(f'Content of db.json: {content}')  # Debug log
            if not content:
                app.logger.warning('db.json is empty. Initializing with default structure.')
                db = {'users': {}, 'logs': []}
            else:
                db = json.loads(content)

        db.setdefault('logs', [])
        db.setdefault('users', {})

        # Clean and validate user data
        cleaned_users = {}
        for username, user in db['users'].items():
            if isinstance(user, dict):
                user.setdefault('role', 'user')
                cleaned_users[username] = user
            else:
                app.logger.warning(f"Skipping invalid user entry: {username} is not a dictionary.")

        db['users'] = cleaned_users

        # No automatic admin creation or assignment
        # Admin rights are only given to users explicitly in the db.json

        save_db(db)
        return db
    except json.JSONDecodeError as e:
        app.logger.error(f'JSON Decode Error in load_db: {e}')
        raise
    except Exception as e:
        app.logger.error(f'Database load error: {str(e)}')
        app.logger.error(traceback.format_exc())
        raise

def save_db(db):
    db_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'db.json')
    with open(db_path, 'w', encoding='utf-8') as f:
        json.dump(db, f, indent=2)

def log_activity(username, action, user_agent_string):
    try:
        db = load_db()
        ua = user_agents.parse(user_agent_string)
        log_entry = {
            'timestamp': datetime.now().isoformat(),
            'username': username,
            'action': action,
            'browser': ua.browser.family,
            'os': ua.os.family,
            'device': ua.device.family,
            'ip': request.remote_addr
        }
        db['logs'].append(log_entry)
        save_db(db)
    except Exception as e:
        app.logger.error(f'Error logging activity: {str(e)}')
        app.logger.error(traceback.format_exc())

def generate_password(length=12):
    return ''.join(random.choices(string.ascii_letters + string.digits, k=length))

def connect_via_ssh():
    ssh = paramiko.SSHClient()
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    connect_params = {
        'hostname': SSH_CONFIG['hostname'],
        'port': SSH_CONFIG.get('port', 22),
        'username': SSH_CONFIG['username']
    }
    if SSH_CONFIG.get('key_filepath'):
        connect_params['key_filename'] = SSH_CONFIG['key_filepath']
    elif SSH_CONFIG.get('password'):
        connect_params['password'] = SSH_CONFIG['password']
    else:
        raise ValueError("Either 'key_filepath' or 'password' must be provided in SSH_CONFIG.")

    try:
        ssh.connect(**connect_params)
        app.logger.info(f"SSH connection established to {SSH_CONFIG['hostname']}")
    except Exception as e:
        app.logger.error(f'SSH connection failed: {e}')
        return None
    return ssh

def execute_ssh_command(command, ssh_client, remote_path=None):
    try:
        if remote_path:
            command = f"cd {remote_path} && {command}"

        app.logger.info(f"Executing SSH Command: {command}")
        stdin, stdout, stderr = ssh_client.exec_command(command)
        exit_status = stdout.channel.recv_exit_status()
        stdout_str = stdout.read().decode().strip()
        stderr_str = stderr.read().decode().strip()
        return stdout_str, stderr_str, exit_status
    except Exception as e:
        app.logger.error(f'SSH command execution error: {e}')
        return None, str(e), -1

def create_docker_compose_content(container_name, version, plan_details, rdp_username, rdp_password, vnc_password, public_port_8006, public_port_rdp_tcp, public_port_rdp_udp, public_port_vnc):
    docker_compose_template = """
version: '3'
services:
  windows:
    image: dockurr/windows
    container_name: {{ container_name }}
    environment:
      VERSION: "{{ version }}"
      DISK_SIZE: "{{ disk_size }}"
      RAM_SIZE: "{{ ram_size }}"
      CPU_CORES: "{{ cpu_cores }}"
      USERNAME: "{{ username }}"
      PASSWORD: "{{ password }}"
      VNC_PASSWORD: "{{ vnc_password }}"
      KEYBOARD: "us"
    devices:
      - /dev/kvm
    cap_add:
      - NET_ADMIN
    ports:
      - "{{ public_port_8006 }}:8006/tcp"
      - "{{ public_port_rdp_tcp }}:3389/tcp"
      - "{{ public_port_rdp_udp }}:3389/udp"
      - "{{ public_port_vnc }}:5900/tcp"
    stop_grace_period: 2m
    restart: unless-stopped
    """
    template = Template(docker_compose_template)
    return template.render(
        container_name=container_name,
        version=version,
        disk_size=plan_details['disk'],
        ram_size=plan_details['ram'],
        cpu_cores=plan_details['cpu'],
        username=rdp_username,
        password=rdp_password,
        vnc_password=vnc_password,
        public_port_8006=public_port_8006,
        public_port_rdp_tcp=public_port_rdp_tcp,
        public_port_rdp_udp=public_port_rdp_udp,
        public_port_vnc=public_port_vnc
    )

def is_valid_username(username):
    import re
    pattern = re.compile(r'^[A-Za-z0-9_]{3,30}$')
    return bool(pattern.match(username))

# Admin Decorator
def admin_required(fn):
    @wraps(fn)
    def wrapper(*args, **kwargs):
        verify_jwt_in_request()
        current_user = get_jwt_identity()
        db = load_db()
        user_data = db['users'].get(current_user)
        if not user_data or user_data.get('role') != 'admin':
            app.logger.warning(f'Unauthorized admin access attempt by user: {current_user}')
            return jsonify({'error': 'Admin access required'}), 403
        return fn(*args, **kwargs)
    return wrapper

@app.route('/api/login', methods=['POST'])
def login():
    try:
        app.logger.info('Processing login request')
        db = load_db()
        data = request.get_json()

        if not data:
            app.logger.warning('No JSON data in login request')
            return jsonify({'error': 'No JSON data provided'}), 400

        username = data.get('username')
        password = data.get('password')

        app.logger.info(f'Login attempt for user: {username}')

        if not username or not password:
            app.logger.warning('Missing username or password in login request')
            return jsonify({'error': 'Username and password are required'}), 400

        user_data = db['users'].get(username)
        if not user_data:
            app.logger.warning(f'Login failed: User {username} not found')
            return jsonify({'error': 'Invalid credentials'}), 401

        # Only use the password verification method
        if pbkdf2_sha256.verify(password, user_data['password']):
            app.logger.info(f'Login successful for user: {username}')
            access_token = create_access_token(identity=username)
            try:
                log_activity(username, 'login', request.headers.get('User-Agent', ''))
            except Exception as e:
                app.logger.error(f'Failed to log login activity: {str(e)}')
            return jsonify({
                'token': access_token,
                'username': username,
                'balance': user_data.get('balance', 0),
                'role': user_data.get('role', 'user')  # Include role in response
            }), 200

        app.logger.warning(f'Login failed: Invalid password for user {username}')
        return jsonify({'error': 'Invalid credentials'}), 401

    except Exception as e:
        app.logger.error(f'Login error: {str(e)}')
        app.logger.error(traceback.format_exc())
        return jsonify({'error': 'An internal server error occurred'}), 500

@app.route('/api/register', methods=['POST'])
def register():
    try:
        app.logger.info('Processing registration request')
        db = load_db()
        data = request.get_json()

        if not data:
            app.logger.warning('No JSON data in registration request')
            return jsonify({'error': 'No JSON data provided'}), 400

        username = data.get('username')
        password = data.get('password')

        app.logger.info(f'Registration attempt for username: {username}')

        if not username or not password:
            app.logger.warning('Missing username or password in registration request')
            return jsonify({'error': 'Username and password are required'}), 400

        if not is_valid_username(username):
            app.logger.warning(f'Invalid username attempted: {username}')
            return jsonify({'error': 'Invalid username. Please use only letters, numbers, and underscores. Length between 3-30 characters.'}), 400

        if username in db['users']:
            app.logger.warning(f'Registration failed: Username {username} already exists')
            return jsonify({'error': 'Username already taken'}), 400

        hashed_password = pbkdf2_sha256.hash(password)

        db['users'][username] = {
            'password': hashed_password,
            'servers': [],
            'balance': 0,
            'tickets': [],
            'logs': [],
            'created_at': datetime.now().isoformat(),
            'role': 'user'  # Assign 'user' role by default
        }

        save_db(db)
        app.logger.info(f'Registration successful for user: {username}')
        log_activity(username, 'register', request.headers.get('User-Agent', ''))
        return jsonify({'message': 'Registration successful'}), 201

    except Exception as e:
        app.logger.error(f'Registration error: {str(e)}')
        app.logger.error(traceback.format_exc())
        return jsonify({'error': 'An internal server error occurred'}), 500

@app.route('/api/servers', methods=['GET', 'POST'])
@jwt_required()
def manage_servers():
    current_user = get_jwt_identity()
    db = load_db()

    user_data = db['users'].get(current_user)
    if not user_data:
        app.logger.warning(f'User {current_user} not found when accessing /api/servers')
        return jsonify({'error': 'User not found'}), 404

    if request.method == 'GET':
        servers = user_data.get('servers', [])
        return jsonify(servers), 200

    elif request.method == 'POST':
        data = request.get_json()

        if not data or 'plan' not in data or 'os' not in data or 'name' not in data:
            app.logger.warning('Invalid request data for server creation')
            return jsonify({'error': 'Invalid request data'}), 400

        plan_key = data['plan']
        os_selected = data['os']

        selected_plan = next((p for p in SERVER_PLANS if p['key'] == plan_key), None)

        if not selected_plan:
            app.logger.error(f"Invalid plan selected: {plan_key}")
            return jsonify({'error': 'Invalid plan selected'}), 400

        if user_data.get('balance', 0) < selected_plan['price']:
            app.logger.error(f"User {current_user} has insufficient funds.")
            return jsonify({'error': 'Insufficient funds'}), 400

        if os_selected not in OS_OPTIONS:
            app.logger.error(f"Invalid operating system selected: {os_selected}")
            return jsonify({'error': 'Invalid operating system selected'}), 400

        # Check if a server with the same name exists
        existing_server = next((s for s in user_data['servers'] if s['name'] == data['name']), None)
        if existing_server:
            return jsonify({'error': 'Server with this name already exists'}), 400

        # Generate a unique server ID
        new_server_id = max([s['id'] for s in user_data['servers']], default=0) + 1
        container_name = f"server_{new_server_id}"

        rdp_password = generate_password()
        vnc_password = generate_password()
        public_port_8006 = random.randint(10000, 60000)
        public_port_rdp_tcp = random.randint(10000, 60000)
        public_port_rdp_udp = public_port_rdp_tcp
        public_port_vnc = random.randint(5900, 6000)

        docker_compose_content = create_docker_compose_content(
            container_name, os_selected, selected_plan,
            data.get('rdp_username', 'admin'), rdp_password,
            vnc_password,  # Pass VNC password
            public_port_8006, public_port_rdp_tcp, public_port_rdp_udp,
            public_port_vnc  # Pass VNC port
        )

        ssh_client = connect_via_ssh()
        if not ssh_client:
            return jsonify({'error': 'Failed to establish SSH connection'}), 500

        remote_path = get_remote_server_dir(container_name)

        try:
            mkdir_command = f"mkdir -p {remote_path}"
            app.logger.info(f"Creating remote directory: {remote_path}")
            stdout_str, stderr_str, exit_status = execute_ssh_command(mkdir_command, ssh_client)
            if exit_status != 0:
                app.logger.error(f"Failed to create remote directory {remote_path}: {stderr_str}")
                raise Exception(f"Failed to create remote directory: {stderr_str}")
            app.logger.info(f"Remote directory created: {remote_path}")

            docker_compose_command = f"""cat <<EOF > {remote_path}/docker-compose.yml
{docker_compose_content}
EOF
"""
            app.logger.info(f"Creating docker-compose.yml on remote server for {container_name}")
            stdout_str, stderr_str, exit_status = execute_ssh_command(docker_compose_command, ssh_client)
            if exit_status != 0:
                app.logger.error(f"Error creating docker-compose.yml on remote server: {stderr_str}")
                raise Exception(f"Failed to create docker-compose.yml: {stderr_str}")
            app.logger.info(f"docker-compose.yml created successfully at {remote_path}")

            validate_command = f"docker-compose -f {remote_path}/docker-compose.yml config"
            validate_stdout, validate_stderr, validate_exit_status = execute_ssh_command(validate_command, ssh_client)
            if validate_exit_status != 0:
                app.logger.error(f'Docker Compose Validation Error: {validate_stderr}')
                raise Exception(f'Docker Compose validation failed: {validate_stderr}')
            else:
                app.logger.info("Docker Compose configuration is valid.")

            deploy_command = f"docker-compose -f {remote_path}/docker-compose.yml up -d"
            app.logger.info(f"Deploying server {container_name} on remote server")
            stdout_str, stderr_str, deploy_exit_status = execute_ssh_command(deploy_command, ssh_client)
            if deploy_exit_status != 0:
                app.logger.error(f'Docker Compose Deployment Error: {stderr_str}')
                raise Exception(f'Docker Compose deployment failed: {stderr_str}')
            else:
                app.logger.info(f"Server {container_name} deployed successfully.")
        except Exception as e:
            app.logger.error(f'Error during SSH operation: {e}')
            return jsonify({'error': f'Failed to deploy server: {str(e)}'}), 500
        finally:
            ssh_client.close()

        new_server = {
            'id': new_server_id,
            'name': data['name'],
            'plan': {
                'key': selected_plan['key'],
                'name': selected_plan['name'],
                'cpu': selected_plan['cpu'],
                'ram': selected_plan['ram'],
                'disk': selected_plan['disk'],
                'price': selected_plan['price']
            },
            'os': OS_OPTIONS[os_selected],
            'status': 'active',
            'ip': generate_unique_ip(),
            'created_at': datetime.now().isoformat(),
            'container_name': container_name,
            'ports': {
                '8006/tcp': public_port_8006,
                '3389/tcp': public_port_rdp_tcp,
                '3389/udp': public_port_rdp_udp,
                '5900/tcp': public_port_vnc
            },
            'vnc_password': vnc_password,
            'vnc_address': f"http://{SERVER_IP}:{public_port_vnc}"  # Assuming SERVER_IP is the public IP
        }

        user_data['balance'] -= selected_plan['price']
        user_data['servers'].append(new_server)
        save_db(db)
        log_activity(current_user, 'create_server', request.headers.get('User-Agent', ''))
        return jsonify(new_server), 201

def monthly_billing_check():
    app.logger.info("Checking for monthly billing...")
    try:
        db = load_db()
        for username, user in db['users'].items():
            for server in user.get('servers', []):
                if server.get("next_payment_due"):
                    due_date = datetime.fromisoformat(server["next_payment_due"])
                    if datetime.now() >= due_date:
                        handle_billing_cycle(user, server)
        save_db(db)
    except Exception as e:
        app.logger.error(f"Error during monthly billing check: {e}")
        app.logger.error(traceback.format_exc())

def handle_billing_cycle(user, server):
    plan = server["plan"]
    plan_price = plan["price"]

    if user.get("balance", 0) >= plan_price:
        user["balance"] -= plan_price
        server["next_payment_due"] = (datetime.now() + timedelta(days=30)).isoformat()
        app.logger.info(f"Successfully billed user for server '{server['name']}'. Next payment due on {server['next_payment_due']}.")
    else:
        server["status"] = "Заморожен"
        server["freeze_reason"] = "Недостаточно средств."
        server["freeze_date"] = datetime.now().isoformat()
        app.logger.info(f"Server '{server['name']}' frozen due to insufficient funds.")

def check_frozen_servers():
    app.logger.info("Checking for frozen servers...")
    try:
        db = load_db()
        for username, user in db['users'].items():
            servers_to_remove = []
            for server in user.get('servers', []):
                if server["status"] == "Заморожен":
                    freeze_date = datetime.fromisoformat(server["freeze_date"])
                    if datetime.now() > freeze_date + timedelta(days=3):
                        ssh_client = connect_via_ssh()
                        if not ssh_client:
                            app.logger.error(f"Failed to establish SSH connection to delete frozen server '{server['name']}'.")
                            continue
                        try:
                            execute_command = f"docker-compose -f {get_remote_server_dir(server['container_name'])}/docker-compose.yml kill && docker-compose -f {get_remote_server_dir(server['container_name'])}/docker-compose.yml rm -f"
                            app.logger.info(f"Deleting frozen server '{server['name']}' from remote server.")
                            stdout_str, stderr_str, exit_status = execute_ssh_command(execute_command, ssh_client)
                            if exit_status != 0:
                                app.logger.error(f"Failed to delete server '{server['name']}': {stderr_str}")
                                continue
                            servers_to_remove.append(server)
                            app.logger.info(f"Server '{server['name']}' deleted after being frozen for over 3 days.")
                        finally:
                            ssh_client.close()
            for server in servers_to_remove:
                user['servers'].remove(server)
        save_db(db)
    except Exception as e:
        app.logger.error(f"Error during frozen server check: {e}")
        app.logger.error(traceback.format_exc())

def initialize_scheduler():
    scheduler = BackgroundScheduler()
    scheduler.add_job(func=monthly_billing_check, trigger="interval", days=30)
    scheduler.add_job(func=check_frozen_servers, trigger="interval", hours=24)
    scheduler.start()
    app.logger.info("Scheduler started for billing and frozen server checks.")

@app.route('/api/servers/<int:server_id>', methods=['GET'])
@jwt_required()
def get_server(server_id):
    try:
        current_user = get_jwt_identity()
        db = load_db()
        user_data = db['users'].get(current_user)

        if not user_data:
            app.logger.warning(f'User {current_user} not found when accessing /api/servers/{server_id}')
            return jsonify({'error': 'User not found'}), 404

        server = next((s for s in user_data['servers'] if s['id'] == server_id), None)
        if not server:
            app.logger.warning(f'Server with ID {server_id} not found for user {current_user}')
            return jsonify({'error': 'Server not found'}), 404

        plan = server.get('plan', {})
        plan_key = plan.get('key')
        plan_name = plan.get('name', 'Unknown')

        if not plan_key:
            app.logger.error(f"Server {server_id} has a plan without a 'key'. Cannot process request.")
            return jsonify({'error': "Server's plan information is incomplete. Please contact support."}), 500

        formatted_server = {
            'id': server['id'],
            'name': server['name'],
            'plan': {
                'key': plan_key,
                'name': plan_name,
                'cpu': plan.get('cpu'),
                'ram': plan.get('ram'),
                'disk': plan.get('disk'),
                'price': plan.get('price')
            },
            'os': server['os'],
            'status': server['status'],
            'ip': server['ip'],
            'created_at': server['created_at'],
            'container_name': server['container_name'],
            'ports': server['ports'],
            'vnc_address': server.get('vnc_address'),
            'vnc_password': server.get('vnc_password')
        }

        return jsonify(formatted_server), 200

    except Exception as e:
        app.logger.error(f'Error in get_server endpoint: {str(e)}')
        app.logger.error(traceback.format_exc())
        return jsonify({'error': 'An internal server error occurred'}), 500

@app.route('/api/servers/<int:server_id>/toggle', methods=['POST'])
@jwt_required()
def toggle_server(server_id):
    try:
        current_user = get_jwt_identity()
        db = load_db()

        user_data = db['users'].get(current_user)
        if not user_data:
            return jsonify({'error': 'User not found'}), 404

        server = next((s for s in user_data['servers'] if s['id'] == server_id), None)
        if not server:
            return jsonify({'error': 'Server not found'}), 404

        container_name = server.get('container_name')
        if not container_name:
            app.logger.error('Container name not found for this server')
            return jsonify({'error': 'Container name not found for this server. Please contact support.'}), 400

        server_dir = get_remote_server_dir(container_name)
        if server['status'] == 'active':
            cmd = f"docker-compose -f {server_dir}/docker-compose.yml stop"
            new_status = 'frozen'
        else:
            cmd = f"docker-compose -f {server_dir}/docker-compose.yml start"
            new_status = 'active'

        ssh_client = connect_via_ssh()
        if not ssh_client:
            return jsonify({'error': 'Failed to establish SSH connection'}), 500

        try:
            stdout_str, stderr_str, exit_status = execute_ssh_command(cmd, ssh_client)
            if exit_status != 0:
                app.logger.error(f'SSH command error: {stderr_str}')
                return jsonify({'error': f'Failed to toggle server status: {stderr_str}'}), 500

            server['status'] = new_status
            save_db(db)
            log_activity(current_user, f'toggle_server_{server_id}', request.headers.get('User-Agent', ''))
            return jsonify({'message': f"Server status changed to {server['status']}"}), 200

        except Exception as e:
            app.logger.error(f'Error during SSH operation: {e}')
            return jsonify({'error': f'Failed to toggle server status: {str(e)}'}), 500
        finally:
            ssh_client.close()

    except Exception as e:
        app.logger.error(f'Unhandled exception in toggle_server: {str(e)}')
        app.logger.error(traceback.format_exc())
        return jsonify({'error': 'An internal server error occurred'}), 500

@app.route('/api/servers/<int:server_id>', methods=['DELETE'])
@jwt_required()
def delete_server(server_id):
    try:
        current_user = get_jwt_identity()
        db = load_db()
        user_data = db['users'].get(current_user)

        if not user_data:
            return jsonify({'error': 'User not found'}), 404

        server = next((s for s in user_data['servers'] if s['id'] == server_id), None)
        if not server:
            return jsonify({'error': 'Server not found'}), 404

        container_name = server.get('container_name')
        if not container_name:
            return jsonify({'error': 'Container name not found for this server'}), 400

        server_dir = get_remote_server_dir(container_name)
        # Добавляем команды docker volume prune -f и docker system prune -f
        commands = [
            f"docker-compose -f {server_dir}/docker-compose.yml down",
            f"rm -rf {server_dir}",
            "docker volume prune -f",  # Удаление неиспользуемых томов
            "docker system prune -f"    # Дополнительная очистка Docker
        ]
        full_command = ' && '.join(commands)

        ssh_client = connect_via_ssh()
        if not ssh_client:
            app.logger.error('Failed to establish SSH connection for deleting server.')
            return jsonify({'error': 'Failed to establish SSH connection'}), 500

        try:
            stdout_str, stderr_str, exit_status = execute_ssh_command(full_command, ssh_client)

            if exit_status != 0:
                app.logger.error(f'SSH command error: {stderr_str}')
                return jsonify({'error': f'Failed to delete server: {stderr_str}'}), 500

            user_data['servers'].remove(server)
            save_db(db)
            log_activity(current_user, f'delete_server_{server_id}', request.headers.get('User-Agent', ''))
            app.logger.info(f"Server {server_id} deleted successfully for user {current_user}.")
            return jsonify({'message': 'Server deleted successfully'}), 200

        except Exception as e:
            app.logger.error(f'Error during SSH operation: {e}')
            return jsonify({'error': f'Failed to delete server: {str(e)}'}), 500
        finally:
            ssh_client.close()

    except Exception as e:
        app.logger.error(f'Unhandled exception in delete_server: {str(e)}')
        app.logger.error(traceback.format_exc())
        return jsonify({'error': 'An internal server error occurred'}), 500

@app.route('/api/servers/<int:server_id>', methods=['PUT'])
@jwt_required()
def update_server(server_id):
    try:
        current_user = get_jwt_identity()
        db = load_db()
        user_data = db['users'].get(current_user)

        if not user_data:
            return jsonify({'error': 'User not found'}), 404

        server = next((s for s in user_data['servers'] if s['id'] == server_id), None)
        if not server:
            return jsonify({'error': 'Server not found'}), 404

        data = request.get_json()
        if not data:
            return jsonify({'error': 'No data provided'}), 400

        new_name = data.get('name')
        new_os = data.get('os')

        if new_name:
            server['name'] = new_name
            app.logger.info(f"Server ID {server_id} name updated to {new_name} by user {current_user}")

        if new_os:
            if new_os not in OS_OPTIONS:
                app.logger.error(f"Invalid operating system selected: {new_os}")
                return jsonify({'error': 'Invalid operating system selected'}), 400
                
            container_name = server.get('container_name')
            server_dir = get_remote_server_dir(container_name)
            docker_compose_path = posixpath.join(server_dir, 'docker-compose.yml')

            docker_compose_content = create_docker_compose_content(
                container_name, new_os, server['plan'],
                server.get('username', 'admin'), server.get('password', generate_password()),
                server.get('vnc_password', generate_password()),
                server['ports']['8006/tcp'], server['ports']['3389/tcp'],
                server['ports']['3389/udp'], server['ports']['5900/tcp']
            )

            ssh_client = connect_via_ssh()
            if not ssh_client:
                app.logger.error('Failed to establish SSH connection for updating server.')
                return jsonify({'error': 'Failed to establish SSH connection'}), 500

            try:
                docker_compose_command = f"""cat <<EOF > {docker_compose_path}
{docker_compose_content}
EOF
"""
                app.logger.info(f"Updating docker-compose.yml on remote server for {container_name}")
                stdout_str, stderr_str, exit_status = execute_ssh_command(docker_compose_command, ssh_client)
                if exit_status != 0:
                    app.logger.error(f"Error updating docker-compose.yml on remote server: {stderr_str}")
                    raise Exception(f"Failed to update docker-compose.yml: {stderr_str}")
                app.logger.info(f"docker-compose.yml updated successfully at {docker_compose_path}")

                restart_command = f"docker-compose -f {docker_compose_path} up -d"
                app.logger.info(f"Restarting server {container_name} to apply OS changes")
                stdout_str, stderr_str, exit_status = execute_ssh_command(restart_command, ssh_client)
                if exit_status != 0:
                    app.logger.error(f"Error restarting server on remote: {stderr_str}")
                    raise Exception(f"Failed to restart server: {stderr_str}")
                app.logger.info(f"Server {container_name} restarted successfully with new OS")

                server['os'] = OS_OPTIONS[new_os]

            except Exception as e:
                app.logger.error(f'Error during SSH operation: {e}')
                return jsonify({'error': f'Failed to update server: {str(e)}'}), 500
            finally:
                ssh_client.close()

        save_db(db)
        log_activity(current_user, f'update_server_{server_id}', request.headers.get('User-Agent', ''))
        return jsonify({'message': 'Server updated successfully', 'server': server}), 200
    except Exception as e:
        app.logger.error(f'Error in update_server endpoint: {e}')
        app.logger.error(traceback.format_exc())
        return jsonify({'error': 'An internal server error occurred'}), 500

@app.route('/api/userinfo', methods=['GET', 'PUT'])
@jwt_required()
def userinfo():
    try:
        current_user = get_jwt_identity()
        db = load_db()
        user_data = db['users'].get(current_user)

        if not user_data:
            app.logger.warning(f'User {current_user} not found when accessing /api/userinfo')
            return jsonify({'error': 'User not found'}), 404

        if request.method == 'GET':
            return jsonify({'username': current_user, 'balance': user_data.get('balance', 0)}), 200

        elif request.method == 'PUT':
            data = request.get_json()
            if not data:
                return jsonify({'error': 'No data provided'}), 400

            current_password = data.get('current_password')
            new_username = data.get('new_username')
            new_password = data.get('new_password')

            if not current_password:
                return jsonify({'error': 'Current password is required'}), 400

            if not pbkdf2_sha256.verify(current_password, user_data['password']):
                return jsonify({'error': 'Current password is incorrect'}), 401

            if new_username:
                if not is_valid_username(new_username):
                    return jsonify({'error': 'Invalid new username. Please use only letters, numbers, and underscores. Length between 3-30 characters.'}), 400
                if new_username in db['users']:
                    return jsonify({'error': 'Username already taken'}), 400
                db['users'][new_username] = db['users'].pop(current_user)
                current_user = new_username
                app.logger.info(f"User changed username to {new_username}")

            if new_password:
                db['users'][current_user]['password'] = pbkdf2_sha256.hash(new_password)
                app.logger.info(f"User {current_user} updated their password")

            save_db(db)
            log_activity(current_user, 'update_userinfo', request.headers.get('User-Agent', ''))
            return jsonify({'message': 'User information updated successfully', 'username': current_user}), 200

    except Exception as e:
        app.logger.error(f'Error in userinfo endpoint: {e}')
        app.logger.error(traceback.format_exc())
        return jsonify({'error': 'An internal server error occurred'}), 500

@app.route('/api/tickets', methods=['GET', 'POST'])
@jwt_required()
def tickets():
    try:
        current_user = get_jwt_identity()
        db = load_db()

        if request.method == 'GET':
            user_data = db['users'].get(current_user)
            if not user_data:
                return jsonify({'error': 'User not found'}), 404

            return jsonify(user_data.get('tickets', [])), 200

        elif request.method == 'POST':
            data = request.get_json()
            if not data or 'title' not in data or 'description' not in data:
                return jsonify({'error': 'Invalid request data'}), 400

            user_data = db['users'].get(current_user)
            if not user_data:
                return jsonify({'error': 'User not found'}), 404

            new_ticket = {
                'id': len(user_data['tickets']) + 1,
                'title': data['title'],
                'description': data.get('description', ''),
                'status': 'open',
                'created_at': datetime.now().isoformat(),
                'messages': []
            }

            user_data['tickets'].append(new_ticket)
            save_db(db)
            log_activity(current_user, 'create_ticket', request.headers.get('User-Agent', ''))
            return jsonify(new_ticket), 201

    except Exception as e:
        app.logger.error(f'Error in tickets endpoint: {e}')
        app.logger.error(traceback.format_exc())
        return jsonify({'error': 'An internal server error occurred'}), 500

@app.route('/api/tickets/<int:ticket_id>', methods=['GET'])
@jwt_required()
def get_ticket(ticket_id):
    try:
        current_user = get_jwt_identity()
        db = load_db()
        user_data = db['users'].get(current_user)

        if not user_data:
            return jsonify({'error': 'User not found'}), 404

        ticket = next((t for t in user_data['tickets'] if t['id'] == ticket_id), None)
        if not ticket:
            return jsonify({'error': 'Ticket not found'}), 404

        return jsonify(ticket), 200

    except Exception as e:
        app.logger.error(f'Error in get_ticket endpoint: {e}')
        app.logger.error(traceback.format_exc())
        return jsonify({'error': 'An internal server error occurred'}), 500

@app.route('/api/tickets/<int:ticket_id>/reply', methods=['POST'])
@jwt_required()
def reply_ticket(ticket_id):
    try:
        current_user = get_jwt_identity()
        db = load_db()

        user_data = db['users'].get(current_user)
        if not user_data:
            return jsonify({'error': 'User not found'}), 404

        ticket = next((t for t in user_data['tickets'] if t['id'] == ticket_id), None)
        if not ticket:
            return jsonify({'error': 'Ticket not found'}), 404

        data = request.get_json()
        if not data or 'message' not in data:
            return jsonify({'error': 'Message is required'}), 400

        message = {
            'content': data['message'],
            'sender': current_user,
            'timestamp': datetime.now().isoformat()
        }

        ticket['messages'].append(message)
        save_db(db)
        log_activity(current_user, f'reply_ticket_{ticket_id}', request.headers.get('User-Agent', ''))
        return jsonify(message), 201

    except Exception as e:
        app.logger.error(f'Error in reply_ticket endpoint: {e}')
        app.logger.error(traceback.format_exc())
        return jsonify({'error': 'An internal server error occurred'}), 500

# Admin Routes

@app.route('/api/admin/users', methods=['GET'])
@admin_required
def get_all_users():
    try:
        db = load_db()
        users = [
            {
                'username': username,
                'balance': user.get('balance', 0),
                'servers_count': len(user.get('servers', [])),
                'tickets_count': len(user.get('tickets', [])),
                'created_at': user.get('created_at'),
                'role': user.get('role', 'user')
            }
            for username, user in db['users'].items()
        ]
        app.logger.info(f'Admin accessed all users list.')
        return jsonify(users), 200
    except Exception as e:
        app.logger.error(f'Error in get_all_users: {e}')
        app.logger.error(traceback.format_exc())
        return jsonify({'error': 'An internal server error occurred'}), 500

@app.route('/api/admin/users/<string:username>', methods=['GET'])
@admin_required
def get_user_details(username):
    try:
        db = load_db()
        user = db['users'].get(username)
        if not user:
            app.logger.warning(f'Admin tried to access non-existent user: {username}')
            return jsonify({'error': 'User not found'}), 404

        user_details = {
            'username': username,
            'balance': user.get('balance', 0),
            'servers': user.get('servers', []),
            'tickets': user.get('tickets', []),
            'created_at': user.get('created_at'),
            'role': user.get('role', 'user')
        }

        app.logger.info(f'Admin accessed details for user: {username}')
        return jsonify(user_details), 200
    except Exception as e:
        app.logger.error(f'Error in get_user_details: {e}')
        app.logger.error(traceback.format_exc())
        return jsonify({'error': 'An internal server error occurred'}), 500

@app.route('/api/admin/users/<string:username>', methods=['DELETE'])
@admin_required
def delete_user(username):
    try:
        db = load_db()
        user = db['users'].get(username)
        if not user:
            app.logger.warning(f'Admin tried to delete non-existent user: {username}')
            return jsonify({'error': 'User not found'}), 404

        # Delete all servers associated with the user
        for server in user.get('servers', []):
            container_name = server.get('container_name')
            server_dir = get_remote_server_dir(container_name)
            commands = [
                f"docker-compose -f {server_dir}/docker-compose.yml down",
                f"rm -rf {server_dir}",
                "docker volume prune -f",
                "docker system prune -f"
            ]
            full_command = ' && '.join(commands)

            ssh_client = connect_via_ssh()
            if ssh_client:
                try:
                    stdout_str, stderr_str, exit_status = execute_ssh_command(full_command, ssh_client)
                    if exit_status != 0:
                        app.logger.error(f'Failed to delete server {server["name"]} for user {username}: {stderr_str}')
                except Exception as e:
                    app.logger.error(f'Error deleting server {server["name"]} for user {username}: {e}')
                finally:
                    ssh_client.close()

        del db['users'][username]
        save_db(db)
        log_activity(current_user, f'delete_user_{username}', request.headers.get('User-Agent', ''))
        app.logger.info(f'Admin deleted user: {username}')
        return jsonify({'message': f'User {username} deleted successfully'}), 200
    except Exception as e:
        app.logger.error(f'Error in delete_user: {e}')
        app.logger.error(traceback.format_exc())
        return jsonify({'error': 'An internal server error occurred'}), 500

@app.route('/api/admin/logs', methods=['GET'])
@admin_required
def get_logs():
    try:
        log_file_path = os.path.join(LOGS_DIR, 'app.log')
        if not os.path.exists(log_file_path):
            return jsonify({'logs': []}), 200

        with open(log_file_path, 'r') as log_file:
            logs = log_file.readlines()
        return jsonify({'logs': logs}), 200
    except Exception as e:
        app.logger.error(f'Error in get_logs: {e}')
        app.logger.error(traceback.format_exc())
        return jsonify({'error': 'Unable to retrieve logs'}), 500

@app.route('/api/admin/tickets', methods=['GET'])
@admin_required
def admin_get_all_tickets():
    try:
        db = load_db()
        all_tickets = []
        for username, user in db['users'].items():
            for ticket in user.get('tickets', []):
                ticket_info = ticket.copy()
                ticket_info['username'] = username
                all_tickets.append(ticket_info)
        return jsonify(all_tickets), 200
    except Exception as e:
        app.logger.error(f'Error in admin_get_all_tickets: {e}')
        app.logger.error(traceback.format_exc())
        return jsonify({'error': 'An internal server error occurred'}), 500
    
@app.route('/api/admin/tickets/<string:username>/<int:ticket_id>/reply', methods=['POST'])
@admin_required
def admin_reply_ticket(username, ticket_id):
    try:
        db = load_db()
        user_data = db['users'].get(username)
        if not user_data:
            return jsonify({'error': 'User not found'}), 404

        ticket = next((t for t in user_data['tickets'] if t['id'] == ticket_id), None)
        if not ticket:
            return jsonify({'error': 'Ticket not found'}), 404

        data = request.get_json()
        if not data or 'message' not in data:
            return jsonify({'error': 'Message is required'}), 400

        message = {
            'content': data['message'],
            'sender': 'admin',  # Indicate that the admin is replying
            'timestamp': datetime.now().isoformat()
        }

        ticket['messages'].append(message)
        save_db(db)
        return jsonify(message), 201

    except Exception as e:
        app.logger.error(f'Error in admin_reply_ticket: {e}')
        app.logger.error(traceback.format_exc())
        return jsonify({'error': 'An internal server error occurred'}), 500
    
@app.route('/api/admin/users/<string:username>/tickets/<int:ticket_id>', methods=['GET'])
@admin_required
def admin_get_ticket(username, ticket_id):
    try:
        db = load_db()
        user_data = db['users'].get(username)
        if not user_data:
            return jsonify({'error': 'User not found'}), 404

        ticket = next((t for t in user_data['tickets'] if t['id'] == ticket_id), None)
        if not ticket:
            return jsonify({'error': 'Ticket not found'}), 404

        return jsonify(ticket), 200
    except Exception as e:
        app.logger.error(f'Error in admin_get_ticket: {e}')
        app.logger.error(traceback.format_exc())
        return jsonify({'error': 'An internal server error occurred'}), 500

@app.route('/api/admin/servers', methods=['GET'])
@admin_required
def get_all_servers():
    try:
        db = load_db()
        servers = []
        for username, user in db['users'].items():
            for server in user.get('servers', []):
                server_info = server.copy()
                server_info['owner'] = username
                servers.append(server_info)
        app.logger.info('Admin accessed all servers list.')
        return jsonify(servers), 200
    except Exception as e:
        app.logger.error(f'Error in get_all_servers: {e}')
        app.logger.error(traceback.format_exc())
        return jsonify({'error': 'An internal server error occurred'}), 500

@app.route('/api/admin/servers/<int:server_id>/toggle', methods=['POST'])
@admin_required
def admin_toggle_server(server_id):
    try:
        db = load_db()
        target_server = None
        target_user = None

        # Find the server and its owner
        for username, user in db['users'].items():
            server = next((s for s in user.get('servers', []) if s['id'] == server_id), None)
            if server:
                target_server = server
                target_user = user
                break

        if not target_server:
            app.logger.warning(f'Admin tried to toggle non-existent server ID: {server_id}')
            return jsonify({'error': 'Server not found'}), 404

        container_name = target_server.get('container_name')
        if not container_name:
            app.logger.error('Container name not found for the server')
            return jsonify({'error': 'Container name not found for this server.'}), 400

        server_dir = get_remote_server_dir(container_name)
        if target_server['status'] == 'active':
            cmd = f"docker-compose -f {server_dir}/docker-compose.yml stop"
            new_status = 'frozen'
        else:
            cmd = f"docker-compose -f {server_dir}/docker-compose.yml start"
            new_status = 'active'

        ssh_client = connect_via_ssh()
        if not ssh_client:
            return jsonify({'error': 'Failed to establish SSH connection'}), 500

        try:
            stdout_str, stderr_str, exit_status = execute_ssh_command(cmd, ssh_client)
            if exit_status != 0:
                app.logger.error(f'SSH command error: {stderr_str}')
                return jsonify({'error': f'Failed to toggle server status: {stderr_str}'}), 500

            target_server['status'] = new_status
            save_db(db)
            log_activity(target_user['username'], f'admin_toggle_server_{server_id}', request.headers.get('User-Agent', ''))
            app.logger.info(f'Admin toggled server ID {server_id} to {new_status}')
            return jsonify({'message': f"Server status changed to {new_status}"}), 200

        except Exception as e:
            app.logger.error(f'Error during SSH operation: {e}')
            return jsonify({'error': f'Failed to toggle server status: {str(e)}'}), 500
        finally:
            ssh_client.close()
    except Exception as e:
        app.logger.error(f'Unhandled exception in admin_toggle_server: {str(e)}')
        app.logger.error(traceback.format_exc())
        return jsonify({'error': 'An internal server error occurred'}), 500

# Scheduler Initialization
initialize_scheduler()

if __name__ == '__main__':
    setup_logging()
    app.run(host='0.0.0.0', port=5000)



<!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="UTF-8">
    <title>Управление серверами</title>
    <link rel="stylesheet" href="/static/styles.css">
    <link rel="icon" href="/static/favicon.ico" type="image/x-icon">
</head>
<body>
    <div class="container">
        <!-- Auth forms container -->
        <div id="auth-container">
            <!-- Login Form -->
            <div id="login-form" class="form-container">
                <h2 align="center">Вход в систему</h2>
                <form id="login">
                    <input type="text" id="login-username" placeholder="Имя пользователя" required>
                    <input type="password" id="login-password" placeholder="Пароль" required>
                    <button type="submit" class="btn primary">Войти</button>
                    <p>Нет аккаунта? <a href="#" id="show-register">Зарегистрироваться</a></p>
                </form>
            </div>

            <!-- Registration Form -->
            <div id="register-form" class="form-container hidden">
                <h2 align="center">Регистрация</h2>
                <form id="register">
                    <input type="text" id="reg-username" placeholder="Имя пользователя" required>
                    <input type="password" id="reg-password" placeholder="Пароль" required>
                    <button type="submit" class="btn primary">Зарегистрироваться</button>
                    <p>Уже есть аккаунт? <a href="#" id="show-login">Войти</a></p>
                </form>
            </div>
        </div>

        <!-- User panel container -->
        <div id="main-content" class="hidden">
            <header>
                <div id="user-info">
                    <span id="username"></span>
                    <span id="balance"></span>
                </div>
                <button id="logout-btn" class="btn primary">Выйти</button>
            </header>

            <nav>
                <button class="tab-btn active" data-tab="servers">Серверы</button>
                <button class="tab-btn" data-tab="support">Поддержка</button>
                <button class="tab-btn" data-tab="settings">Настройки</button>
            </nav>

            <!-- Servers Section -->
            <section id="servers" class="tab-content active">
                <h2>Мои серверы</h2>
                <button class="btn primary" id="open-buy-server">Создать сервер</button>
                <div id="servers-list" class="grid"></div>
            </section>

            <!-- Support Section -->
            <section id="support" class="tab-content hidden">
                <h2>Поддержка</h2>
                <div class="support-container">
                    <!-- Support form -->
                    <form id="ticket-form">
                        <input type="text" id="ticket-title" placeholder="Тема" required>
                        <textarea id="ticket-description" placeholder="Описание проблемы" required></textarea>
                        <button type="submit" class="btn primary">Отправить</button>
                    </form>
                    <!-- Tickets list -->
                    <div id="tickets-list"></div>
                </div>
            </section>

            <!-- Settings Section -->
            <section id="settings" class="tab-content hidden">
                <h2>Настройки</h2>
                <div class="settings-container">
                    <form id="settings-form-main">
                        <div class="form-group">
                            <label for="new-username-main">Новое имя пользователя</label>
                            <input type="text" id="new-username-main" placeholder="Имя пользователя">
                        </div>
                        <div class="form-group">
                            <label for="current-password-main">Текущий пароль</label>
                            <input type="password" id="current-password-main" placeholder="Текущий пароль" required>
                        </div>
                        <div class="form-group">
                            <label for="new-password-main">Новый пароль</label>
                            <input type="password" id="new-password-main" placeholder="Новый пароль">
                        </div>
                        <button type="submit" class="btn primary">Сохранить</button>
                    </form>
                </div>
            </section>
        </div>
    </div>

    <!-- Notification Container -->
    <div id="notification-container"></div>

    <!-- Buy Server Modal -->
    <div id="buy-server-modal" class="modal hidden">
        <div class="modal-content">
            <div class="modal-header">
                <h3>Создать сервер</h3>
                <button class="close-modal">&times;</button>
            </div>
            <div class="modal-body">
                <form id="buy-server-form">
                    <div class="form-group">
                        <label for="server-name">Имя сервера</label>
                        <input type="text" id="server-name" placeholder="Имя сервера" required>
                    </div>
                    <div class="form-group">
                        <label for="server-os">Операционная система</label>
                        <select id="server-os" required>
                            <option value="" disabled selected>Выберите ОС</option>
                            <option value="win2020">Windows Server 2020</option>
                            <option value="win2022">Windows Server 2022</option>
                            <option value="win2025">Windows Server 2025</option>
                            <option value="win10">Windows 10</option>
                            <option value="win11">Windows 11</option>
                        </select>
                    </div>
                    <div class="form-group">
                        <label>Выберите тарифный план</label>
                        <div class="plan-selection">
                            <button type="button" class="buy-server" data-plan="basic">Базовый</button>
                            <button type="button" class="buy-server" data-plan="advanced">Продвинутый</button>
                            <button type="button" class="buy-server" data-plan="premium">Премиум</button>
                        </div>
                    </div>
                    <button type="submit" class="btn primary">Создать</button>
                </form>
            </div>
        </div>
    </div>

    <!-- Ticket Detail Modal -->
    <div id="ticket-modal" class="modal hidden">
        <div class="modal-content">
            <div class="modal-header">
                <h3 id="modal-ticket-title">Тема Тикета</h3>
                <button class="close-modal">&times;</button>
            </div>
            <div class="modal-body">
                <p id="modal-ticket-description">Описание</p>
                <div id="modal-ticket-messages"></div>
                <form id="reply-form">
                    <textarea id="reply-message" placeholder="Ваш ответ" required></textarea>
                    <button type="submit" class="btn primary">Отправить ответ</button>
                </form>
            </div>
        </div>
    </div>

    <!-- Server Details Modal -->
    <div id="server-details-modal" class="modal hidden">
        <div class="modal-content">
            <div class="modal-header">
                <h2>Детали сервера</h2>
                <button class="close-modal">&times;</button>
            </div>
            <div class="modal-body">
                <p><strong>Имя:</strong> <span id="modal-server-name"></span></p>
                <p><strong>IP:</strong> <span id="modal-server-ip"></span></p>
                <p><strong>VNC Адрес:</strong> <span id="modal-server-vnc-address"></span></p>
                <p><strong>VNC Пароль:</strong> <span id="modal-server-vnc-password" class="password-field">********</span></p>
                <p><strong>План:</strong> <span id="modal-server-plan"></span></p>
                <p><strong>ОС:</strong> <span id="modal-server-os"></span></p>
                <p><strong>Статус:</strong> <span id="modal-server-status"></span></p>
                <div id="server-ports"></div>
            </div>
        </div>
    </div>

    <script src="/static/script.js"></script>
</body>
</html>



<!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="UTF-8">
    <title>Администраторская панель</title>
    <link rel="stylesheet" href="/static/styles.css">
</head>
<body>
    <div class="container">
        <header>
            <div id="admin-info">
                <h1>Администраторская панель</h1>
                <button id="logout-btn" class="btn primary">Выйти</button>
            </div>
        </header>
        <nav>
            <button class="tab-btn active" data-tab="users">Пользователи</button>
            <button class="tab-btn" data-tab="servers">Серверы</button>
            <button class="tab-btn" data-tab="tickets">Тикеты</button>
            <button class="tab-btn" data-tab="logs">Логи</button>
        </nav>
        <!-- Users Section -->
        <section id="users" class="tab-content active">
            <h2>Управление пользователями</h2>
            <div id="users-list"></div>
        </section>
        <!-- Servers Section -->
        <section id="servers" class="tab-content hidden">
            <h2>Управление серверами</h2>
            <div id="servers-list"></div>
        </section>
        <!-- Tickets Section -->
        <section id="tickets" class="tab-content hidden">
            <h2>Поддержка</h2>
            <div id="tickets-list"></div>
        </section>
        <!-- Logs Section -->
        <section id="logs" class="tab-content hidden">
            <h2>Просмотр логов</h2>
            <pre id="logs-content"></pre>
        </section>
    </div>
    <!-- Ticket Detail Modal -->
    <div id="ticket-modal" class="modal hidden">
        <div class="modal-content">
            <div class="modal-header">
                <h3 id="modal-ticket-title">Тема Тикета</h3>
                <button class="close-modal" id="close-ticket-modal">&times;</button>
            </div>
            <div class="modal-body">
                <p><strong>Пользователь:</strong> <span id="modal-ticket-username"></span></p>
                <p id="modal-ticket-description">Описание</p>
                <div id="modal-ticket-messages"></div>
                <form id="reply-form">
                    <textarea id="reply-message" placeholder="Ваш ответ" required></textarea>
                    <button type="submit" class="btn primary">Отправить ответ</button>
                </form>
            </div>
        </div>
    </div>
    <!-- Notification Container -->
    <div id="notification-container"></div>
    <!-- Include admin.js -->
    <script src="/static/admin.js"></script>
</body>
</html>



<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Page Not Found</title>
    <link rel="stylesheet" href="{{ url_for('static', filename='styles.css') }}">
</head>
<body>
    <div class="container">
        <h1>404 - Page Not Found</h1>
        <p>Sorry, the page you're looking for doesn't exist.</p>
        <a href="/">Go to Home</a>
    </div>
</body>
</html>



document.addEventListener('DOMContentLoaded', () => {
    const API_URL = '/api';

    function getAuthHeaders() {
        const token = localStorage.getItem('authToken');
        if (!token) {
            window.location.href = '/';
            return {};
        }
        return {
            'Content-Type': 'application/json',
            'Authorization': `Bearer ${token}`
        };
    }

    function isAuthenticated() {
        return localStorage.getItem('authToken') !== null;
    }

    function logout() {
        localStorage.removeItem('authToken');
        localStorage.removeItem('username');
        localStorage.removeItem('role');
        window.location.href = '/';
    }

    function showNotification(message, type = 'error') {
        // Implement notification similar to script.js
        const container = document.getElementById('notification-container');
        const notification = document.createElement('div');
        notification.className = `notification ${type}`;
        notification.innerHTML = `
            <span>${message}</span>
            <button class="close-notification">&times;</button>
        `;
        container.appendChild(notification);

        setTimeout(() => {
            notification.classList.add('show');
        }, 100);

        setTimeout(() => {
            notification.classList.remove('show');
            setTimeout(() => {
                notification.remove();
            }, 500);
        }, 5000);

        notification.querySelector('.close-notification').addEventListener('click', () => {
            notification.classList.remove('show');
            setTimeout(() => {
                notification.remove();
            }, 500);
        });
    }

    // Load and display users
    async function loadUsers() {
        try {
            const response = await fetch(`${API_URL}/admin/users`, {
                method: 'GET',
                headers: getAuthHeaders()
            });
            if (!response.ok) {
                throw new Error('Не удалось загрузить пользователей.');
            }
            const users = await response.json();
            displayUsers(users);
        } catch (error) {
            console.error(error);
            showNotification(error.message, 'error');
        }
    }

    function displayUsers(users) {
        const usersList = document.getElementById('users-list');
        usersList.innerHTML = '';
        users.forEach(user => {
            const userDiv = document.createElement('div');
            userDiv.className = 'user-card';
            userDiv.innerHTML = `
                <p><strong>Имя пользователя:</strong> ${user.username}</p>
                <p><strong>Баланс:</strong> ${user.balance}</p>
                <p><strong>Роль:</strong> ${user.role}</p>
                <p><strong>Серверов:</strong> ${user.servers_count}</p>
                <p><strong>Тикетов:</strong> ${user.tickets_count}</p>
                <button class="btn danger delete-user" data-username="${user.username}">Удалить</button>
            `;
            usersList.appendChild(userDiv);
        });

        document.querySelectorAll('.delete-user').forEach(button => {
            button.addEventListener('click', () => {
                const username = button.getAttribute('data-username');
                if (confirm(`Удалить пользователя ${username}?`)) {
                    deleteUser(username);
                }
            });
        });
    }

    async function deleteUser(username) {
        try {
            const response = await fetch(`${API_URL}/admin/users/${username}`, {
                method: 'DELETE',
                headers: getAuthHeaders()
            });
            if (!response.ok) {
                throw new Error('Не удалось удалить пользователя.');
            }
            showNotification(`Пользователь ${username} удален.`, 'success');
            loadUsers();
        } catch (error) {
            console.error(error);
            showNotification(error.message, 'error');
        }
    }

    // Load and display servers
    async function loadServers() {
        try {
            const response = await fetch(`${API_URL}/admin/servers`, {
                method: 'GET',
                headers: getAuthHeaders()
            });
            if (!response.ok) {
                throw new Error('Не удалось загрузить серверы.');
            }
            const servers = await response.json();
            displayServers(servers);
        } catch (error) {
            console.error(error);
            showNotification(error.message, 'error');
        }
    }

    function displayServers(servers) {
        const serversList = document.getElementById('servers-list');
        serversList.innerHTML = '';
        servers.forEach(server => {
            const serverDiv = document.createElement('div');
            serverDiv.className = 'server-card';
            serverDiv.innerHTML = `
                <p><strong>Имя сервера:</strong> ${server.name}</p>
                <p><strong>Владелец:</strong> ${server.owner}</p>
                <p><strong>План:</strong> ${server.plan.name}</p>
                <p><strong>Статус:</strong> ${server.status}</p>
                <button class="btn danger toggle-server" data-server-id="${server.id}">${server.status === 'active' ? 'Остановить' : 'Запустить'}</button>
            `;
            serversList.appendChild(serverDiv);
        });

        document.querySelectorAll('.toggle-server').forEach(button => {
            button.addEventListener('click', () => {
                const serverId = button.getAttribute('data-server-id');
                adminToggleServer(serverId);
            });
        });
    }

    async function adminToggleServer(serverId) {
        try {
            const response = await fetch(`${API_URL}/admin/servers/${serverId}/toggle`, {
                method: 'POST',
                headers: getAuthHeaders()
            });
            if (!response.ok) {
                throw new Error('Не удалось изменить статус сервера.');
            }
            const result = await response.json();
            showNotification(result.message, 'success');
            loadServers();
        } catch (error) {
            console.error(error);
            showNotification(error.message, 'error');
        }
    }

    // Load and display tickets
    async function loadTickets() {
        try {
            const response = await fetch(`${API_URL}/admin/tickets`, {
                method: 'GET',
                headers: getAuthHeaders()
            });
            if (!response.ok) {
                throw new Error('Не удалось загрузить тикеты.');
            }
            const tickets = await response.json();
            displayTickets(tickets);
        } catch (error) {
            console.error(error);
            showNotification(error.message, 'error');
        }
    }

    function displayTickets(tickets) {
        const ticketsList = document.getElementById('tickets-list');
        ticketsList.innerHTML = '';
        tickets.forEach(ticket => {
            const ticketDiv = document.createElement('div');
            ticketDiv.className = 'ticket-card';
            ticketDiv.innerHTML = `
                <div class="ticket-header">
                    <h3>${ticket.title}</h3>
                    <span class="ticket-status status-${ticket.status}">${ticket.status}</span>
                </div>
                <p><strong>Пользователь:</strong> ${ticket.username}</p>
                <p>${ticket.description}</p>
                <small>Создан: ${new Date(ticket.created_at).toLocaleString()}</small>
                <button class="btn primary view-ticket" data-ticket-id="${ticket.id}" data-username="${ticket.username}">Просмотреть</button>
            `;
            ticketsList.appendChild(ticketDiv);
        });

        document.querySelectorAll('.view-ticket').forEach(button => {
            button.addEventListener('click', () => {
                const ticketId = button.getAttribute('data-ticket-id');
                const username = button.getAttribute('data-username');
                openTicketModal(ticketId, username);
            });
        });
    }

    // Load and display logs
    async function loadLogs() {
        try {
            const response = await fetch(`${API_URL}/admin/logs`, {
                method: 'GET',
                headers: getAuthHeaders()
            });
            if (!response.ok) {
                throw new Error('Не удалось загрузить логи.');
            }
            const data = await response.json();
            const logsContent = document.getElementById('logs-content');
            logsContent.textContent = data.logs.join('\n');
        } catch (error) {
            console.error(error);
            showNotification(error.message, 'error');
        }
    }

    // Tab navigation
    document.querySelectorAll('.tab-btn').forEach(button => {
        button.addEventListener('click', () => {
            document.querySelectorAll('.tab-btn').forEach(btn => btn.classList.remove('active'));
            document.querySelectorAll('.tab-content').forEach(tab => tab.classList.add('hidden'));
            button.classList.add('active');
            document.getElementById(button.dataset.tab).classList.remove('hidden');

            if (button.dataset.tab === 'users') {
                loadUsers();
            } else if (button.dataset.tab === 'servers') {
                loadServers();
            } else if (button.dataset.tab === 'tickets') {
                loadTickets();
            } else if (button.dataset.tab === 'logs') {
                loadLogs();
            }
        });
    });

    // Logout button
    document.getElementById('logout-btn').addEventListener('click', logout);

    // Initialization
    const token = localStorage.getItem('authToken');
    const role = localStorage.getItem('role');
    if (!isAuthenticated() || role !== 'admin') {
        window.location.href = '/';
    } else {
        loadUsers();  // Load users by default
    }

    // Ticket modal functions
    async function openTicketModal(ticketId, username) {
        try {
            const response = await fetch(`${API_URL}/admin/users/${username}/tickets/${ticketId}`, {
                method: 'GET',
                headers: getAuthHeaders()
            });

            if (!response.ok) {
                const errorData = await response.json();
                throw new Error(errorData.error || 'Ошибка загрузки тикета');
            }

            const ticket = await response.json();
            displayTicketDetails(ticket, username);
        } catch (error) {
            console.error('Ошибка загрузки тикета:', error);
            showNotification(error.message, 'error');
        }
    }

    function displayTicketDetails(ticket, username) {
        document.getElementById('modal-ticket-title').textContent = ticket.title;
        document.getElementById('modal-ticket-description').textContent = ticket.description;
        document.getElementById('modal-ticket-username').textContent = username;

        const messagesContainer = document.getElementById('modal-ticket-messages');
        messagesContainer.innerHTML = '';

        if (!Array.isArray(ticket.messages) || ticket.messages.length === 0) {
            messagesContainer.innerHTML = '<p>Нет сообщений.</p>';
        } else {
            ticket.messages.forEach(msg => {
                const msgDiv = document.createElement('div');
                msgDiv.className = 'ticket-message';
                msgDiv.innerHTML = `
                    <p><strong>${msg.sender}</strong> <em>${new Date(msg.timestamp).toLocaleString()}</em></p>
                    <p>${msg.content}</p>
                `;
                messagesContainer.appendChild(msgDiv);
            });
        }

        const ticketModal = document.getElementById('ticket-modal');
        ticketModal.setAttribute('data-ticket-id', ticket.id);
        ticketModal.setAttribute('data-username', username);
        ticketModal.classList.remove('hidden');

        // Close modal event
        document.getElementById('close-ticket-modal').addEventListener('click', () => {
            ticketModal.classList.add('hidden');
        });

        // Handle reply form submission
        document.getElementById('reply-form').onsubmit = async (e) => {
            e.preventDefault();
            const messageContent = document.getElementById('reply-message').value.trim();

            if (!messageContent) {
                showNotification('Пожалуйста, введите сообщение', 'error');
                return;
            }

            try {
                const ticketId = ticketModal.getAttribute('data-ticket-id');
                const username = ticketModal.getAttribute('data-username');

                const response = await fetch(`${API_URL}/admin/tickets/${username}/${ticketId}/reply`, {
                    method: 'POST',
                    headers: getAuthHeaders(),
                    body: JSON.stringify({ message: messageContent })
                });

                if (!response.ok) {
                    const data = await response.json();
                    throw new Error(data.error || 'Ошибка при отправке ответа');
                }

                const newMessage = await response.json();
                showNotification('Ответ успешно отправлен!', 'success');
                // Add new message to interface
                const msgDiv = document.createElement('div');
                msgDiv.className = 'ticket-message';
                msgDiv.innerHTML = `
                    <p><strong>${newMessage.sender}</strong> <em>${new Date(newMessage.timestamp).toLocaleString()}</em></p>
                    <p>${newMessage.content}</p>
                `;
                messagesContainer.appendChild(msgDiv);
                document.getElementById('reply-form').reset();
            } catch (error) {
                console.error('Ошибка отправки ответа:', error);
                showNotification(error.message, 'error');
            }
        };
    }
});



const API_URL = '/api';

// Initialize currentUser variable
let currentUser = null;

// Plan configurations
const planConfigs = {
    basic: { key: 'basic', name: 'Базовый', cpu: 2, ram: 4, disk: '50GB', price: 500 },
    advanced: { key: 'advanced', name: 'Продвинутый', cpu: 4, ram: 8, disk: '100GB', price: 1000 },
    premium: { key: 'premium', name: 'Премиум', cpu: 8, ram: 16, disk: '200GB', price: 2000 }
};

// Helper functions
function showElement(id) {
    const element = document.getElementById(id);
    if (element) {
        element.classList.remove('hidden');
    } else {
        console.warn(`Element with id "${id}" not found.`);
    }
}

function hideElement(id) {
    const element = document.getElementById(id);
    if (element) {
        element.classList.add('hidden');
    } else {
        console.warn(`Element with id "${id}" not found.`);
    }
}

function setActiveTab(tabId) {
    const contents = document.querySelectorAll('.tab-content');
    contents.forEach(content => {
        content.classList.remove('active');
        content.style.opacity = 0; // Fade out
    });

    const newContent = document.getElementById(tabId);
    newContent.classList.add('active');
    setTimeout(() => {
        newContent.style.opacity = 1; // Fade in
    }, 50);
}

function getAuthHeaders() {
    const token = localStorage.getItem('authToken');
    if (!token) {
        window.location.href = '/';
        return {};
    }
    return {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${token}`
    };
}


function showNotification(message, type = 'error') {
    const container = document.getElementById('notification-container');
    const notification = document.createElement('div');
    notification.className = `notification ${type}`;
    notification.innerHTML = `
        <span>${message}</span>
        <button class="close-notification">&times;</button>
    `;
    container.appendChild(notification);

    setTimeout(() => {
        notification.classList.add('show');
    }, 100);

    setTimeout(() => {
        notification.classList.remove('show');
        setTimeout(() => {
            notification.remove();
        }, 500);
    }, 5000);

    notification.querySelector('.close-notification').addEventListener('click', () => {
        notification.classList.remove('show');
        setTimeout(() => {
            notification.remove();
        }, 500);
    });
}

function logout() {
    localStorage.removeItem('authToken');
    localStorage.removeItem('username');
    localStorage.removeItem('balance');
    localStorage.removeItem('role');
    currentUser = null;
    updateUserInterface();
    window.location.href = '/';
}


// Обработчик регистрации
document.getElementById('register').addEventListener('submit', async (e) => {
    e.preventDefault();
    const username = document.getElementById('reg-username').value.trim();
    const password = document.getElementById('reg-password').value.trim();

    if (!username || !password) {
        showNotification('Пожалуйста, заполните все поля', 'error');
        return;
    }

    try {
        const response = await fetch(`${API_URL}/register`, {
            method: 'POST',
            headers: { 
                'Content-Type': 'application/json',
                'Accept': 'application/json'
            },
            body: JSON.stringify({ username, password })
        });

        const data = await response.json();

        if (response.ok) {
            showNotification('Регистрация успешна! Теперь вы можете войти.', 'success');
            showElement('login-form');
            hideElement('register-form');
        } else {
            showNotification(data.error || 'Ошибка регистрации', 'error');
        }
    } catch (error) {
        console.error('Ошибка регистрации:', error);
        showNotification('Ошибка при регистрации', 'error');
    }
});

// Login function
document.getElementById('login').addEventListener('submit', async (e) => {
    e.preventDefault();
    const username = document.getElementById('login-username').value.trim();
    const password = document.getElementById('login-password').value.trim();

    if (!username || !password) {
        showNotification('Пожалуйста, заполните все поля', 'error');
        return;
    }

    try {
        const response = await fetch(`${API_URL}/login`, {
            method: 'POST',
            headers: { 
                'Content-Type': 'application/json',
                'Accept': 'application/json',
                'X-Requested-With': 'XMLHttpRequest'
            },
            body: JSON.stringify({ username, password })
        });

        if (!response.ok) {
            const data = await response.json();
            throw new Error(data.error || `HTTP error! status: ${response.status}`);
        }

        const data = await response.json();

        if (data.token) {
            localStorage.setItem('authToken', data.token);
            localStorage.setItem('username', data.username);
            localStorage.setItem('balance', data.balance);
            localStorage.setItem('role', data.role);  // Store the role
            currentUser = {
                username: data.username,
                balance: data.balance,
                role: data.role
            };
            if (currentUser.role === 'admin') {
                window.location.href = '/admin.html';  // Redirect admins
            } else {
                updateUserInterface();
                setActiveTab('servers');
                showNotification('Вход выполнен успешно!', 'success');
            }
        } else {
            showNotification('Неверные учетные данные', 'error');
        }
    } catch (error) {
        console.error('Ошибка входа:', error);
        showNotification(`Ошибка при входе в систему: ${error.message}`, 'error');
    }
});

// Проверка аутентификации
function isAuthenticated() {
    return localStorage.getItem('authToken') !== null;
}

// Управление серверами
async function loadServers() {
    try {
        const response = await fetch(`${API_URL}/servers`, {
            method: 'GET',
            headers: getAuthHeaders()
        });

        if (!response.ok) {
            const errorData = await response.json();
            throw new Error(errorData.error || `HTTP error! status: ${response.status}`);
        }

        const servers = await response.json();
        displayServers(servers);
    } catch (error) {
        console.error('Ошибка загрузки серверов:', error);
        showNotification(error.message, 'error');
    }
}

function displayServers(servers) {
    const serversList = document.getElementById('servers-list');
    serversList.innerHTML = '';

    if (!Array.isArray(servers) || servers.length === 0) {
        serversList.innerHTML = '<p>У вас нет серверов.</p>';
        return;
    }

    servers.forEach(server => {
        const serverCard = document.createElement('div');
        serverCard.className = 'server-card';
        serverCard.innerHTML = `
            <h3>${server.name}</h3>
            <span class="server-status status-${server.status}">${server.status}</span>
            <p><strong>IP:</strong> ${server.ip}</p>
            <p><strong>VNC:</strong> <a href="${server.vnc_address}" target="_blank">${server.vnc_address}</a></p>
            <p><strong>VNC Пароль:</strong> <span class="password-field" title="Наведи курсор для отображения">${server.vnc_password}</span></p>
            <p>План: ${server.plan.name}</p>
            <p>CPU: ${server.plan.cpu} / RAM: ${server.plan.ram}GB</p>
            <button class="btn primary view-server" data-server-id="${server.id}">Просмотреть</button>
            <button class="btn secondary update-server" data-server-id="${server.id}">Обновить</button>
            <button class="btn danger toggle-server" data-server-id="${server.id}">${server.status === 'active' ? 'Остановить' : 'Запустить'}</button>
            <button class="btn danger delete-server" data-server-id="${server.id}">Удалить</button>
            <button class="btn secondary restart-server" data-server-id="${server.id}">Перезапустить</button>
        `;
        serversList.appendChild(serverCard);
    });

    attachServerEventListeners();
    // Удаляем возможность показа пароля через кнопку
}

function attachServerEventListeners() {
    // Просмотр деталей сервера
    document.querySelectorAll('.view-server').forEach(button => {
        button.addEventListener('click', () => {
            const serverId = button.getAttribute('data-server-id');
            openServerDetailsModal(serverId);
        });
    });

    // Обновление сервера
    document.querySelectorAll('.update-server').forEach(button => {
        button.addEventListener('click', () => {
            const serverId = button.getAttribute('data-server-id');
            openUpdateServerModal(serverId);
        });
    });

    // Переключение статуса сервера
    document.querySelectorAll('.toggle-server').forEach(button => {
        button.addEventListener('click', () => {
            const serverId = button.getAttribute('data-server-id');
            toggleServerStatus(serverId);
        });
    });

    // Удаление сервера
    document.querySelectorAll('.delete-server').forEach(button => {
        button.addEventListener('click', () => {
            const serverId = button.getAttribute('data-server-id');
            deleteServer(serverId);
        });
    });

    // Перезапуск сервера
    document.querySelectorAll('.restart-server').forEach(button => {
        button.addEventListener('click', () => {
            const serverId = button.getAttribute('data-server-id');
            restartServer(serverId);
        });
    });
}

// Функция переключения статуса сервера
async function toggleServerStatus(serverId) {
    try {
        const response = await fetch(`${API_URL}/servers/${serverId}/toggle`, {
            method: 'POST',
            headers: getAuthHeaders()
        });

        if (!response.ok) {
            const errorData = await response.json();
            throw new Error(errorData.error || `HTTP error! status: ${response.status}`);
        }

        const result = await response.json();
        showNotification(result.message, 'success');
        loadServers();
    } catch (error) {
        console.error('Ошибка при переключении сервера:', error);
        showNotification(error.message, 'error');
    }
}

// Функция удаления сервера
async function deleteServer(serverId) {
    if (!confirm('Вы уверены, что хотите удалить этот сервер? Это действие нельзя отменить.')) return;

    try {
        const response = await fetch(`${API_URL}/servers/${serverId}`, {
            method: 'DELETE',
            headers: getAuthHeaders()
        });

        if (!response.ok) {
            const errorData = await response.json();
            throw new Error(errorData.error || `HTTP error! status: ${response.status}`);
        }

        const result = await response.json();
        showNotification(result.message, 'success');
        loadServers();
    } catch (error) {
        console.error('Ошибка при удалении сервера:', error);
        showNotification(error.message, 'error');
    }
}

// Функция перезапуска сервера
async function restartServer(serverId) {
    try {
        const response = await fetch(`${API_URL}/servers/${serverId}/restart`, {
            method: 'POST',
            headers: getAuthHeaders()
        });

        if (!response.ok) {
            const errorData = await response.json();
            throw new Error(errorData.error || `HTTP error! status: ${response.status}`);
        }

        const result = await response.json();
        showNotification(result.message, 'success');
        loadServers();
    } catch (error) {
        console.error('Ошибка при перезагрузке сервера:', error);
        showNotification(error.message, 'error');
    }
}

// Управление тикетами
document.getElementById('ticket-form').addEventListener('submit', async (e) => {
    e.preventDefault();
    const title = document.getElementById('ticket-title').value.trim();
    const description = document.getElementById('ticket-description').value.trim();

    if (!title || !description) {
        showNotification('Пожалуйста, заполните все поля', 'error');
        return;
    }

    try {
        const response = await fetch(`${API_URL}/tickets`, {
            method: 'POST',
            headers: getAuthHeaders(),
            body: JSON.stringify({ title, description })
        });

        if (!response.ok) {
            const data = await response.json();
            throw new Error(data.error || 'Ошибка при создании тикета');
        }

        showNotification('Тикет успешно создан!', 'success');
        document.getElementById('ticket-form').reset();
        loadTickets();
    } catch (error) {
        console.error('Ошибка создания тикета:', error);
        showNotification(error.message, 'error');
    }
});

async function loadTickets() {
    try {
        const response = await fetch(`${API_URL}/tickets`, {
            method: 'GET',
            headers: getAuthHeaders()
        });

        if (!response.ok) {
            const errorData = await response.json();
            throw new Error(errorData.error || `HTTP error! status: ${response.status}`);
        }

        const tickets = await response.json();
        displayTickets(tickets);
    } catch (error) {
        console.error('Ошибка загрузки тикетов:', error);
        showNotification(error.message, 'error');
    }
}

function displayTickets(tickets) {
    const ticketsList = document.getElementById('tickets-list');
    ticketsList.innerHTML = '';

    if (!Array.isArray(tickets) || tickets.length === 0) {
        ticketsList.innerHTML = '<p>У вас нет тикетов.</p>';
        return;
    }

    tickets.forEach(ticket => {
        const ticketCard = document.createElement('div');
        ticketCard.className = 'ticket-card';
        ticketCard.innerHTML = `
            <div class="ticket-header">
                <h3>${ticket.title}</h3>
                <span class="ticket-status status-${ticket.status}">${ticket.status}</span>
            </div>
            <p>${ticket.description}</p>
            <small>Создан: ${new Date(ticket.created_at).toLocaleString()}</small>
            <button class="btn primary view-ticket" data-ticket-id="${ticket.id}">Просмотреть</button>
        `;
        ticketsList.appendChild(ticketCard);
    });

    document.querySelectorAll('.view-ticket').forEach(button => {
        button.addEventListener('click', () => {
            const ticketId = button.getAttribute('data-ticket-id');
            openTicketModal(ticketId);
        });
    });
}

async function openTicketModal(ticketId) {
    try {
        const response = await fetch(`${API_URL}/tickets/${ticketId}`, {
            method: 'GET',
            headers: getAuthHeaders()
        });

        if (!response.ok) {
            const errorData = await response.json();
            throw new Error(errorData.error || `HTTP error! status: ${response.status}`);
        }

        const ticket = await response.json();
        displayTicketDetails(ticket);
    } catch (error) {
        console.error('Ошибка загрузки тикета:', error);
        showNotification(error.message, 'error');
    }
}

function displayTicketDetails(ticket) {
    document.getElementById('modal-ticket-title').textContent = ticket.title;
    document.getElementById('modal-ticket-description').textContent = ticket.description;

    const messagesContainer = document.getElementById('modal-ticket-messages');
    messagesContainer.innerHTML = '';

    if (!Array.isArray(ticket.messages) || ticket.messages.length === 0) {
        messagesContainer.innerHTML = '<p>Нет сообщений.</p>';
    } else {
        ticket.messages.forEach(msg => {
            const msgDiv = document.createElement('div');
            msgDiv.className = 'ticket-message';
            msgDiv.innerHTML = `
                <p><strong>${msg.sender}</strong> <em>${new Date(msg.timestamp).toLocaleString()}</em></p>
                <p>${msg.content}</p>
            `;
            messagesContainer.appendChild(msgDiv);
        });
    }

    const ticketModal = document.getElementById('ticket-modal');
    ticketModal.setAttribute('data-ticket-id', ticket.id);
    showElement('ticket-modal');

    // Обработчик отправки ответа
    document.getElementById('reply-form').onsubmit = async (e) => {
        e.preventDefault();
        const messageContent = document.getElementById('reply-message').value.trim();

        if (!messageContent) {
            showNotification('Пожалуйста, введите сообщение', 'error');
            return;
        }

        try {
            const response = await fetch(`${API_URL}/tickets/${ticketId}/reply`, {
                method: 'POST',
                headers: getAuthHeaders(),
                body: JSON.stringify({ message: messageContent })
            });

            if (!response.ok) {
                const data = await response.json();
                throw new Error(data.error || 'Ошибка при отправке ответа');
            }

            const newMessage = await response.json();
            showNotification('Ответ успешно отправлен!', 'success');
            // Добавить новое сообщение в интерфейс
            const msgDiv = document.createElement('div');
            msgDiv.className = 'ticket-message';
            msgDiv.innerHTML = `
                <p><strong>${newMessage.sender}</strong> <em>${new Date(newMessage.timestamp).toLocaleString()}</em></p>
                <p>${newMessage.content}</p>
            `;
            messagesContainer.appendChild(msgDiv);
            document.getElementById('reply-form').reset();
        } catch (error) {
            console.error('Ошибка отправки ответа:', error);
            showNotification(error.message, 'error');
        }
    };
}

// Функциональность модального окна настроек
document.getElementById('settings').addEventListener('click', () => {
    // Установка активной вкладки
    setActiveTab('settings');
});

// Update Userinfo Form Handler
document.getElementById('settings-form-main').addEventListener('submit', async (e) => {
    e.preventDefault();
    const newUsername = document.getElementById('new-username-main').value.trim();
    const currentPassword = document.getElementById('current-password-main').value.trim();
    const newPassword = document.getElementById('new-password-main').value.trim();

    if (!currentPassword) {
        showNotification('Текущий пароль обязателен', 'error');
        return;
    }

    if (!newUsername && !newPassword) {
        showNotification('Пожалуйста, введите новое имя пользователя или пароль', 'error');
        return;
    }

    const payload = { current_password: currentPassword };
    if (newUsername) payload.new_username = newUsername;
    if (newPassword) payload.new_password = newPassword;

    try {
        const response = await fetch(`${API_URL}/userinfo`, {
            method: 'PUT',
            headers: getAuthHeaders(),
            body: JSON.stringify(payload)
        });

        if (!response.ok) {
            const data = await response.json();
            throw new Error(data.error || `HTTP error! status: ${response.status}`);
        }

        const data = await response.json();
        if (data.username) {
            localStorage.setItem('username', data.username);
            currentUser.username = data.username;
            document.getElementById('username').textContent = `Пользователь: ${currentUser.username}`;
        }

        if (data.balance !== undefined) {
            localStorage.setItem('balance', data.balance);
            currentUser.balance = data.balance;
            document.getElementById('balance').textContent = `Баланс: ${currentUser.balance} ₽`;
        }

        showNotification('Настройки успешно обновлены!', 'success');
        setActiveTab('servers'); // Переключение обратно на вкладку серверов
    } catch (error) {
        console.error('Ошибка обновления настроек:', error);
        showNotification(error.message, 'error');
    }
});

// Обработчики кнопок закрытия модальных окон
document.querySelectorAll('.close-modal').forEach(button => {
    button.addEventListener('click', () => {
        button.closest('.modal').classList.add('hidden');
    });
});

// Функция открытия модального окна создания сервера
document.getElementById('open-buy-server').addEventListener('click', () => {
    showElement('buy-server-modal');
});

// Обработчик формы покупки сервера
document.getElementById('buy-server-form').addEventListener('submit', async (e) => {
    e.preventDefault();
    const serverName = document.getElementById('server-name').value.trim();
    const serverOS = document.getElementById('server-os').value;

    const selectedPlanKey = document.querySelector('.buy-server.active')?.dataset.plan;
    const planDetails = planConfigs[selectedPlanKey];

    if (!serverName || !serverOS || !planDetails) {
        showNotification('Пожалуйста, заполните все поля и выберите план', 'error');
        return;
    }

    try {
        const response = await fetch(`${API_URL}/servers`, {
            method: 'POST',
            headers: getAuthHeaders(),
            body: JSON.stringify({
                name: serverName,
                plan: planDetails.key,
                os: serverOS
            })
        });

        if (!response.ok) {
            const errorData = await response.json();
            throw new Error(errorData.error || 'Ошибка при создании сервера');
        }

        const newServer = await response.json();
        showNotification('Сервер успешно создан!', 'success');
        hideElement('buy-server-modal');
        document.getElementById('buy-server-form').reset();
        loadServers();

        // Обновить баланс пользователя
        currentUser.balance -= planDetails.price;
        localStorage.setItem('balance', currentUser.balance);
        document.getElementById('balance').textContent = `Баланс: ${currentUser.balance} ₽`;
    } catch (error) {
        console.error('Ошибка покупки сервера:', error);
        showNotification(error.message, 'error');
    }
});

// Функция открытия модального окна деталей сервера
async function openServerDetailsModal(serverId) {
    try {
        const response = await fetch(`${API_URL}/servers/${serverId}`, {
            method: 'GET',
            headers: getAuthHeaders()
        });

        if (!response.ok) {
            const errorData = await response.json();
            throw new Error(errorData.error || `HTTP error! status: ${response.status}`);
        }

        const server = await response.json();
        displayServerDetails(server);
    } catch (error) {
        console.error('Ошибка загрузки сервера:', error);
        showNotification(error.message, 'error');
    }
}

function displayServerDetails(server) {
    document.getElementById('modal-server-name').textContent = server.name;
    document.getElementById('modal-server-ip').textContent = server.ip;
    document.getElementById('modal-server-vnc-address').innerHTML = `<a href="${server.vnc_address}" target="_blank">${server.vnc_address}</a>`;
    document.getElementById('modal-server-vnc-password').textContent = server.vnc_password;

    // Используем CSS для раскрытия пароля при наведении
    // Здесь отсутствует кнопка "Показать", так что просто оставляем текст размытым

    // Добавить информацию о сервере
    document.getElementById('modal-server-plan').textContent = server.plan.name;
    document.getElementById('modal-server-os').textContent = server.os;
    document.getElementById('modal-server-status').textContent = server.status;

    // Заполнить порты
    const portsInfo = `
        <p><strong>Port 8006/tcp:</strong> ${server.ports["8006/tcp"]}</p>
        <p><strong>RDP TCP:</strong> ${server.ports["3389/tcp"]}</p>
        <p><strong>RDP UDP:</strong> ${server.ports["3389/udp"]}</p>
        <p><strong>VNC TCP:</strong> ${server.ports["5900/tcp"]}</p>
    `;
    document.getElementById('server-ports').innerHTML = portsInfo;

    showElement('server-details-modal');
}

// Функция обновления интерфейса пользователя
function updateUserInterface() {
    const authContainer = document.getElementById('auth-container');
    const mainContent = document.getElementById('main-content');
    const usernameElement = document.getElementById('username');
    const balanceElement = document.getElementById('balance');

    if (isAuthenticated()) {
        if (!currentUser) {
            const username = localStorage.getItem('username');
            const balance = parseFloat(localStorage.getItem('balance'));

            if (username && !isNaN(balance)) {
                currentUser = {
                    username: username,
                    balance: balance
                };
                finalizeUserInterface();
            } else {
                // Получить информацию о пользователе с сервера
                fetch(`${API_URL}/userinfo`, {
                    method: 'GET',
                    headers: getAuthHeaders()
                })
                .then(response => {
                    if (!response.ok) {
                        throw new Error('Не удалось получить информацию о пользователе');
                    }
                    return response.json();
                })
                .then(data => {
                    currentUser = {
                        username: data.username,
                        balance: data.balance
                    };
                    // Сохранить эти данные в localStorage
                    localStorage.setItem('username', data.username);
                    localStorage.setItem('balance', data.balance);
                    // Обновить интерфейс
                    finalizeUserInterface();
                })
                .catch(error => {
                    console.error('Не удалось получить информацию о пользователе:', error);
                    logout(); // Опционально, выйти из системы, если не удалось получить информацию
                });
            }
        } else {
            finalizeUserInterface();
        }
    } else {
        // Показать контейнер аутентификации и скрыть основной контент
        authContainer.classList.remove('hidden');
        mainContent.classList.add('hidden');
    }
}

function finalizeUserInterface() {
    const authContainer = document.getElementById('auth-container');
    const mainContent = document.getElementById('main-content');
    const usernameElement = document.getElementById('username');
    const balanceElement = document.getElementById('balance');

    authContainer.classList.add('hidden');
    mainContent.classList.remove('hidden');

    // Обновить информацию о пользователе в заголовке
    if (usernameElement) usernameElement.textContent = `Пользователь: ${currentUser.username}`;
    if (balanceElement) balanceElement.textContent = `Баланс: ${currentUser.balance} ₽`;

    // Загрузить данные пользователя
    loadServers();
    loadTickets();
}

// Обработчики переключения форм
document.getElementById('show-register').addEventListener('click', (e) => {
    e.preventDefault();
    hideElement('login-form');
    showElement('register-form');
});

document.getElementById('show-login').addEventListener('click', (e) => {
    e.preventDefault();
    hideElement('register-form');
    showElement('login-form');
});

// Обработчики навигации по вкладкам
document.querySelectorAll('.tab-btn').forEach(btn => {
    btn.addEventListener('click', () => {
        setActiveTab(btn.dataset.tab);
    });
});

// Обработчик кнопки выхода
document.getElementById('logout-btn').addEventListener('click', () => {
    logout();
});

// Инициализация при загрузке страницы
document.addEventListener('DOMContentLoaded', function() {
    updateUserInterface();
});



{
  "users": {
    "test": {
      "password": "$pbkdf2-sha256$29000$<hashed_password_here>",
      "servers": [
        {
          "id": 1,
          "name": "Server-1730443463374",
          "plan": {
            "key": "advanced",
            "name": "jrngjae",
            "cpu": 4,
            "ram": 8,
            "price": 1000
          },
          "status": "active",
          "password": "SVBes7qlNc40",
          "created_at": "2024-11-01T13:44:23.380705",
          "auto_renewal": true,
          "container_name": "server_47387a38",
          "ports": {
            "8006/tcp": 12345,
            "3389/tcp": 23456,
            "3389/udp": 23456
          }
        }
      ],
      "balance": 34765734657833657,
      "tickets": [
        {
          "id": 1,
          "title": "test",
          "description": "test",
          "status": "open",
          "created_at": "2024-11-01T13:34:30.026514",
          "messages": []
        }
      ],
      "logs": [],
      "created_at": "2024-11-01T13:23:04.989224",
      "role": "user"
    },
    "test4453": {
      "password": "$pbkdf2-sha256$29000$IUQo5VyLsZYyJsT4fw9BKA$0F/z5qNGFgVhu//bW7cDzKRKZL66MXjEoxqYTKveyAY",
      "servers": [],
      "balance": 6994000,
      "tickets": [],
      "logs": [],
      "created_at": "2024-11-02T04:08:25.433258",
      "role": "admin"
    },
    "admin": {
      "password": "$pbkdf2-sha256$29000$IqS0Vurdu3fufU.pNSYEYA$xroF5KX/IT/28bzR9V0gcfPA2jzWGZoseacqm4wpG.U",
      "servers": [],
      "balance": 0,
      "tickets": [],
      "logs": [],
      "created_at": "2024-11-02T21:30:36.217539",
      "role": "admin"
    }
  },
  "logs": [
    {
      "timestamp": "2024-11-02T04:18:25.090630",
      "username": "test4453",
      "action": "login",
      "browser": "Chrome",
      "os": "Windows",
      "device": "Other",
      "ip": "127.0.0.1"
    },
    {
      "timestamp": "2024-11-02T04:18:48.982819",
      "username": "test4453",
      "action": "create_server",
      "browser": "Chrome",
      "os": "Windows",
      "device": "Other",
      "ip": "127.0.0.1"
    },
    {
      "timestamp": "2024-11-02T21:30:47.311132",
      "username": "test4453",
      "action": "login",
      "browser": "Chrome",
      "os": "Windows",
      "device": "Other",
      "ip": "127.0.0.1"
    },
    {
      "timestamp": "2024-11-02T21:31:10.051326",
      "username": "test4453",
      "action": "login",
      "browser": "Chrome",
      "os": "Windows",
      "device": "Other",
      "ip": "127.0.0.1"
    },
    {
      "timestamp": "2024-11-02T21:37:34.117611",
      "username": "test4453",
      "action": "login",
      "browser": "Chrome",
      "os": "Windows",
      "device": "Other",
      "ip": "127.0.0.1"
    },
    {
      "timestamp": "2024-11-02T21:49:29.231965",
      "username": "test4453",
      "action": "login",
      "browser": "Chrome",
      "os": "Windows",
      "device": "Other",
      "ip": "127.0.0.1"
    },
    {
      "timestamp": "2024-11-02T21:57:00.389988",
      "username": "test4453",
      "action": "login",
      "browser": "Chrome",
      "os": "Windows",
      "device": "Other",
      "ip": "127.0.0.1"
    },
    {
      "timestamp": "2024-11-02T23:07:11.415035",
      "username": "test4453",
      "action": "login",
      "browser": "Chrome",
      "os": "Windows",
      "device": "Other",
      "ip": "127.0.0.1"
    },
    {
      "timestamp": "2024-11-02T23:29:35.571245",
      "username": "test4453",
      "action": "login",
      "browser": "Chrome",
      "os": "Windows",
      "device": "Other",
      "ip": "127.0.0.1"
    },
    {
      "timestamp": "2024-11-02T23:39:01.080747",
      "username": "test4453",
      "action": "login",
      "browser": "Chrome",
      "os": "Windows",
      "device": "Other",
      "ip": "127.0.0.1"
    },
    {
      "timestamp": "2024-11-02T23:49:32.263749",
      "username": "test4453",
      "action": "login",
      "browser": "Chrome",
      "os": "Windows",
      "device": "Other",
      "ip": "127.0.0.1"
    },
    {
      "timestamp": "2024-11-02T23:49:51.502472",
      "username": "test4453",
      "action": "login",
      "browser": "Chrome",
      "os": "Windows",
      "device": "Other",
      "ip": "127.0.0.1"
    },
    {
      "timestamp": "2024-11-03T00:20:27.228696",
      "username": "test4453",
      "action": "login",
      "browser": "Chrome",
      "os": "Windows",
      "device": "Other",
      "ip": "127.0.0.1"
    },
    {
      "timestamp": "2024-11-03T00:42:53.345320",
      "username": "test4453",
      "action": "login",
      "browser": "Chrome",
      "os": "Windows",
      "device": "Other",
      "ip": "127.0.0.1"
    },
    {
      "timestamp": "2024-11-03T00:52:35.296750",
      "username": "test4453",
      "action": "login",
      "browser": "Chrome",
      "os": "Windows",
      "device": "Other",
      "ip": "127.0.0.1"
    }
  ]
}



fix all errors in backend and frontend, like autoredirect while trying to visit admin page with admin right's, also fix no content error in user interface when clicking on options in panel i don't see anything also remove create button from servers page add setting's tab with password and name