from dotenv import load_dotenv, find_dotenv
load_dotenv(find_dotenv())
import os
import sys
import subprocess
from datetime import datetime
import webbrowser
import threading
import shutil
import time

# Add the parent directory to the Python path
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

import modules.logger_tool as logger

# Setup logging
log_name = 'pytest_run_tests'
log_dir = os.getenv("LOG_PATH", "/logs")  # Default path as fallback
logging = logger.get_logger(
    name=log_name,
    log_level=os.getenv("LOG_LEVEL", "DEBUG"),
    log_path=log_dir,
    log_file=log_name,
    runtime=True,
    log_format='default'
)

def find_project_root():
    # Start from the current file location
    root = os.path.dirname(os.path.abspath(__file__))
    # Traverse up until you find the .env file
    while not os.path.exists(os.path.join(root, '.env')):
        new_root = os.path.dirname(root)
        if root == new_root:  # root directory reached without finding .env
            raise Exception("Project root not found.")
        root = new_root
    return root

def load_env():
    project_root = find_project_root()
    dotenv_path = find_dotenv(os.path.join(project_root, '.env'))
    load_dotenv(dotenv_path)
    required_vars = ["FIXME"]
    for var in required_vars:
        if var not in os.environ:
            print(f"Error: {var} is not set in the environment.")
            sys.exit(1)

def select_test_file():
    project_root = find_project_root()
    test_categories = {
        "A": {
            "name": "X Copilot Initialization",
            "tests": {
                "1": os.path.join(project_root, "backend", "app", "tests", "pytest_init_x.py")
            }
        },
        "B": {
            "name": "Graph QA",
            "tests": {
                "1": os.path.join(project_root, "backend", "app", "tests", "pytest_init_school_timetable_graph_qa.py"),
                "2": os.path.join(project_root, "backend", "app", "tests", "pytest_init_curriculum_graph_qa.py"),
                "3": os.path.join(project_root, "backend", "app", "tests", "pytest_init_calendar_graph_qa.py")
            }
        },
        "C": {
            "name": "Connections",
            "tests": {
                "1": os.path.join(project_root, "backend", "app", "tests", "pytest_arbor.py")
            }
        },
        "D": {
            "name": "Transcription",
            "tests": {
                "1": os.path.join(project_root, "tests", "pytest_transcribe.py")
            }
        },
        "E": {
            "name": "LangGraph",
            "tests": {
                "1": os.path.join(project_root, "backend", "app", "tests", "pytest_langgraph.py")
            }
        }
    }

    print("Select a test file to run:")
    for category_key, category in test_categories.items():
        print(f"\n{category_key}: {category['name']}")
        for test_key, test_file in category["tests"].items():
            print(f"  {category_key}{test_key}: {os.path.basename(test_file)}")

    choice = input("\nEnter your choice (e.g., A1): ").upper()
    if len(choice) == 2 and choice[0] in test_categories and choice[1] in test_categories[choice[0]]["tests"]:
        category_key, test_key = choice[0], choice[1]
        return test_categories[category_key]["tests"][test_key], choice

    print("Invalid choice.")
    sys.exit(1)

def create_log_dir(choice, project_root):
    log_dir = os.path.join(project_root, "logs", "pytests")
    if choice[0] == "A":
        log_dir = os.path.join(log_dir, "database", "init")
    elif choice[0] == "B":
        log_dir = os.path.join(log_dir, "database", "langchain", "graph_qa")
    elif choice[0] == "C":
        log_dir = os.path.join(log_dir, "database", "connections", "arbor")
    elif choice[0] == "D":
        log_dir = os.path.join(log_dir, "transcribe")
    elif choice[0] == "E":
        log_dir = os.path.join(log_dir, "langgraph")
    else:
        print("Invalid choice.")
        sys.exit(1)
    
    os.makedirs(log_dir, exist_ok=True)
    return log_dir

def open_html_report_in_browser(html_path):
    """Function to open the HTML report in the default web browser."""
    # Check for the existence of the file every 2 seconds, up to a maximum of 10 checks
    for _ in range(10):
        if os.path.exists(html_path):
            webbrowser.open(html_path)
            break
        time.sleep(2)
    else:
        print("HTML report was not generated in time.")

def run_tests(test_file, log_dir, choice):
    timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
    base_filename = os.path.basename(test_file).replace('.py', '')
    html_report = os.path.join(log_dir, f"{base_filename}_pytest_report_{timestamp}.html")
    xml_report = os.path.join(log_dir, f"{base_filename}_pytest_report_{timestamp}.xml")
    
    pytest_command = [
        "pytest",
        "-v",
        test_file,
        f"--junitxml={xml_report}",
        f"--html={html_report}",
        "--self-contained-html",
        "--capture=tee-sys",
        "--show-capture=all"
    ]

    if choice[0] == "A":
        test_components = input("Enter test components to run (school,users,timetable), comma-separated, or 'all': ").lower()
        if test_components != 'all':
            components = test_components.split(',')
            for component in components:
                pytest_command.append(f"-m {component}")

    print("Running command:", ' '.join(pytest_command))

    # Start a thread to open the HTML report, checking for its existence
    threading.Thread(target=open_html_report_in_browser, args=(html_report,)).start()

    result = subprocess.run(pytest_command, check=True)
    return result

def main():
    project_root = find_project_root()
    load_env()
    data_dir = os.path.join(project_root, "APP_DATA")
    # TODO: Modify this after initial testing
    if os.path.exists(data_dir):
        shutil.rmtree(data_dir)
    test_file, choice = select_test_file()
    if not test_file:
        print("Invalid choice.")
        sys.exit(1)

    log_dir = create_log_dir(choice, project_root)
    run_tests(test_file, log_dir, choice)

if __name__ == "__main__":
    main()
