# NLP Program with Functions for Q1, Q2, Q3
import nltk
import string
import matplotlib.pyplot as plt
from nltk.corpus import stopwords, wordnet as wn
from nltk.stem import WordNetLemmatizer
from sklearn.feature_extraction.text import CountVectorizer, TfidfVectorizer
from nltk.util import ngrams
from collections import Counter
import spacy
from textblob import TextBlob
from gensim.models import Word2Vec
from sklearn.decomposition import PCA
import numpy as np

# Download required NLTK packages
nltk.download('all')

# Load Spacy model
nlp = spacy.load("en_core_web_sm")

# ----------------- Q1: Text Preprocessing & Representation -----------------
def q1_text_preprocessing(text):
    text_lower = text.lower()
    text_no_punc = text_lower.translate(str.maketrans('', '', string.punctuation))
    tokens = nltk.word_tokenize(text_no_punc)
    stop_words = set(stopwords.words('english'))
    tokens = [w for w in tokens if w not in stop_words]
    lemmatizer = WordNetLemmatizer()
    tokens = [lemmatizer.lemmatize(w) for w in tokens]

    print("Preprocessed Tokens:\n", tokens)

    cv = CountVectorizer()
    bow = cv.fit_transform([text])
    print("\nBag of Words Representation:\n", bow.toarray())

    tfidf = TfidfVectorizer()
    tfidf_matrix = tfidf.fit_transform([text])
    print("\nTF-IDF Representation:\n", tfidf_matrix.toarray())

    plt.figure(figsize=(8,5))
    plt.bar(cv.get_feature_names_out(), bow.toarray()[0])
    plt.title("Bag of Words Visualization")
    plt.xticks(rotation=45)
    plt.show()

# ----------------- Q2: Semantic Understanding & Language Modeling -----------------
def q2_semantic_language(word, sample_text):
    synonyms = [syn.lemmas()[0].name() for syn in wn.synsets(word)]
    antonyms = [ant.name() for syn in wn.synsets(word) for ant in syn.lemmas()[0].antonyms()]
    hypernyms = [hyp.name().split('.')[0] for syn in wn.synsets(word) for hyp in syn.hypernyms()]

    print(f"Word: {word}")
    print("Synonyms:", synonyms)
    print("Antonyms:", antonyms)
    print("Hypernyms:", hypernyms)

    tokens = sample_text.lower().split()
    bigrams = list(ngrams(tokens, 2))
    bigram_counts = Counter(bigrams)
    unigram_counts = Counter(tokens)
    vocab_size = len(set(tokens))
    laplace_prob = lambda bigram: (bigram_counts[bigram]+1) / (unigram_counts[bigram[0]] + vocab_size)

    print("\nBigram Probabilities with Laplace Smoothing:")
    for bigram in bigrams:
        print(f"{bigram}: {laplace_prob(bigram):.4f}")

# ----------------- Q3: Information Extraction & Sentiment Analysis -----------------
def q3_info_sentiment(text, sentiment_text, sentences_for_w2v):
    doc = nlp(text)
    print("Named Entities:")
    for ent in doc.ents:
        print(ent.text, ent.label_)

    sentiment = TextBlob(sentiment_text).sentiment
    print("\nSentiment Polarity:", sentiment.polarity)
    if sentiment.polarity > 0:
        print("Positive")
    elif sentiment.polarity < 0:
        print("Negative")
    else:
        print("Neutral")

    w2v_model = Word2Vec(sentences_for_w2v, vector_size=50, window=2, min_count=1, workers=4)
    words = list(w2v_model.wv.index_to_key)
    X = w2v_model.wv[words]
    pca = PCA(n_components=2)
    result = pca.fit_transform(X)

    plt.figure(figsize=(8,6))
    plt.scatter(result[:,0], result[:,1])
    for i, word in enumerate(words):
        plt.annotate(word, xy=(result[i,0], result[i,1]))
    plt.title("Word2Vec Embedding Visualization")
    plt.show()

# ----------------- Example Usage -----------------
if __name__ == "__main__":
    text_q1 = """Natural Language Processing (NLP) is a sub-field of artificial intelligence that focuses on 
    the interaction between computers and humans through natural language."""
    q1_text_preprocessing(text_q1)

    word_q2 = "good"
    sample_text_q2 = "I love natural language processing and I love machine learning"
    q2_semantic_language(word_q2, sample_text_q2)

    ner_text = "Apple is looking at buying U.K. startup for $1 billion"
    sentiment_text = "I love AI but I hate bugs in the code"
    sentences_w2v = [["natural", "language", "processing", "is", "fun"],
                     ["I", "love", "machine", "learning"]]
    q3_info_sentiment(ner_text, sentiment_text, sentences_w2v)
