import os
import sys
import json
import re
import math

# === Step 1: Check if `requests` is installed ===
try:
    import requests
except ImportError:
    print("\n⚠️ `requests` module not found! Checking internet connection...\n")
    def check_connection():
        try:
            # Ping Bing as a connection test
            os.system("ping -c 1 bing.com >nul 2>&1")  # Linux/macOS
            os.system("ping -n 1 bing.com >nul 2>&1")   # Windows
            return True
        except Exception:
            return False

    online = check_connection()
    if online:
        print("\n🌐 Internet detected! Installing `requests`...\n")
        os.system("pip install requests")
        try:
            import requests
            print("\n✅ `requests` installed successfully!\n")
        except ImportError:
            print("\n🚨 Installation failed! Please install manually: `pip install requests`\n")
            sys.exit(1)
    else:
        print("\n🚨 No internet detected! Running in offline mode...\n")
        # Create a fake requests module to avoid crashes
        class FakeRequests:
            def get(self, url, timeout=5):
                return None
        requests = FakeRequests()

# === Step 2: Define the CGG-EUSO Chatbot with Enhanced Thinking Chain and NLP ===
class CGG_EUSO:
    def __init__(self):
        self.knowledge_file = "knowledge.json"
        self.responses_file = "responses.json"
        self.load_data()

    def load_data(self):
        """Loads stored knowledge and responses from files."""
        try:
            with open(self.knowledge_file, "r", encoding="utf-8") as f:
                self.knowledge = json.load(f)
        except FileNotFoundError:
            self.knowledge = {}
        try:
            with open(self.responses_file, "r", encoding="utf-8") as f:
                self.responses = json.load(f)
        except FileNotFoundError:
            self.responses = {}

    def save_data(self):
        """Saves learned knowledge and responses to files."""
        with open(self.knowledge_file, "w", encoding="utf-8") as f:
            json.dump(self.knowledge, f, ensure_ascii=False, indent=4)
        with open(self.responses_file, "w", encoding="utf-8") as f:
            json.dump(self.responses, f, ensure_ascii=False, indent=4)

    def check_online(self):
        """Checks if the computer is online using Bing."""
        try:
            requests.get("http://www.bing.com", timeout=5)
            return True
        except Exception:
            return False

    def nlp_preprocess(self, text):
        """
        Performs basic NLP preprocessing:
          - Tokenizes the text.
          - Removes common English and Chinese stopwords.
          - Returns a cleaned string.
        """
        # A minimal list of stopwords (can be expanded)
        stopwords = set(["the", "and", "is", "in", "at", "of", "a", "to", 
                         "我", "的", "了", "在", "是"])
        # Tokenize by extracting word characters
        words = re.findall(r'\w+', text.lower())
        filtered_words = [word for word in words if word not in stopwords]
        return " ".join(filtered_words)

    def thinking_chain(self, raw_text):
        """
        Processes raw online data with multi-step reasoning:
          - Removes HTML tags and extra spaces.
          - Applies NLP preprocessing to extract meaningful tokens.
          - Splits the text into sentences and selects key points.
          - Summarizes complex information in simpler terms.
        """
        # Remove HTML tags and clean whitespace
        clean_text = re.sub(r'<.*?>', ' ', raw_text)
        clean_text = re.sub(r'\s+', ' ', clean_text).strip()
        # Apply NLP preprocessing
        nlp_text = self.nlp_preprocess(clean_text)
        # Split into sentences based on punctuation
        sentences = re.split(r'(?<=[.!?]) +', nlp_text)
        # Choose the first 3 sentences as key points
        summary = " ".join(sentences[:3])
        if len(summary) > 300:
            summary = summary[:300] + "..."
        return summary

    def search_bing(self, query):
        """Searches Bing for the query and returns a processed result."""
        try:
            response = requests.get(f"https://www.bing.com/search?q={query}", timeout=5)
            raw_text = response.text
            processed_text = self.thinking_chain(raw_text)
            return processed_text
        except Exception:
            return ""

    def search_duckduckgo(self, query):
        """Searches DuckDuckGo using its API for the query."""
        try:
            url = f"https://api.duckduckgo.com/?q={query}&format=json"
            response = requests.get(url, timeout=5)
            data = response.json()
            abstract = data.get("AbstractText", "").strip()
            if abstract:
                return abstract
            return self.thinking_chain(response.text)
        except Exception:
            return ""

    def similarity(self, text1, text2):
        """
        Computes a simple similarity score based on word overlap.
        Returns a value between 0 and 1.
        """
        words1 = set(text1.lower().split())
        words2 = set(text2.lower().split())
        if not words1 or not words2:
            return 0
        common = words1.intersection(words2)
        return len(common) / max(len(words1), len(words2))

    def fact_check(self, query):
        """
        Searches both Bing and DuckDuckGo, compares the results,
        and returns a merged accurate answer.
        """
        result_bing = self.search_bing(query)
        result_ddg = self.search_duckduckgo(query)
        if result_bing and result_ddg:
            sim = self.similarity(result_bing, result_ddg)
            if sim >= 0.5:
                merged = result_bing if len(result_bing) >= len(result_ddg) else result_ddg
                return merged
            else:
                if "definition" in result_ddg.lower():
                    return result_ddg
                return result_bing
        elif result_bing:
            return result_bing
        elif result_ddg:
            return result_ddg
        else:
            return "No reliable information found online."

    def learn_knowledge(self, topic, info):
        """Adds new knowledge after processing through the Thinking Chain."""
        if topic not in self.knowledge or len(info) > len(self.knowledge[topic]):
            self.knowledge[topic] = info
            self.save_data()

    def learn_response(self, question, answer):
        """Learns how to respond to the user."""
        if question not in self.responses:
            self.responses[question] = answer
            self.save_data()

    def predict_questions(self, user_input):
        """
        Suggests related questions based on stored knowledge.
        Returns a list of suggestions if similar questions exist.
        """
        suggestions = []
        for question in self.knowledge.keys():
            if user_input.lower() in question.lower() or self.similarity(user_input, question) > 0.3:
                suggestions.append(question)
        return suggestions

    def respond(self, user_input):
        """
        Generates a response:
          - If a learned response exists, returns it.
          - Else, if knowledge is stored, returns that.
          - Otherwise, if online, fact-checks and uses the Thinking Chain to answer.
          - If offline, prompts the user for input.
          - Also predicts and suggests related questions.
        """
        if user_input in self.responses:
            answer = self.responses[user_input]
        elif user_input in self.knowledge:
            answer = f"I found this in my knowledge: {self.knowledge[user_input]}"
        else:
            if self.check_online():
                answer = self.fact_check(user_input)
                self.learn_knowledge(user_input, answer)
            else:
                print("\n🤔 I don't know this yet. Please teach me!")
                new_response = input("Enter a response: ")
                self.learn_response(user_input, new_response)
                answer = "Got it! I'll remember this."
        suggestions = self.predict_questions(user_input)
        if suggestions:
            answer += "\n\nYou might also be interested in these related topics:\n" + "\n".join(suggestions)
        return answer

    def show_code(self):
        """Displays stored knowledge and responses (for debugging)."""
        print("\n📜 **CGG-EUSO Code Check Mode** 📜")
        print("\nKnowledge stored:")
        print(json.dumps(self.knowledge, ensure_ascii=False, indent=4))
        print("\nResponses stored:")
        print(json.dumps(self.responses, ensure_ascii=False, indent=4))

# === Step 3: Run the Chatbot ===
bot = CGG_EUSO()

print("\n💬 CGG-EUSO is ready! Choose a mode:")
print("1️⃣ Chat Mode")
print("2️⃣ Code Check Mode")

while True:
    mode = input("\nSelect (1/2): ").strip()
    if mode == "1":
        print("\n💬 Enter 'exit' to quit.\n")
        while True:
            user_input = input("You: ")
            if user_input.lower() == "exit":
                print("\nGoodbye! 👋")
                break
            response = bot.respond(user_input)
            print(f"CGG-EUSO: {response}")
        break
    elif mode == "2":
        bot.show_code()
        break
    else:
        print("\n❌ Invalid choice! Please enter '1' or '2'.")