# Pode correr o programa sem argumentos:
#   python3 shop
# ou passando outros ficheiros de produtos como argumento:
#   python3 shop produtos1.txt ...

def loadDataBase(fname, produtos):
    """Lê dados do ficheiro fname e atualiza/acrescenta a informação num
    dicionário de produtos com o formato {código: (nome, secção, preço, iva), ...}.
    """
    with open(fname, 'r') as f:                               # Abre o ficheiro em modo de leitura
        productsFileContent = f.read()                        # Cria uma string com o conteudo do ficheiro

    for product in productsFileContent.split('\n')[1:]:       # Divide a string 'productsFileContent' numa lista com cada produto
        productComponents = product.split(';')                # Divide as componentes do produto (código, nome, secção, preço, iva)

        if len(productComponents) != 5:
            continue

        produtos.update({productComponents[0]: (              # Atualiza a entrada de uma determinada chave (código)
            productComponents[1],                             # Nome
            productComponents[2],                             # Secção
            float(productComponents[3]),                      # Preço
            float(productComponents[4].strip('%')) / 100      # IVA
        )})


def registaCompra(produtos):
    """Lê códigos de produtos (ou códigos e quantidades),
    mostra nome, quantidade e preço final de cada um,
    e devolve dicionário com {codigo: quantidade, ...}
    """
    compra = {"totals": [0, 0, 0]}     # Inicia o dicionário da compra com os totais da mesma: [total bruto, total iva, total liquido]
    userInput = input('Code? ')
    while userInput != "":
        try:
            code, amount = userInput.split(' ')              # Divide o input do utilizador no código e na quantia
        except ValueError:
            code, amount = userInput, 1                      # No caso de não ser introduzida quantia, então ela fica 1

        # Caso a segunda parcela da entrada não seja um número, é pedido ao utilizador para introduzir o código de novo
        try:
            amount = int(amount)
        except ValueError:
            userInput = input('Code? ')
            continue

        if code in produtos:
            if code not in compra:                                        # Se o produto ainda não estiver na lista é adicionado à mesma
                compra[code] = 0

            compra[code] += amount                                        # Adiciona ao dicionário da compra a quantidade comprada do produto
            noIvaPrice = produtos[code][2] * amount                       # Obtém o preço (sem iva) do determinado produto
            compra["totals"][0] += noIvaPrice                             # Adiciona o preço sem iva ao total bruto
            compra["totals"][1] += noIvaPrice * produtos[code][3]         # Adiciona o valor do iva ao total iva
            print(f"{produtos[code][0]}  {amount}  {noIvaPrice * (1+produtos[code][3]):.2f}")

        userInput = input('Code? ')

    compra["totals"][2] += compra["totals"][0] + compra["totals"][1]      # Calcula o total liquido da compra
    return compra    # Devolve a lista


def fatura(produtos, compra):
    """Imprime a fatura de uma dada compra."""

    # Obtém a lista de secções presentes na compra (por ordem alfabética)
    sections = sorted(list({section for section in [product[1] for code, product in produtos.items() if code in compra]}))

    # Itera as secções para apresentar os produtos ordenados por secção
    for section in sections:
        print(section)     # Mostra a secção

        # Obtém a lista de codigos usados na compra presentes na secção atual
        sectionProductsCodes = sorted([code for code in produtos if produtos[code][1] == section and code in compra])

        # Itera os códigos para apresentar as informações de cada produto
        for code in sectionProductsCodes:
            print(f"{compra[code]:>4} {produtos[code][0]:<31}({int(produtos[code][3]*100):>2}%){round(compra[code]*produtos[code][2]*(1+produtos[code][3]), 2):>11}")

    # Apresenta os totais da compra
    print(f"""{'Total Bruto:':>41}{round(compra["totals"][0], 2):>11}
{'Total IVA:':>41}{round(compra["totals"][1], 2):>11}
{'Total Liquido:':>41}{round(compra["totals"][2], 2):>11}""")


def main(args):
    # produtos guarda a informação da base de dados numa forma conveniente.
    produtos = {'p1': ('Ketchup.', 'Mercearia Salgado', 1.59, 0.23)}
    # Carregar base de dados principal
    loadDataBase("produtos.txt", produtos)
    # Juntar bases de dados opcionais (Não altere)
    for arg in args:
        loadDataBase(arg, produtos)
    
    # Use este código para mostrar o menu e ler a opção repetidamente
    MENU = "(C)ompra (F)atura (S)air ? "
    compras = {}
    repetir = True
    while repetir:
        # Utilizador introduz a opção com uma letra minúscula ou maiúscula
        op = input(MENU).upper()
        # Processar opção
        if op == "C":
            # Esta opção regista os produtos de uma compra
            compras[len(compras)+1] = registaCompra(produtos)

        elif op == "F":
            # Esta opção apresenta a fatura de uma compra
            try:
                numCompra = int(input("Numero compra? "))
                fatura(produtos, compras[numCompra])
            except:
                continue

        elif op == "S":
            repetir = False

    print("Obrigado!")


# Não altere este código / Do not change this code
import sys
if __name__ == "__main__":
    main(sys.argv[1:])