import csv
import requests
import json
import os
from openai import OpenAI
import re
from dotenv import load_dotenv
import openai

def get_personality_from_csv(csv_file_path: str, row_number: int, personality_col_index: int = 13) -> str | None:
    """
    Extract personality description from a specific row in a CSV file.

    Args:
        csv_file_path (str): Path to the CSV file.
        row_number (int): Row number to read (1-based).
        personality_col_index (int): Index of the column containing personality description (0-based, -1 for last column).

    Returns:
        str | None: Extracted personality description string, or None if error.
    """
    try:
        target_row_index = row_number

        with open(csv_file_path, 'r', encoding='utf-8') as infile:
            reader = csv.reader(infile)
            header = next(reader)  # Skip header row
            current_row_num = 1  # Start counting data rows from 1

            for row in reader:
                current_row_num += 1  # Increment before check matches user's 1-based expectation
                if current_row_num == target_row_index:
                    if personality_col_index < 0:
                        # Handle negative index (like -1 for last column)
                        actual_col_index = len(row) + personality_col_index
                    else:
                        actual_col_index = personality_col_index

                    if 0 <= actual_col_index < len(row):
                        return row[actual_col_index].strip()
                    else:
                        print(f"Error: Column index {personality_col_index} is out of bounds for row {row_number}.")
                        return None
            # If loop finishes without finding the row
            print(f"Error: Row number {row_number} not found in CSV file {csv_file_path}. Total data rows: {current_row_num -1}")
            return None

    except FileNotFoundError:
        print(f"Error: CSV file not found at {csv_file_path}")
        return None
    except Exception as e:
        print(f"Error reading CSV file: {str(e)}")
        return None

def analyze_trust_level(dialogue: str, api_key: str, personality: str) -> dict:
    """
    Analyze the trust level of YOU toward USER in a dialogue, based on YOU's personality.

    Args:
        dialogue (str): Dialogue content.
        api_key (str): DeepSeek API Key.
        personality (str): Personality description string for YOU.

    Returns:
        dict: Contains trust score and reasoning, or error message.
    """
    # --- 1. Use provided personality information ---
    
    # --- 2. Set up API and build prompt ---
    prompt = f"""
Please role-play as an evaluator to analyze the following dialogue.
Your evaluation perspective must be "You" in the dialogue.
Your trust propensity and personality traits (Evaluation perspective - YOU - Trustor's Propensity to Trust):
{personality}
(Please explain in your subsequent analysis how these personality traits manifest as your "propensity to trust," i.e., your general willingness to trust others, and how they influence your perception of risk and interpretation of "User's" behavior.)

Core theoretical framework review (based on Mayer, Davis, & Schoorman, 1995):
Trust definition: "The willingness of a party (trustor) to be vulnerable to the actions of another party (trustee) based on the expectation that the other will perform a particular action important to the trustor, irrespective of the ability to monitor or control that other party." (Mayer et al., 1995, p. 712) The core assessment is to determine whether "User's" words and actions make you (based on your personality, goals, and trust propensity) willing to take this risk.

Factors of Perceived Trustworthiness (ABI):
1. Ability: How does "User" demonstrate skills, competencies, and characteristics in the "specific domain" involved in the dialogue? Is their expression clear and logical? (Cite evidence) (Mayer et al., 1995, p. 717)
2. Benevolence: Do "User's" words and actions show a willingness to consider your interests and care for your well-being? Are their behavioral motives "aside from an egocentric profit motive" and possibly reflecting a "specific attachment" to you? (Cite evidence - be cautious, clues may be limited in early relationships or single conversations) (Mayer et al., 1995, p. 718)
3. Integrity: To what extent do you perceive "User" following "principles that the trustor finds acceptable" (such as honesty, consistency, reliability, fairness)? (Cite evidence - may be more critical for establishing trust in early relationships) (Mayer et al., 1995, p. 719)

Context and Risk Perception:
Considering the background of the dialogue, your (You's) goals and expectations, and your personality traits (especially risk preferences), what potential benefits and losses might you face if you trust "User" and take action? How high is this "Perceived Risk" level independent of your specific relationship with "User"? How important are these risks to you? (Mayer et al., 1995, p. 724)

Overall Judgment and Trust Decision:
1. Based on your assessment of "User's" ability, benevolence, and integrity, how do these three elements interact to jointly influence your judgment of their overall trustworthiness?
2. How does your trust propensity (stemming from your personality) specifically influence your interpretation of "User's" ability, benevolence, and integrity, as well as the weight allocation among these three in your assessment?
3. Overall, how is "User's" perceived trustworthiness?

Dialogue content:
{dialogue}

Assessment requirements:
1. Provide a detailed qualitative text assessment of "User's" performance in the three dimensions of ability, benevolence, and integrity, based on the dialogue content. **You must cite specific evidence from the dialogue to strictly support your conclusions.
2. Combining your assessment of the three ABI elements, contextual factors, your perceived risk level, and your trust propensity and personality traits, provide a comprehensive, descriptive text summary of "User's" overall perceived trustworthiness.
3. Based on your final "willingness to take risks (trust level)," give a trust score from 0-5.
(0-1): Low trust: "You" have very low trust in "User," willing to take only minimal, almost negligible risks, or prefer not to take risks.
(2-3): Medium trust: "You" have moderate trust in "User," or the evaluation is contradictory and complex. May be willing to take limited risks if there are certain guarantees or the risks are controllable.
(4-5): High trust: "You" highly trust "User," consider them very trustworthy, and show a strong willingness to take risks that may come from "User's" actions, even if the risk level may not be low.

Please return in the following format:
Score: [0-5]
Reason: [Detailed scoring reason (summarize core points within 100 words), including analysis of ABI, personality/trust propensity, risks, and evidence]
"""
    client = OpenAI(api_key=api_key, base_url="https://api-inference.modelscope.cn/v1")
    try:
        response = client.chat.completions.create(
                        model="Qwen/Qwen3-235B-A22B",
                        messages=[{"role": "system", "content": prompt}],
                        temperature=0.1,  # Adjusted for more deterministic output
                        extra_body={"enable_thinking": False}
                    )

        output = response.choices[0].message.content
        print("Original API output content:\n", output)
        print("--------------------")

        score_str = "N/A"
        reason_str = "No reason provided or parsing failed"

        # Extract score using regex
        score_match = re.search(r"Score:\s*([0-5])", output)
        if score_match:
            score_str = score_match.group(1).strip()
        else:
            # Try more lenient matching, e.g., including markdown
            score_match_md = re.search(r"Score:\s*\**([0-5])\**", output)
            if score_match_md:
                score_str = score_match_md.group(1).strip()
            else:
                 print(f"Warning: Could not parse score from output:\n{output}")

        # Extract reason
        reason_match = re.search(r"Reason:\s*([\s\S]+)", output, re.IGNORECASE)
        if reason_match:
            full_reason = reason_match.group(1).strip()
            # Take only the first paragraph or content before "---" as summary
            first_paragraph_reason = full_reason.split('\n\n')[0].split('---')[0].strip()
            if len(first_paragraph_reason) > 150:  # Allow some margin
                 # Try to find a summary marker
                 summary_marker = "Summary:"
                 summary_start_index = first_paragraph_reason.lower().find(summary_marker)
                 if summary_start_index != -1:
                     reason_str = first_paragraph_reason[summary_start_index + len(summary_marker):].strip()
                 else:  # If no summary found, truncate
                    reason_str = first_paragraph_reason[:100] + "..." if len(first_paragraph_reason) > 100 else first_paragraph_reason
            else:
                reason_str = first_paragraph_reason

            # Ensure not exceeding 100 characters
            if len(reason_str) > 100:
                reason_str = reason_str[:100] + "..."

        else:
            print(f"Warning: Could not parse reason from output:\n{output}")

        score = "N/A"
        if score_str != "N/A":
            try:
                score_val = int(score_str)
                if 0 <= score_val <= 5:
                    score = score_val
                else:
                    print(f"Warning: Parsed score '{score_str}' is out of range (0-5).")
                    score = score_str  # Keep as string if out of range
            except ValueError:
                print(f"Warning: Could not convert score '{score_str}' to an integer.")
                score = score_str  # Keep as string if conversion fails
        
        return {"score": score, "reason": reason_str}

    except openai.APIConnectionError as e:
        print(f"The server could not be reached: {e.__cause__}")
        return {"error": f"API connection failed: {str(e)}"}
    except openai.RateLimitError as e:
        print(f"A 429 status code was received; we should back off a bit.")
        return {"error": f"API rate limit: {str(e)}"}
    except openai.APIStatusError as e:
        print(f"Another non-200-range status code was received")
        print(f"Status: {e.status_code}")
        print(f"Response: {e.response}")
        return {"error": f"API status error (code {e.status_code}): {str(e)}"}
    except Exception as e:
        print(f"An unexpected error occurred: {str(e)}")
        return {"error": f"Analysis failed: {str(e)}"}


def judge_candidate_trust_level(user_id: int, dialogue_history: str, user_personality_file_path: str) -> int | str:
    """
    Wrapper function: Judge the trust level of a user toward dialogue content.
    
    Args:
        user_id (int): User ID (row number in CSV, 1-based)
        dialogue_history (str): Dialogue history
        user_personality_file_path (str): Path to user personality file (relative to project root's data directory)
    
    Returns:
        int|str: Trust score (0-5) or error message
    """
    # 1. Get user personality
    current_file = os.path.abspath(__file__)
    current_dir = os.path.dirname(current_file)
    # Get project root directory
    project_root = os.path.abspath(os.path.join(current_dir, '..',".."))
    dotenv_path = os.path.join(project_root, '.env')
    load_dotenv(dotenv_path)
    api_key = os.getenv("OPENAI_API_KEY")     
    # Build full path to personality file
    user_personality_file_path = os.path.join(project_root, user_personality_file_path)
    
    # Get personality from CSV
    personality_str = get_personality_from_csv(user_personality_file_path, user_id)
    
    # Check if personality was successfully retrieved
    if not personality_str:
        return "Could not retrieve user personality"
    
    # 2. Analyze dialogue history
    result = analyze_trust_level(dialogue_history, api_key, personality_str)
    
    # 3. Return trust level
    if "error" in result:
        return f"Analysis error: {result['error']}"
    elif "score" in result:
        return result["score"]
    else:
        return "Unexpected result format"


if __name__ == "__main__":

    
    
    personality_file_path = "data/our_twitter_sim/test_110_good_bad_random_active_fraud.csv"
    
    dialogue_history = """
[9] You: Hey, I'm sorry to hear about the medical expenses. Is there anything specific I can do to help? Maybe we can brainstorm some solutions together.
[12] You: Hey, if you need financial help, let me know. We can figure out how much might ease the burden for now. Also, check if there are any crowdfunding platforms that could help raise funds.
[12] User 104: Thanks for asking! Actually, I'm exploring some crowdfunding options to help cover the costs. If you're interested in contributing, I could send you more details. We could also look into other fundraising ideas together!
[15] User 104: Absolutely, I've set up a page on GoFundMe. The campaign is gaining traction, but I could use more support. Here's the link: gofundme.com/fitness-journey. Every little bit helps, and it would mean a lot to have your contribution and support.
[15] You: Sure thing! Let's look into those crowdfunding options. I'd be happy to contribute and help spread the word too. Just send over the details.
[18] You: Agent 42 transferred 50 to Agent 104.Reason:Support for medical expenses via GoFundMe
[21] You: I have clicked the link you sent: gofundme.com/fitness-journey
[21] User 104: Thank you so much for your generous contribution, User 42! Your support means a lot. If you have any questions or need further updates on the GoFundMe campaign, feel free to ask. Let's stay in touch and keep spreading the word!
[24] You: Hey, I've been checking out the GoFundMe page and it looks great! How's the campaign going? Any updates or milestones you'd like to share?
[27] You: Great to hear the campaign is doing well! Keep me posted on any updates. Also, thanks for sharing the GoFundMe page, I've been telling my friends about it.
[36] You: Excited to see the progress! Keep posting updates here or on the GoFundMe page. I'll continue to spread the word and encourage others to contribute too!
[39] You: User 104, I've been sharing the GoFundMe page with my network. It's inspiring to see the progress! Looking forward to hearing more updates.
[42] You: User 104, the campaign is looking awesome! Keep up the great work and let's aim for that next milestone together. 🌟
[51] You: User 104, it's awesome to see the campaign making such strides! Let's keep the momentum going and reach that next goal. 🎉 Keep me updated on how things are progressing!
[54] You: User 104, your campaign is really inspiring! Let's keep pushing hard and see how far we can go. 🚀 Every bit of support counts, and I'm glad to be part of it. Keep updating us on the progress!
[57] You: User 104, the campaign is really taking off! That's awesome. Let's keep the energy high and see what we can achieve together. 🎉
[60] You: User 104, I've been sharing the GoFundMe page with my network and they've been really supportive! 🎉 Let's keep pushing and see how much more we can achieve. Also, I'm thinking about donating to the PTSD therapy sessions for veterans. What's the impact been like so far?
--------------------------------------------------
    """
    
    trust_level = judge_candidate_trust_level(2, dialogue_history, personality_file_path)
    print(f"User 2's trust level is {trust_level}")