import os
import sys
import socket
import struct
import ctypes
from loguru import logger

# --- [ КОНФИГУРАЦИЯ СТЕКА HioSW ] ---
# Формат: RR (2 байта), Flags (1 байт)
HEADER_FORMAT = "!H B"

def is_admin():
    """Проверка прав через Shell32"""
    try:
        return ctypes.windll.shell32.IsUserAnAdmin()
    except:
        return False

def get_script_dir():
    """Определение папки через GetModuleFileNameW для надежности"""
    buf = ctypes.create_unicode_buffer(1024)
    ctypes.windll.kernel32.GetModuleFileNameW(None, buf, 1024)
    return os.path.dirname(buf.value)

# --- [ АВТО-АДМИНКА ] ---
if __name__ == "__main__" and not is_admin():
    script = os.path.abspath(sys.argv[0])
    params = ' '.join(sys.argv[1:])
    ctypes.windll.shell32.ShellExecuteW(None, "runas", sys.executable, f'"{script}" {params}', None, 1)
    sys.exit()

# --- [ ЯДРО СИСТЕМЫ / Lib Class ] ---
class R_TCP:
    def __init__(self, target_ip="127.0.0.1", am=1, gsm=0, tndm=0, rr=0):
        self.target_ip = target_ip
        self.am = am
        self.gsm = gsm
        self.tndm = tndm
        self.rr = rr
        self.base_dir = get_script_dir()
        try:
            os.chdir(self.base_dir) 
        except:
            pass

    def pack_hio(self, data, am=None, gsm=0, tndm=0, rr=None):
        """Упаковка данных с учетом флагов (GSM=бит 5, TnDM=бит 4)"""
        _am = am if am is not None else self.am
        _rr = rr if rr is not None else self.rr
        # Флаги: AM(биты 6-7), GSM(бит 5), TnDM(бит 4)
        flags = (_am << 6) | (gsm << 5) | (tndm << 4)
        payload = data if isinstance(data, bytes) else str(data).encode('utf-8')
        return struct.pack(HEADER_FORMAT, _rr, flags) + payload

    def node(self, is_server=False):
        """
        Метод управления нодой для PyPI. 
        node(True) -> Запускает бесконечный цикл сервера (LISTEN).
        node(False) -> Возвращает объект для отправки данных (Client).
        """
        if is_server:
            self._listen_loop()
        else:
            return self

    def _listen_loop(self):
        """Внутренняя логика сервера для метода node(True)"""
        logger.info(f"Node listening on port 80... (Ctrl+C to stop)")
        try:
            with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
                s.bind(('0.0.0.0', 80))
                s.listen()
                while True:
                    conn, addr = s.accept()
                    raw = conn.recv(65535)
                    if len(raw) < 3: continue
                    rr, fl = struct.unpack(HEADER_FORMAT, raw[:3])
                    data = raw[3:]
                    
                    # Парсинг флагов
                    is_gsm = (fl >> 5) & 1
                    is_tndm = (fl >> 4) & 1
                    
                    if is_tndm:
                        msg = data.decode('utf-8', errors='ignore')
                        logger.opt(colors=True).success(f"<yellow>TnDM SMS</yellow> | {addr[0]}: <white>{msg}</white>")
                    elif is_gsm:
                        logger.info(f"GSM HTML | {addr[0]} | Size: {len(data)} bytes")
                    else:
                        logger.info(f"RAW | AM:{fl>>6} RR:{rr} | Size:{len(data)}")
        except KeyboardInterrupt:
            print("\nNode stopped.")
        except Exception as e:
            logger.error(f"Server Error: {e}")

    def send_tndm(self, text):
        """Метод для быстрой отправки текста через TnDM"""
        packet = self.pack_hio(text, tndm=1)
        try:
            with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
                s.settimeout(5)
                s.connect((self.target_ip, 80))
                s.sendall(packet)
                logger.success(f"TnDM sent to {self.target_ip}")
                return True
        except Exception as e:
            logger.error(f"TnDM send failed: {e}")
            return False

# --- [ ИНТЕРФЕЙС / CLI ] ---
def hio_interface():
    client = R_TCP()
    
    while True:
        os.system('cls' if os.name == 'nt' else 'clear')
        print(f"=== [ HioSW R-TCP v2.5.0 | TnDM & Lib Mode ] ===")
        print(f"PATH: {client.base_dir}")
        print(f"CONFIG: TARGET:{client.target_ip} | AM:{client.am} | RR:{client.rr}\n")
        print(f"1. [LISTEN]  Запуск ноды (Сервер)")
        print(f"2. [GSM]     Отправить HTML файл")
        print(f"3. [TnDM]    Отправить SMS (Текст)")
        print(f"4. [CONFIG]  Настройка (IP/AM/RR)")
        print(f"0. [EXIT]    Выход")
        
        choice = input("\nSelect > ")

        if choice == '1':
            client.node(is_server=True)

        elif choice == '2':
            html_files = [f for f in os.listdir(client.base_dir) if f.endswith('.html')]
            if not html_files:
                print(f"(!) Файлы .html не найдены"); input(); continue
            for i, f in enumerate(html_files): print(f"{i}. {f}")
            f_idx = int(input("№ файла: "))
            with open(os.path.join(client.base_dir, html_files[f_idx]), 'rb') as f:
                packet = client.pack_hio(f.read(), gsm=1)
            try:
                with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
                    s.settimeout(5); s.connect((client.target_ip, 80))
                    s.sendall(packet)
                    logger.success(f"Файл доставлен")
            except Exception as e: logger.error(e)
            input("\nEnter...")

        elif choice == '3':
            msg = input("Текст сообщения: ")
            client.send_tndm(msg)
            input("\nНажмите Enter...")

        elif choice == '4':
            os.system('cls')
            print(f"1. IP ({client.target_ip})\n2. AM ({client.am})\n3. RR ({client.rr})\n0. Назад")
            sub = input("\nOpt > ")
            if sub == '1': client.target_ip = input("New IP: ")
            elif sub == '2': client.am = int(input("New AM (0-3): "))
            elif sub == '3': client.rr = int(input("New RR: "))

        elif choice == '0': sys.exit()

if __name__ == "__main__":
    hio_interface()
