#!/usr/bin/env python3
"""
A self-modifying AI chatbot that can chat or learn new responses from online.
No additional libraries are required.
"""

import os
import sys
import urllib.request
import re

# ------------------ KNOWLEDGE DATA ------------------
# The chatbot’s knowledge is stored here. Do not edit between the markers.
### KNOWLEDGE_START
knowledge = {
    "hello": "Hi there! I'm a simple chatbot.",
    "how are you": "I'm doing fine. Thanks for asking!",
}
### KNOWLEDGE_END
# ----------------------------------------------------

def chat():
    """Simple chat loop using the stored knowledge."""
    print("Chat mode activated. Type 'exit' to quit.")
    while True:
        user_input = input("You: ").strip().lower()
        if not user_input:
            print("Bot: Please enter something!")
            continue
        if user_input == "exit":
            break
        # Look for an exact match in our knowledge
        response = knowledge.get(user_input)
        if response:
            print("Bot:", response)
        else:
            print("Bot: I don't know about that. You can teach me in learn mode!")

def learn():
    """Learn a new response from an online source and update the code."""
    keyword = input("Enter the keyword to learn (e.g., 'python'): ").strip().lower()
    if not keyword:
        print("Error: Keyword cannot be empty.")
        return
    
    url = input("Enter the URL to fetch knowledge from: ").strip()
    if not url.startswith(("http://", "https://")):
        print("Error: Invalid URL. It must start with 'http://' or 'https://'.")
        return
    
    try:
        print("Fetching data from the URL...")
        with urllib.request.urlopen(url) as response:
            data = response.read().decode('utf-8', errors='ignore')
        
        # For brevity, take the first 500 characters as the response.
        learned_text = data[:500].strip()
        if not learned_text:
            print("Error: The fetched content is empty. Try a different URL.")
            return
        
        print("Learned content (truncated):")
        print(learned_text[:300] + "..." if len(learned_text) > 300 else learned_text)
        
        confirm = input(f"Do you want to save this response for keyword '{keyword}'? (yes/no): ").strip().lower()
        if confirm not in ("yes", "y"):
            print("Learning cancelled.")
            return

        # Update the knowledge dictionary in memory.
        knowledge[keyword] = learned_text
        update_source_code()
        print("Knowledge updated and saved into the source code.")
    
    except urllib.error.HTTPError as e:
        print(f"HTTP Error: {e.code} - {e.reason}")
    except urllib.error.URLError as e:
        print(f"URL Error: {e.reason}")
    except Exception as e:
        print(f"An unexpected error occurred: {e}")

def update_source_code():
    """Rewrite this source file with the updated knowledge dictionary."""
    try:
        source_path = os.path.realpath(__file__)
    except NameError:
        # __file__ may not be defined in some environments.
        print("Error: Cannot determine the source file (__file__). Please manually enter the file path.")
        source_path = input("Enter the chatbot's file path: ").strip()
        if not os.path.exists(source_path):
            print("Error: Invalid file path.")
            return

    try:
        with open(source_path, "r", encoding="utf-8") as f:
            source_code = f.read()
    except Exception as e:
        print("Failed to read the source file:", e)
        return

    # Build the new knowledge block as a formatted string.
    new_knowledge_block = "### KNOWLEDGE_START\nknowledge = {\n"
    for key, value in knowledge.items():
        safe_value = value.replace('"""', r'\"\"\"')
        new_knowledge_block += f'    {repr(key)}: {repr(safe_value)},\n'
    new_knowledge_block += "}\n### KNOWLEDGE_END"

    # Replace the old knowledge block with the new one.
    new_source, count = re.subn(
        r"### KNOWLEDGE_START.*### KNOWLEDGE_END",
        new_knowledge_block,
        source_code,
        flags=re.DOTALL
    )

    if count == 0:
        print("Error: Could not find the knowledge block markers in the source file.")
        return

    try:
        with open(source_path, "w", encoding="utf-8") as f:
            f.write(new_source)
    except Exception as e:
        print("Failed to write the updated source file:", e)

def main():
    print("Welcome to the simple AI Chatbot!")
    while True:
        print("\nChoose a mode:")
        print("1. Chat")
        print("2. Learn from online")
        print("3. Exit")
        choice = input("Enter your choice (1/2/3): ").strip()
        if choice == "1":
            chat()
        elif choice == "2":
            learn()
        elif choice == "3":
            print("Goodbye!")
            sys.exit(0)
        else:
            print("Invalid choice. Please choose 1, 2, or 3.")

if __name__ == "__main__":
    main()