import requests
from bs4 import BeautifulSoup
import os
import py7zr
import tkinter as tk
from tkinter import filedialog
import subprocess
import ctypes
import sys
import logging
from tkinter import messagebox

# ASCII-Print-Text
ascii_art = r"""
  /$$$$$$                                /$$   /$$                       /$$    
 /$$__  $$                              | $$  | $$                      | $$    
| $$  \__/  /$$$$$$   /$$$$$$   /$$$$$$ | $$  | $$  /$$$$$$   /$$$$$$$ /$$$$$$  
| $$       /$$__  $$ /$$__  $$ /$$__  $$| $$$$$$$$ /$$__  $$ /$$_____/|_  $$_/  
| $$      | $$  \ $$| $$  \__/| $$  \ $$| $$__  $$| $$  \ $$|  $$$$$$   | $$    
| $$    $$| $$  | $$| $$      | $$  | $$| $$  | $$| $$  | $$ \____  $$  | $$ /$$
|  $$$$$$/|  $$$$$$/| $$      |  $$$$$$/| $$  | $$|  $$$$$$/ /$$$$$$$/  |  $$$$/ 
 \______/  \______/ |__/       \______/ |__/  |__/ \______/ |_______/    \___/  
 by Myzi
"""

# Logging konfigurieren
logging.basicConfig(
    filename='fivem_installation.log',
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s'
)

def is_admin():
    try:
        return ctypes.windll.shell32.IsUserAnAdmin()
    except Exception:
        return False

def main():
    print(ascii_art)  # ASCII-Print ausgeben
    if not is_admin():
        logging.info("Das Skript benötigt Administratorrechte. Bitte als Administrator ausführen.")
        # Administratorrechte anfordern und aktuelles Fenster schließen
        ctypes.windll.shell32.ShellExecuteW(None, "runas", sys.executable, " ".join(sys.argv), None, 1)
        sys.exit()  # Beende das alte Fenster

    base_url = "https://runtime.fivem.net/artifacts/fivem/build_server_windows/master/"
    logging.info("---- Skript gestartet ----")
    logging.info(f"Lade Webseite herunter: {base_url}")

    try:
        response = requests.get(base_url)
        response.raise_for_status()
        logging.info("Webseite erfolgreich heruntergeladen.")

        number = input("Bitte gib die Build-Zahl ein: ")
        logging.info(f"Gesuchte Build-Zahl: {number}")

        soup = BeautifulSoup(response.text, 'html.parser')
        links = soup.find_all('a', href=True)
        found_link = None

        for link in links:
            if number in link.text:
                found_link = link['href']
                break

        if found_link:
            full_link = os.path.join(base_url, found_link)
            logging.info(f"Der zugehörige Link für Build {number} lautet: {full_link}")
            local_filename = download_file(full_link)
            if local_filename:
                output_folder = select_output_folder()
                if output_folder:
                    server_folder = os.path.join(output_folder, "server")
                    txdata_folder = os.path.join(output_folder, "txData")
                    os.makedirs(server_folder, exist_ok=True)
                    os.makedirs(txdata_folder, exist_ok=True)
                    extract_file(local_filename, server_folder)
                    create_readme(output_folder)  # Erstelle die Readme.txt
                    os.remove(local_filename)  # Lösche die heruntergeladene 7z-Datei
                    logging.info(f"Die Datei {local_filename} wurde gelöscht.")

                    # Firewall-Regeln erstellen
                    if create_firewall_rules():
                        logging.info("Firewall-Regeln wurden erfolgreich erstellt oder übersprungen.")
                    else:
                        logging.warning("Fehler beim Erstellen der Firewall-Regeln.")

                    # FXServer.exe starten
                    fxserver_path = os.path.join(server_folder, "FXServer.exe")
                    if os.path.exists(fxserver_path):
                        start_fxserver(fxserver_path)  # Starte den FXServer
                    else:
                        logging.error("FXServer.exe wurde nicht gefunden.")

        else:
            logging.warning(f"Kein Link für Build {number} gefunden.")

    except requests.RequestException as e:
        logging.error(f"Fehler beim Herunterladen der Webseite: {e}")
    except Exception as e:
        logging.error(f"Ein unerwarteter Fehler ist aufgetreten: {e}")

    logging.info("---- Skript beendet ----")


def download_file(url):
    try:
        response = requests.get(url, stream=True)
        response.raise_for_status()
        filename = url.split('/')[-1]

        with open(filename, 'wb') as file:
            for chunk in response.iter_content(chunk_size=8192):
                file.write(chunk)

        logging.info(f"Datei erfolgreich heruntergeladen: {filename}")
        return filename
    except requests.RequestException as e:
        logging.error(f"Fehler beim Herunterladen der Datei: {e}")
        return None


def select_output_folder():
    root = tk.Tk()
    root.withdraw()  # Hauptfenster ausblenden
    folder_path = filedialog.askdirectory(title="Wähle einen Zielordner zum Entpacken der Datei")
    return folder_path


def extract_file(file_path, output_folder):
    try:
        with py7zr.SevenZipFile(file_path, mode='r') as archive:
            archive.extractall(path=output_folder)
        logging.info(f"Datei erfolgreich entpackt in: {output_folder}")
    except Exception as e:
        logging.error(f"Fehler beim Entpacken der Datei: {e}")


def create_readme(output_folder):
    readme_content = (
        "Danke, dass du dich für das automatische FiveM Installationsskript von Corohost entschieden hast.\n"
        "Bei Fragen wende dich gerne auf unserem Discord an uns:\n"
        "https://Discord.gg/corohost"
    )
    readme_path = os.path.join(output_folder, "Readme.txt")
    with open(readme_path, 'w', encoding='utf-8') as readme_file:
        readme_file.write(readme_content)
    logging.info("Readme.txt erfolgreich erstellt.")


def create_firewall_rules():
    rules = [
        {"name": "FIVEM-AUTOINSTALL-1", "port": 30120, "protocol": "TCP"},
        {"name": "FIVEM-AUTOINSTALL-2", "port": 30120, "protocol": "UDP"},
        {"name": "FIVEM-AUTOINSTALL-4", "port": 40120, "protocol": "TCP"},
        {"name": "FIVEM-AUTOINSTALL-5", "port": 40120, "protocol": "UDP"},
    ]

    for rule in rules:
        if check_firewall_rule(rule["name"]):
            response = messagebox.askyesno("Firewall-Regel existiert",
                                           f"Die Firewall-Regel '{rule['name']}' existiert bereits.\nMöchten Sie die Regel erneut erstellen?")
            if response:  # Benutzer hat "Ja" gewählt
                create_rule(rule)  # Erstelle die Regel neu
            else:
                logging.info(f"Erstellung der Firewall-Regel '{rule['name']}' wurde übersprungen.")
        else:
            create_rule(rule)  # Regel erstellen, wenn sie nicht existiert


def create_rule(rule):
    try:
        subprocess.run(
            ["netsh", "advfirewall", "firewall", "add", "rule",
             f"name={rule['name']}", "dir=in", "action=allow",
             f"protocol={rule['protocol']}", f"localport={rule['port']}",
             "enable=yes"],
            check=True
        )
        subprocess.run(
            ["netsh", "advfirewall", "firewall", "add", "rule",
             f"name={rule['name']}", "dir=out", "action=allow",
             f"protocol={rule['protocol']}", f"localport={rule['port']}",
             "enable=yes"],
            check=True
        )
        logging.info(
            f"Firewall-Regel '{rule['name']}' erfolgreich erstellt für Port {rule['port']} ({rule['protocol']}).")
    except subprocess.CalledProcessError as e:
        logging.error(f"Fehler beim Erstellen der Firewall-Regel: {e}")


def check_firewall_rule(rule_name):
    try:
        result = subprocess.run(
            ["netsh", "advfirewall", "firewall", "show", "rule", f"name={rule_name}"],
            capture_output=True,
            text=True
        )
        return "No rules match the specified criteria" not in result.stdout
    except Exception as e:
        logging.error(f"Fehler beim Überprüfen der Firewall-Regel: {e}")
        return False


def start_fxserver(fxserver_path):
    try:
        subprocess.Popen(fxserver_path, creationflags=subprocess.CREATE_NEW_CONSOLE)
        logging.info("FXServer.exe wurde erfolgreich in einem neuen CMD-Fenster gestartet.")
    except Exception as e:
        logging.error(f"Fehler beim Starten von FXServer.exe: {e}")


if __name__ == "__main__":
    main()
