import socket
import threading
import os
import sys
import logging
import json

# Globals
pushes = []
EXIT = False
lock = threading.Lock()

# Server function to create socket
def make_server_socket(port):
    MAXNAMELEN = 255
    BACKLOG = 3
    hostname = "localhost"
    
    try:
        # Set up the socket
        server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        server_socket.bind((hostname, port))
        server_socket.listen(BACKLOG)
        print(f"Waiting for connection on port {port}")
        return server_socket
    except Exception as e:
        print(f"Error creating server socket: {e}")
        sys.exit(1)

# Function to write logs
def write_to_log(message, ip):
    logging.basicConfig(filename="log.txt", level=logging.INFO)
    logging.info(f"[{ip}] : {message}")
    print(f"[{ip}] : {message}")

# Function to check version
def check_version(version):
    try:
        for push in pushes:
            if int(push[1]) == int(version) or int(push[1]) > int(version):
                return False
        return True
    except ValueError:
        return True

# Write the pushes to file
def write_to_push_file():
    with open("pushes.txt", "w") as push_file:
        for push in pushes:
            push_file.write(f"{push[0]},{push[1]}\n")

# Function to make prompt
def make_prompt(prompt="> "):
    return input(prompt)

# Execute push command
def execute_push(commands):
    if len(commands) == 3:
        print("Please verify push data")
        print("-----------------------")
        print(f"Installer link: {commands[1]}")
        print(f"Version Number: {commands[2]}")
        x = make_prompt("Is this information correct? [y/n] ")
        if x.lower() == 'y':
            if check_version(commands[2]):
                with lock:
                    pushes.append([commands[1], commands[2]])
                write_to_push_file()
            else:
                print("This Version Number already Exists!")

# Execute remove command
def execute_remove(commands):
    try:
        delete_cand = int(commands[1]) - 1
        pushes.pop(delete_cand)
        write_to_push_file()
    except Exception as e:
        print("Your selection was invalid")

# Execute show command
def execute_show(commands):
    print("\nPushes")
    print("----------------------------------")
    for idx, push in enumerate(pushes):
        print(f"{idx + 1}: {push[0]}, {push[1]}")

# Function to send data to socket
def write_out(sock, data):
    sock.sendall(data.encode())

# Server loop to handle incoming connections
def server_loop():
    server_socket = make_server_socket(2004)
    while True:
        try:
            client_socket, client_address = server_socket.accept()
            print("Connection Made")
            data = client_socket.recv(1024).decode()
            print(data)

            commands = data.split(" ")
            if commands[0] == "INIT":
                write_out(client_socket, "READY")
            elif commands[0] == "CHECK":
                try:
                    version = int(commands[1])
                    if version < int(pushes[-1][1]):
                        write_out(client_socket, pushes[-1][0])
                    else:
                        write_out(client_socket, "UPTODATE")
                except Exception as e:
                    write_out(client_socket, "FAIL")
            else:
                write_out(client_socket, "FAIL")
            client_socket.close()
        except Exception as e:
            print(f"Error in server loop: {e}")

    print("Exiting Server Thread")

# Host loop to handle user commands
def host_loop():
    while True:
        command_line = make_prompt()
        commands = command_line.split(" ")
        if len(commands) > 0:
            if commands[0] == "push":
                execute_push(commands)
            elif commands[0] == "remove":
                execute_remove(commands)
            elif commands[0] == "show":
                execute_show(commands)
            elif commands[0] == "exit":
                print("Thread Exiting")
                sys.exit(0)
            else:
                print("Please enter a valid command!")

# Function to load pushes from file
def load_pushes():
    if os.path.exists("pushes.txt"):
        with open("pushes.txt", "r") as push_file:
            for line in push_file:
                data = line.strip().split(",")
                pushes.append([data[0], data[1]])

# Main function
def main():
    print("Starting Deli Label Maker server")
    print("--------------------------------")
    load_pushes()

    # Create threads for server and host
    server_thread = threading.Thread(target=server_loop)
    host_thread = threading.Thread(target=host_loop)

    server_thread.start()
    host_thread.start()

    host_thread.join()
    global EXIT
    EXIT = True
    server_thread.join()

    print("Exiting Program")

if __name__ == "__main__":
    main()
