# run pip3 install requests
import requests
import json
import os
from signal import signal, SIGINT
from sys import exit

# API_ENDPOINT = "https://etud.insa-toulouse.fr/~proximo/ajax/zapette.php"
API_ENDPOINT = "http://localhost/proximo/ajax/zapette.php"

class bcolors:
    HEADER = '\033[95m'
    OKBLUE = '\033[94m'
    OKGREEN = '\033[92m'
    WARNING = '\033[93m'
    FAIL = '\033[91m'
    ENDC = '\033[0m'
    BOLD = '\033[1m'
    UNDERLINE = '\033[4m'

class scan_types:
    SELL = 'v',
    BUY = 'a',

class error_types:
    NONE = 0,
    NETWORK = 1,
    URL = 2,
    INPUT = 3,
    NO_EXIST = 4,

class Scanner:

    def __init__(self):
        self.ask_type()
        self.password = self.get_password()
        self.scannedArticles = []

    def ask_type(self):
        typeInput = input("\nVoulez vous " + bcolors.OKGREEN + "acheter" + bcolors.ENDC + " ou " + bcolors.FAIL + "vendre" + bcolors.ENDC + " ? [" + bcolors.OKGREEN + "a" + bcolors.ENDC + "/" + bcolors.FAIL + "v" + bcolors.ENDC + "] ")
        if (typeInput.lower() == 'a'):
            self.type = scan_types.BUY
        else:
            self.type = scan_types.SELL

    def get_password(self):
        with open('pass') as f:
            password = f.readline()
        return password.strip()

    def display_type(self):
        if (self.type == scan_types.SELL):
            print("    ==> Mode " + bcolors.FAIL + bcolors.BOLD + "VENTE")
        else:
            print("    ==> Mode " + bcolors.OKGREEN + bcolors.BOLD + "ACHAT")
        print(bcolors.ENDC)

    def scan_product(self, code):
        data = {
            'password': self.password,
            'action': 'scan',
            'data': str(code)
        }
        r = requests.post(url=API_ENDPOINT, data=json.dumps(data))
        if (r.json()['status'] == 0):
            article = r.json()["data"]
            self.scannedArticles.append(article)
        return r.json()['status'] == 0

    def display_cart(self):
        total = 0.0
        for article in self.scannedArticles:
            print(article["name"] + ' : ' + bcolors.BOLD + article["price"] + '€' + bcolors.ENDC)
            total += float(article["price"])
        # Print only to only 2 decimals
        total_display = "{:.2f}".format(total)
        print(bcolors.OKGREEN + "Total: " + bcolors.BOLD + total_display + '€' + bcolors.ENDC)

    def send_cart(self):
        scanned_list = []
        modifier = -1 if self.type == scan_types.SELL else 1
        for article in self.scannedArticles:
            scanned_list.append({"id": article["id"], "quantity": modifier})
        data = {
            'password': self.password,
            'action': 'validate',
            'data': scanned_list
        }
        r = requests.post(url=API_ENDPOINT, data=json.dumps(data))
        return r.json()['status'] == 0

def ask_confirmation(message):
    confirm_input = input(message)
    return confirm_input.lower() == 'o'

def clear_screen():
    os.system('clear')
    print("Appuyez sur " + bcolors.BOLD + "[CTRL + C]" + bcolors.ENDC + " à tout moment pour quitter.\n")

def printStartScreen():
    clear_screen()
    print(bcolors.BOLD)
    print(bcolors.WARNING + "#########################################")
    print("#/                                     \#")
    print("#            " + bcolors.FAIL + "-=|" + bcolors.OKGREEN + " ZAPETTE " + bcolors.FAIL + "|=-" + bcolors.WARNING + "            #")
    print("#\                                     /#")
    print("#########################################")
    print(bcolors.ENDC)
    print("Bienvenue dans le programme de la Zapette !")

def display_scan_header(scanner, last_error):
    clear_screen()
    scanner.display_type()
    print("Scannez le codes puis appuyez sur [ENTRÉE] pour valider.")
    print("Appuyez sur [ENTRÉE] sans code pour valider la commande.\n")
    scanner.display_cart()
    if (last_error == error_types.URL):
        print(bcolors.FAIL + "Format URL invalide !" + bcolors.ENDC)
    elif (last_error == error_types.NETWORK):
        print(bcolors.FAIL + "URL invalide !" + bcolors.ENDC)
    elif (last_error == error_types.INPUT):
       print(bcolors.FAIL + "Code invalide !" + bcolors.ENDC)
    elif (last_error == error_types.NO_EXIST):
       print(bcolors.FAIL + "L'article n'existe pas." + bcolors.ENDC)
    print()

def confirm_end_scan(scanner):
    display_scan_header(scanner, error_types.NONE)
    return ask_confirmation("Voulez vous vraiment terminer et envoyer les modifications ? [o/n] ")

def handler(signal_received, frame):
    os.system('clear')
    print('Programme de la zapette terminé.')
    exit(0)

def validate_cart(scanner):
    clear_screen()
    print("Envoi des modifications au serveur...")
    if (scanner.send_cart()):
        print(bcolors.OKGREEN + bcolors.BOLD + "Succès !" + bcolors.ENDC)
    else:
        print(bcolors.FAIL + bcolors.BOLD + "Échec !" + bcolors.ENDC)
    input("\nAppuyez sur [ENTRÉE] pour continuer...")

def main():
    signal(SIGINT, handler)
    printStartScreen()
    while True:
        scanner = Scanner()
        last_error = error_types.NONE
        while True:
            display_scan_header(scanner, last_error)
            code_input = input('=> ')
            if (code_input == ""):
                if (confirm_end_scan(scanner)):
                    validate_cart(scanner)
                    break
                else:
                    continue
            try:
                code = int(code_input)
                if (scanner.scan_product(code)):
                    last_error = error_types.NONE
                else:
                    last_error = error_types.NO_EXIST
            except requests.exceptions.MissingSchema:
                last_error = error_types.URL
            except requests.exceptions.ConnectionError:
                last_error = error_types.NETWORK
            except ValueError:
                last_error = error_types.INPUT
        clear_screen()

main()
