import string

import pyttsx3
import speech_recognition as sr  # recognise speech
import playsound  # to play an audio file
from gtts import gTTS  # google text to speech
import random
from time import ctime  # get time details
import webbrowser  # open browser
import ssl
import certifi
import time
import os  # to remove created audio files
from PIL import Image
import subprocess
import pyautogui  # screenshot
# import pyttsx3
import bs4 as bs
import urllib.request
import requests
import warnings
import nltk


# ignore anny warnings
from newspaper import Article
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity

warnings.filterwarnings('ignore')

# Download pckgs from nltk
nltk.download('punkt', quiet=True)
nltk.download('wordnet', quiet=True)

# Get Artclie url
article = Article('https://www.mayoclinic.org/diseases-conditions/coronavirus/symptoms-causes/syc-20479963')
article.download()
article.parse()
article.nlp()
corpus = article.text

# tockenization
text = corpus
sent_tokens = nltk.sent_tokenize(text)  # convert the text into a list of sentences

# create a dictionary(key: value) pair to remove punctuations
remove_punct_dict = dict((ord(punct), None) for punct in string.punctuation)

def lemNormalize(text):
    return nltk.word_tokenize(text.lower().translate(remove_punct_dict))

class person:
    name = ''

    def setName(self, name):
        self.name = name


class asis:
    name = ''

    def setName(self, name):
        self.name = name


def there_exists(terms):
    for term in terms:
        if term in voice_data:
            return True

there_exists_implicit = ['well done betty']


def engine_speak(text):
    text = str(text)
    engine.say(text)
    engine.runAndWait()


r = sr.Recognizer()  # initialise a recogniser

def speak(text):
    tts = gTTS(text=text, lang='en')
    filename = 'voice.mp3'
    tts.save(filename)
    playsound.playsound(filename)
    os.remove(filename)


def response(user_response):
    # the users response/query
    # user_response = 'What is coronavirus disease'

    user_response = user_response.lower()

    # print(user_response)

    robo_response = ' '

    # Append the users response to the sentense list
    sent_tokens.append(user_response)

    # print the sentence list after appending the users response
    # print(sent_tokens)

    # create a TfidVectorizer obj
    TfidVec = TfidfVectorizer(tokenizer=lemNormalize, stop_words='english')

    # Convert the text to a matrix of TF-IDf features
    tfidf = TfidVec.fit_transform(sent_tokens)

    # print the TFIDF FEATURES
    # print(tfidf)

    # get the measure of the simmilarity
    # vals = cosine_similarity(tfidf[-1],tfdif)
    vals = cosine_similarity(tfidf[-1], tfidf)

    # print(vals)

    # get the index of thmost similar text/sentence to the users response
    idx = vals.argsort()[0][-2]

    # print(idx)

    # reduce the dimensionality of vals
    flat = vals.flatten()

    # sort the list in ascending order
    flat.sort()

    # get the most similar score to the users response
    score = flat[-2]

    # print th simmilarity score
    # print(score)

    # if val 'score' is 0 then there's no similar to the users response
    if (score == 0):
        robo_response = robo_response + 'I apologize, I don\'t understand'
    else:
        robo_response = robo_response + sent_tokens[idx]

    # print the th bot response
    # print(robo_response)

    sent_tokens.remove(user_response)

    # def speak(user_response):
    #     reply = gTTS(text=user_response, lang='en')
    #     # tts = gTTS(text=text, lang='en')
    #     filename = 'voice.mp3'
    #     tts.save(filename)
    #     playsound.playsound(filename)
    #
    #     speak(robo_response)

    return robo_response


# listen for audio and convert it to text:
def record_audio(ask=""):

    with sr.Microphone() as source:  # microphone as source
        if ask:
            engine_speak(ask)
        audio = r.listen(source, 5, 5)  # listen for the audio via source
        print("Done Listening")
        voice_data = ''
        try:
            voice_data = r.recognize_google(audio)  # convert audio to text
        except sr.UnknownValueError:  # error: recognizer does not understand
            engine_speak('I did not get that')
        except sr.RequestError:
            engine_speak('Sorry, the service is down')  # error: recognizer is not connected
        print(">>", voice_data.lower())  # print what user said
        return voice_data.lower()

flag = True
while flag == True:
    intro = 'I am Betty, I will answer your queries about Corona virus.'
    print(f'Betty: {intro}')
    speak(intro)
    # flag=False
    break


# get string and make a audio file to be played
def engine_speak(audio_string):
    audio_string = str(audio_string)
    tts = gTTS(text=audio_string, lang='en')  # text to speech(voice)
    r = random.randint(1, 20000000)
    audio_file = 'audio' + str(r) + '.mp3'
    tts.save(audio_file)  # save as mp3
    playsound.playsound(audio_file)  # play the audio file
    print(asis_obj.name + ":", audio_string)  # print what app said
    os.remove(audio_file)  # remove audio file

# userResponse = voice_data

def respond(voice_data):

    # 1: greeting
    if there_exists(['hey', 'hi', 'hello']):
        greetings = ["hey, how can I help you" + person_obj.name, "hey, what's up?" + person_obj.name,
                     "I'm listening" + person_obj.name, "how can I help you?" + person_obj.name,
                     "hello" + person_obj.name]
        greet = greetings[random.randint(0, len(greetings) - 1)]
        engine_speak(greet)

    # 2: name
    if there_exists(["what is your name", "what's your name", "tell me your name"]):

        if person_obj.name:
            engine_speak(f"My name is {asis_obj.name}, {person_obj.name}")  # gets users name from voice input
        else:
            engine_speak(f"My name is {asis_obj.name}. what's your name?")  # incase you haven't provided your name.

    if there_exists(["my name is"]):
        person_name = voice_data.split("is")[-1].strip()
        engine_speak("okay, i will remember that " + person_name)
        person_obj.setName(person_name)  # remember name in person object

    if there_exists(["what is my name"]):
        engine_speak("Your name must be " + person_obj.name)

    if there_exists(["your name should be"]):
        asis_name = voice_data.split("be")[-1].strip()
        engine_speak("okay, i will remember that my name is " + asis_name)
        asis_obj.setName(asis_name)  # remember name in asis object

    # 3: greeting
    if there_exists(["how are you", "how are you doing"]):
        engine_speak("I'm very well, thanks for asking " + person_obj.name)

    # 4: time
    if there_exists(["what's the time", "tell me the time", "what time is it", "what is the time"]):
        time = ctime().split(" ")[3].split(":")[0:2]
        if time[0] == "00":
            hours = '12'
        else:
            hours = time[0]
        minutes = time[1]
        time = hours + " hours and " + minutes + "minutes"
        engine_speak(time)

    # 5: search google
    if there_exists(["search for"]) and 'youtube' not in voice_data:
        search_term = voice_data.split("for")[-1]
        url = "https://google.com/search?q=" + search_term
        webbrowser.get().open(url)
        engine_speak("Here is what I found for" + search_term + "on google")

    if there_exists(["search"]) and 'youtube' not in voice_data:
        search_term = voice_data.replace("search", "")
        url = "https://google.com/search?q=" + search_term
        webbrowser.get().open(url)
        engine_speak("Here is what I found for" + search_term + "on google")

    # 6: search youtube
    if there_exists(["youtube"]):
        search_term = voice_data.split("for")[-1]
        search_term = search_term.replace("on youtube", "").replace("search", "")
        url = "https://www.youtube.com/results?search_query=" + search_term
        webbrowser.get().open(url)
        engine_speak("Here is what I found for " + search_term + "on youtube")

    # 7: get stock price
    if there_exists(["price of"]):
        search_term = voice_data.split("for")[-1]
        url = "https://google.com/search?q=" + search_term
        webbrowser.get().open(url)
        engine_speak("Here is what I found for " + search_term + " on google")

    # 8 time table
    if there_exists(["show my time table"]):
        im = Image.open(r"D:\WhatsApp Image 2019-12-26 at 10.51.10 AM.jpeg")
        im.show()

    # 9 weather
    if there_exists(["weather"]):
        search_term = voice_data.split("for")[-1]
        url = "https://www.google.com/search?sxsrf=ACYBGNSQwMLDByBwdVFIUCbQqya-ET7AAA%3A1578847393212&ei=oUwbXtbXDN-C4-EP-5u82AE&q=weather&oq=weather&gs_l=psy-ab.3..35i39i285i70i256j0i67l4j0i131i67j0i131j0i67l2j0.1630.4591..5475...1.2..2.322.1659.9j5j0j1......0....1..gws-wiz.....10..0i71j35i39j35i362i39._5eSPD47bv8&ved=0ahUKEwiWrJvwwP7mAhVfwTgGHfsNDxsQ4dUDCAs&uact=5"
        webbrowser.get().open(url)
        engine_speak("Here is what I found for on google")

    # 10 stone paper scisorrs
    if there_exists(["game"]):
        voice_data = record_audio("choose among rock paper or scissor")
        moves = ["rock", "paper", "scissor"]

        cmove = random.choice(moves)
        pmove = voice_data

        engine_speak("The computer chose " + cmove)
        engine_speak("You chose " + pmove)
        # engine_speak("hi")
        if pmove == cmove:
            engine_speak("the match is draw")
        elif pmove == "rock" and cmove == "scissor":
            engine_speak("Player wins")
        elif pmove == "rock" and cmove == "paper":
            engine_speak("Computer wins")
        elif pmove == "paper" and cmove == "rock":
            engine_speak("Player wins")
        elif pmove == "paper" and cmove == "scissor":
            engine_speak("Computer wins")
        elif pmove == "scissor" and cmove == "paper":
            engine_speak("Player wins")
        elif pmove == "scissor" and cmove == "rock":
            engine_speak("Computer wins")

    # 11 toss a coin
    if there_exists(["toss", "flip", "coin"]):
        moves = ["head", "tails"]
        cmove = random.choice(moves)
        engine_speak("The computer chose " + cmove)

    # 12 calc
    if there_exists(["plus", "minus", "multiply", "divide", "power", "+", "-", "*", "/"]):
        opr = voice_data.split()[1]

        if opr == '+':
            engine_speak(int(voice_data.split()[0]) + int(voice_data.split()[2]))
        elif opr == '-':
            engine_speak(int(voice_data.split()[0]) - int(voice_data.split()[2]))
        elif opr == 'multiply' or 'x':
            engine_speak(int(voice_data.split()[0]) * int(voice_data.split()[2]))
        elif opr == 'divide':
            engine_speak(int(voice_data.split()[0]) / int(voice_data.split()[2]))
        elif opr == 'power':
            engine_speak(int(voice_data.split()[0]) ** int(voice_data.split()[2]))
        else:
            engine_speak("Wrong Operator")

    # 13 screenshot
    if there_exists(["capture", "my screen", "screenshot"]):
        myScreenshot = pyautogui.screenshot()
        myScreenshot.save('D:/screenshot/screen.png')

    # 14 to search wikipedia for definition
    if there_exists(["definition of"]):
        definition = record_audio("what do you need the definition of")
        url = urllib.request.urlopen('https://en.wikipedia.org/wiki/' + definition)
        soup = bs.BeautifulSoup(url, 'lxml')
        definitions = []
        for paragraph in soup.find_all('p'):
            definitions.append(str(paragraph.text))
        if definitions:
            if definitions[0]:
                engine_speak('im sorry i could not find that definition, please try a web search')
            elif definitions[1]:
                engine_speak('here is what i found ' + definitions[1])
            else:
                engine_speak('Here is what i found ' + definitions[2])
        else:
            engine_speak("im sorry i could not find the definition for " + definition)

    if there_exists(["exit", "quit", "goodbye"]):
        engine_speak("bye")
        exit()

    # Current city or region
    if there_exists(["where am i"]):
        Ip_info = requests.get('https://api.ipdata.co?api-key=test').json()
        loc = Ip_info['region']
        engine_speak(f"You must be somewhere in {loc}")

        # Current location as per Google maps
    if there_exists(["what is my exact location"]):
        url = "https://www.google.com/maps/search/Where+am+I+?/"
        webbrowser.get().open(url)
        engine_speak("You must be somewhere near here, as per Google maps")

    #
    # if there_exists_implicit =='well done betty':
    #     engine_speak('Does that mean you like my skills?')
    #     if there_exists('yes'):
    #         engine_speak('Am humbled')

    if there_exists(['thanks','thank you','bye',]):
        engine_speak("you are welcome")
        exit()


    voice_data =voice_data.lower()

    robo_response =''

    # Append the users response to the sentense list
    sent_tokens.append(voice_data)

    # create a TfidVectorizer obj
    TfidVec = TfidfVectorizer(tokenizer=lemNormalize, stop_words='english')

    # Convert the text to a matrix of TF-IDf features
    tfidf = TfidVec.fit_transform(sent_tokens)

    # get the measure of the simmilarity
    # vals = cosine_similarity(tfidf[-1],tfdif)
    vals = cosine_similarity(tfidf[-1], tfidf)

    # get the index of thmost similar text/sentence to the users response
    idx = vals.argsort()[0][-2]

    # reduce the dimensionality of vals
    flat = vals.flatten()

    # sort the list in ascending order
    flat.sort()

    # get the most similar score to the users response
    score = flat[-2]



    # if val 'score' is 0 then there's no similar to the users response
    if (score == 0):
        robo_response = robo_response + 'Yes please, say something'
    else:
        robo_response = robo_response + sent_tokens[idx]

    sent_tokens.remove(voice_data)

    engine_speak(robo_response)


time.sleep(2)

person_obj = person()
asis_obj = asis()
asis_obj.name = 'Betty'
person_obj.name = ""
engine = pyttsx3.init()

while (2):
    voice_data = record_audio("Recording")  # get the voice input
    print("Done")
    print("Q:", voice_data)
    respond(voice_data)  # respond
