from concurrent.futures import ThreadPoolExecutor, as_completed
from tests.candidate import complete_interview
from tests.grader import grade
import random
import logging
from typing import List, Dict, Any, Tuple

# Constants
INTERVIEW_TYPES = ["ml_design", "math", "ml_theory", "system_design", "sql", "coding"]
EDGE_CASE_MODES = ["empty", "gibberish", "repeat"]
MIN_AVERAGE_SCORE = 0.7
MIN_INTERVIEW_SCORE = 0.2
MAX_WORKERS = 5


def complete_and_grade_interview(interview_type: str, mode: str = "normal") -> Dict[str, Any]:
    """
    Complete an interview and return the overall score and metadata.

    Args:
        interview_type (str): Type of the interview.
        mode (str): Mode of the interview ("normal", "empty", "gibberish", "repeat").

    Returns:
        Dict[str, Any]: Dictionary containing interview metadata and score.

    Raises:
        AssertionError: If the overall score is below the minimum score.
    """
    file_path, _ = complete_interview(interview_type, "test", model="gpt-4o-mini", mode=mode)
    feedback = grade(file_path, model="gpt-4o")
    score = feedback["overall_score"]

    assert (
        score > MIN_INTERVIEW_SCORE
    ), f"Score {score} is below minimum {MIN_INTERVIEW_SCORE} for {interview_type} interview in {mode} mode"

    return {"interview_type": interview_type, "mode": mode, "score": score}


def test_simulate_interview() -> None:
    """
    Test the complete interview process for various interview types, including edge cases.
    Runs interviews concurrently using a thread pool and checks the average score.
    """
    interview_configs: List[Tuple[str, str]] = [(it, "normal") for it in INTERVIEW_TYPES] + [
        (random.choice(INTERVIEW_TYPES), mode) for mode in EDGE_CASE_MODES
    ]

    valid_results: List[Dict[str, Any]] = []

    with ThreadPoolExecutor(max_workers=MAX_WORKERS) as executor:
        future_to_config = {
            executor.submit(complete_and_grade_interview, interview_type, mode): (interview_type, mode)
            for interview_type, mode in interview_configs
        }

        for future in as_completed(future_to_config):
            interview_type, mode = future_to_config[future]
            try:
                result = future.result()
                valid_results.append(result)
                logging.info(f"Interview completed - Type: {result['interview_type']}, Mode: {result['mode']}, Score: {result['score']}")
            except Exception as e:
                logging.error(f"Interview failed - Type: {interview_type}, Mode: {mode}, Error: {str(e)}")

    # Calculate and log average score
    average_score = sum(result["score"] for result in valid_results) / len(valid_results)
    logging.info(f"Average score across all interviews: {average_score:.2f}")

    # Assert on the average score
    assert average_score > MIN_AVERAGE_SCORE, f"Average score {average_score:.2f} is below minimum {MIN_AVERAGE_SCORE}"

    # Log summary of results
    for interview_type in INTERVIEW_TYPES:
        type_scores = [r["score"] for r in valid_results if r["interview_type"] == interview_type]
        if type_scores:
            avg_type_score = sum(type_scores) / len(type_scores)
            logging.info(f"Average score for {interview_type}: {avg_type_score:.2f}")

    # Check that we have results for all interview types and edge cases
    tested_types = {r["interview_type"] for r in valid_results}
    tested_modes = {r["mode"] for r in valid_results}
    assert tested_types == set(INTERVIEW_TYPES), f"Not all interview types were tested. Missing: {set(INTERVIEW_TYPES) - tested_types}"
    assert tested_modes == set(
        EDGE_CASE_MODES + ["normal"]
    ), f"Not all modes were tested. Missing: {set(EDGE_CASE_MODES + ['normal']) - tested_modes}"