from users import register_user, is_login_successful
from psql import query, query_no_fetch, make_safe
from meds import query_all_table, query_delete, query_web, add_to_db, query_table
from barcode import scan_barcode
from ordermed import send_pharmacy_email, send_pharmacy_request
from kivymd.app import MDApp
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.metrics import dp
import requests
import datetime
import time
import os


#Load the Kivy File (which does all the formatting)
Builder.load_file("app.kv")


#Declare all available screens
class LoginScreen(Screen):
    pass
class MainScreen(Screen):
    pass
class CameraClickScreen(Screen):
    pass
class CabinetScreen(Screen):
    pass
class AddScreen(Screen):
    pass


#Define all functionalities of the app
class Main(MDApp):

    #Root variables that are accessible from all screens
    username = ""
    string_to_check = ""
    mapping = ""
    meds = ""

    def build(self):
        """
        Called: When the App is first started.
        Create the Screen Manager (enables functionalities to switch between
        different screens in the app).
        """
        sm = ScreenManager()
        sm.add_widget(LoginScreen(name='loginScreen'))
        sm.add_widget(MainScreen(name='mainScreen'))
        sm.add_widget(CameraClickScreen(name='cameraClickScreen'))
        sm.add_widget(CabinetScreen(name='cabinetScreen'))
        sm.add_widget(AddScreen(name='addScreen'))
        return sm

    def auth(self):
        """
        Called: When the Button to login in the app is pressed.
        Uses the is_login_successful function from users.py to check the password
        and prints different messages / switches to the main screen on success.
        """
        x, uname = is_login_successful(self.root.get_screen('loginScreen').ids.uname.text, self.root.get_screen('loginScreen').ids.psword.text)
        if x == "username_not_found":
            label = self.root.get_screen('loginScreen').ids.show
            label.text = "Username Not Found"
        elif x == "wrong_password":
            label = self.root.get_screen('loginScreen').ids.show
            label.text = "Wrong password"
        elif x == "correct_password":
            label = self.root.get_screen('loginScreen').ids.show
            label.text = "Correct Password " + str(uname)
            self.root.username = uname
            self.root.current = 'mainScreen'

    def reg(self):
        """
        Called: When the Button to register is pressed.
        Uses the register_user function from users.py to check all fields and prints different
        messages / deletes everything on success so the user can log in.
        """
        x = register_user(self.root.get_screen('loginScreen').ids.uname.text,
                                    self.root.get_screen('loginScreen').ids.psword.text,
                                    self.root.get_screen('loginScreen').ids.name.text,
                                    self.root.get_screen('loginScreen').ids.street.text,
                                    self.root.get_screen('loginScreen').ids.postal.text,
                                    self.root.get_screen('loginScreen').ids.city.text,
                                    self.root.get_screen('loginScreen').ids.country.text)
        if x == "already_exists":
            label = self.root.get_screen('loginScreen').ids.show
            label.text = "That user handle is already taken!"
        elif x == "fill_out_all":
            label = self.root.get_screen('loginScreen').ids.show
            label.text = "Fill out all fields!"
        elif x == "user_registered":
            self.root.get_screen('loginScreen').ids.uname.text = ''
            self.root.get_screen('loginScreen').ids.psword.text = ''
            self.root.get_screen('loginScreen').ids.name.text = ''
            self.root.get_screen('loginScreen').ids.street.text = ''
            self.root.get_screen('loginScreen').ids.postal.text = ''
            self.root.get_screen('loginScreen').ids.city.text = ''
            self.root.get_screen('loginScreen').ids.country.text = ''
            label = self.root.get_screen('loginScreen').ids.show
            label.text = "Created User!"

    def logOut(self):
        """
        Called: When the Button to log out is pressed.
        Empties all fields in the login screen and switches to the login screen.
        """
        self.root.username = ""
        self.root.get_screen('loginScreen').ids.uname.text = ''
        self.root.get_screen('loginScreen').ids.psword.text = ''
        self.root.get_screen('loginScreen').ids.name.text = ''
        self.root.get_screen('loginScreen').ids.street.text = ''
        self.root.get_screen('loginScreen').ids.postal.text = ''
        self.root.get_screen('loginScreen').ids.city.text = ''
        self.root.get_screen('loginScreen').ids.country.text = ''
        label = self.root.get_screen('loginScreen').ids.show
        label.text = ''
        self.root.current = 'loginScreen'

    def goBack(self):
        """
        Called: When the Button to go back is pressed.
        Switches to the main screen.
        """
        self.root.current = 'mainScreen'

    def openScanner(self):
        """
        Called: When the Button to start a scan is pressed.
        Switches to the scan screen.
        """
        self.root.current = 'cameraClickScreen'

    def capture(self):
        """
        Called: When the Button in the scan screen to capture a photo is pressed.
        Stores the photo with a unique name, uses the scan_barcode function from
        barcode.py to retrieve the gtin from the photo and deletes the photo again.
        Queries the web with the query_web function from meds.py to retrieve the name
        of this medicine adds the current date as buydate and checks if medicines with
        this substance (same number from swissmedic) already are in our cabinet. It
        then stores all those variables on the add screen and switches to the add screen.
        """
        camera = self.root.get_screen('cameraClickScreen').ids['camera']
        timestr = time.strftime("%Y%m%d_%H%M%S")
        img_name = "IMG_{}.png".format(timestr)
        camera.export_to_png(img_name)
        gtin = scan_barcode(img_name)
        try:
            os.remove(img_name)
        except:
            pass
        med_name, gtin = query_web(gtin)
        if not med_name and not gtin:
            print("gtin invalid")
        elif not med_name and gtin:
            print("no results")
            self.root.current = 'mainScreen'
        else:
            buy_date = datetime.datetime.today().date()
            buy_date = buy_date.strftime('%d.%m.%Y')
            smid = gtin[4:9]
            self.root.get_screen('addScreen').ids.show.text = ''
            self.root.get_screen('addScreen').ids.exp_date.text = ''
            self.root.get_screen('addScreen').ids.show_medname.text = med_name
            self.root.get_screen('addScreen').ids.show_buydate.text = buy_date
            self.root.get_screen('addScreen').ids.show_gtin.text = gtin
            self.root.get_screen('addScreen').ids.show_smid.text = smid
            meds = query_table(self.root.username, smid)
            self.root.get_screen('addScreen').ids.youHave.text = 'YOU HAVE:'
            self.root.get_screen('addScreen').ids.youAdd.text = 'YOU WANT TO ADD:'
            if not meds:
                self.root.get_screen('addScreen').ids.medCabinet.text = ''
            else:
                s = ""
                for med in meds:
                    s += str(med[2]) + "\n" + "Expires: " + med[4].strftime('%d.%m.%Y') + "\n"
                self.root.get_screen('addScreen').ids.medCabinet.text = s
            self.root.current = 'addScreen'

    def openCabinet(self):
        """
        Called: When the Button to open the cabinet is pressed.
        Deletes all previous variables in the cabinet screen and uses the query_all_table function
        from meds.py to return all medicines that are currently in the cabinet of the user. It then
        stores these medicines in a variable in the cabinet_screen and switches to the cabinet screen.
        """
        self.root.get_screen('cabinetScreen').ids.deleteMed.text = ''
        self.root.get_screen('cabinetScreen').ids.show.text = ''
        meds, mapping = query_all_table(self.root.username)
        self.root.meds = meds
        self.root.mapping = mapping
        s = ""
        for number, med in enumerate(meds):
            s += str(number+1) + " : " + str(med[2]) + "   Bought: " + med[3].strftime('%d.%m.%Y') + "   Expires: " + med[4].strftime('%d.%m.%Y') + "\n"
        self.root.get_screen('cabinetScreen').ids.medCabinet.text = s
        self.root.current = 'cabinetScreen'

    def deleteNr(self):
        """
        Called: When the Button in the cabinet screen to delete a medicine from the cabinet is pressed.
        Uses the mapping from the function above and deletes the medicine with this number.
        If the given number is invalid the user is asked to provide a new number.
        """
        mapping = self.root.mapping
        try:
            real_index = mapping[int(self.root.get_screen('cabinetScreen').ids.deleteMed.text)]
            query_delete(real_index)
            self.root.current = 'mainScreen'
        except:
            self.root.get_screen('cabinetScreen').ids.show.text = "Enter an existing Nr."

    def reorderNr(self):
        """
        Called: When the Button in the cabinet screen to reorder a medicine from the cabinet is pressed.
        Also uses the mapping from above and reorders the medicine with this number by
        retrieving information about this medicine in the meds table and information about
        the user in the users table and then using send_pharmacy_email and send_pharmacy_request
        from ordermed.py. If the given number is invalid the user is asked to provide a new number.
        """
        mapping = self.root.mapping
        meds = self.root.meds
        try:
            real_index = mapping[int(self.root.get_screen('cabinetScreen').ids.deleteMed.text)]
            med_response = query("SELECT username, medname, gtin FROM meds WHERE id='{}'".format(real_index))
            med_response_user = med_response[0][0]
            user_response = query("SELECT * FROM users WHERE username='{}'".format(med_response_user))
            mailing_list = [med_response[0][1], med_response[0][2], user_response[0][2], user_response[0][3], user_response[0][4], user_response[0][5], user_response[0][6]]
            a = send_pharmacy_email(mailing_list)
            print(a.content)
            b = send_pharmacy_request(mailing_list)
            print(b.text)
            self.root.current = 'mainScreen'
        except:
            self.root.get_screen('cabinetScreen').ids.show.text = "Enter an existing Nr."

    def addMed(self):
        """
        Called: When the Button in the add screen to add a medicine to the cabinet is pressed.
        Uses the username (root variable) and all the information stored in the variables in the add screen
        and checks if the expiry date was entered in a valid format. It then transforms it from e.g. 02.2022
        to 01.03.2022 because this is the first day the medicine will be expired. If all of that worked
        the new medicine is added to the table meds and it switches to the main screen.
        """
        uname = self.root.username
        med_name = self.root.get_screen('addScreen').ids.show_medname.text
        buy_date = self.root.get_screen('addScreen').ids.show_buydate.text
        buy_date = datetime.datetime.strptime(buy_date, '%d.%m.%Y')
        buy_date = buy_date.strftime('%Y-%m-%d')
        gtin = self.root.get_screen('addScreen').ids.show_gtin.text
        smid = self.root.get_screen('addScreen').ids.show_smid.text
        expiry_date = self.root.get_screen('addScreen').ids.exp_date.text
        try:
            int(expiry_date[0:2])
            int(expiry_date[3:])
            if len(expiry_date) == 7 and expiry_date[2] == ".":
                expiry_month = expiry_date[:2]
                expiry_year = expiry_date[3:]
                if expiry_month == "12":
                    expiry_month = "01"
                    expiry_year = str(int(expiry_year)+1)
                else:
                    expiry_month = str(int(expiry_month)+1)
                expiry_date = "01.{}.{}".format(expiry_month, expiry_year)
                expiry_date = datetime.datetime.strptime(expiry_date, "%d.%m.%Y")
                expiry_date = expiry_date.strftime('%Y-%m-%d')
                add_to_db(uname, med_name, buy_date, expiry_date, gtin, smid)
                self.root.current = 'mainScreen'
            else:
                self.root.get_screen('addScreen').ids.exp_date.text = ''
                self.root.get_screen('addScreen').ids.show.text = "Enter a valid expiration date"
        except:
            self.root.get_screen('addScreen').ids.exp_date.text = ''
            self.root.get_screen('addScreen').ids.show.text = "Enter a valid expiration date"


#Start the App
Main().run()
