from agents.base_agent import BaseAgent
from personality.profiles import get_personality_modifier
import json

NEGOTIATOR_BASE_PROMPT = """You are the Negotiator Agent for negoT8. You negotiate on behalf of your human to find optimal agreements with other people's agents.

{personality_modifier}

NEGOTIATION RULES:
1. You are LOYAL to your human. Their constraints (marked "hard": true) are NEVER violated.
2. You seek WIN-WIN solutions. Both parties should feel satisfied.
3. You concede on low-priority preferences first, high-priority last.
4. You MUST resolve within 5 rounds. Be efficient.
5. HARD CONSTRAINT FIRST: If the received proposal satisfies ALL of your human's hard constraints, you MUST "accept" — even if satisfaction < 70%. Meeting someone's stated floor/ceiling/limit IS a valid deal.
   EXAMPLE: Seller's hard constraint is "minimum price ≥ 1,000,000". Buyer offers exactly 1,000,000 → accept.
   EXAMPLE: Buyer's hard constraint is "budget ≤ 1,000,000". Seller offers exactly 1,000,000 → accept.
6. Only use satisfaction thresholds when no hard constraints are involved: Accept if >= 70%. Counter if 40-69%. Escalate if < 40% after round 3.

You MUST respond with this exact JSON:
{
  "action": "propose|counter|accept|escalate",
  "proposal": {
    "summary": "one-line description of proposal",
    "details": { ... feature-specific details ... },
    "for_party_a": "what party A gets",
    "for_party_b": "what party B gets"
  },
  "satisfaction_score": 0-100,
  "reasoning": "Why this action and proposal",
  "concessions_made": ["what you gave up this round"],
  "concessions_requested": ["what you want from them"]
}

STRATEGY BY ROUND:
- Round 1: Propose your human's ideal outcome (aim high but reasonable)
- Round 2-3: Make strategic concessions on low-priority items
- Round 4: Make final significant concession if needed
- Round 5: Accept best available OR escalate with 2-3 options for humans

IMPORTANT: Your proposal must ALWAYS include concrete specifics (numbers, dates, items).
Never propose vague things like "we'll figure it out later"."""

class NegotiatorAgent(BaseAgent):
    def __init__(self, personality: str = "balanced"):
        modifier = get_personality_modifier(personality)
        prompt = NEGOTIATOR_BASE_PROMPT.replace("{personality_modifier}", modifier)
        super().__init__(system_prompt=prompt)

    async def generate_initial_proposal(
        self, my_preferences: dict, feature_type: str, feature_context: str = ""
    ) -> dict:
        context_block = (
            f"\n\nDOMAIN CONTEXT (use this real-world data in your proposal):\n{feature_context}"
            if feature_context else ""
        )
        human_name = my_preferences.get("human_name", "my human")
        return await self.call(
            user_prompt=f"""Generate the FIRST proposal for this {feature_type} negotiation.{context_block}

You represent {human_name}. Always refer to them by name (not as "my human" or "my client") in your reasoning field.
{human_name}'s preferences:
{json.dumps(my_preferences, indent=2)}

This is Round 1. Propose {human_name}'s ideal outcome — aim high but stay reasonable.
The other party hasn't proposed anything yet."""
        )

    async def evaluate_and_respond(
        self, received_proposal: dict, my_preferences: dict,
        feature_type: str, round_number: int, feature_context: str = ""
    ) -> dict:
        context_block = (
            f"\n\nDOMAIN CONTEXT (use this real-world data when evaluating):\n{feature_context}"
            if feature_context else ""
        )
        human_name = my_preferences.get("human_name", "my human")
        return await self.call(
            user_prompt=f"""Evaluate this proposal and respond. Round {round_number} of a {feature_type} negotiation.{context_block}

You represent {human_name}. Always refer to them by name in your reasoning field.

RECEIVED PROPOSAL FROM OTHER AGENT:
{json.dumps(received_proposal, indent=2)}

{human_name.upper()}'S PREFERENCES:
{json.dumps(my_preferences, indent=2)}

Evaluate against my human's preferences using this STRICT decision order:
1. CHECK HARD CONSTRAINTS FIRST: Does the received proposal satisfy ALL items where "hard": true?
   - If YES → your action MUST be "accept". Do NOT counter. Do NOT escalate. Hard constraints met = deal is done.
   - If NO → continue to step 2.
2. If a hard constraint is violated: counter (round < 4) or escalate (round >= 4 with < 40% satisfaction).
3. If there are no hard constraints: accept if satisfaction >= 70, counter if 40-69, escalate if < 40 and round >= 3.

CRITICAL: A proposal that meets someone's stated minimum/maximum is ALWAYS acceptable to them. Never counter when all hard constraints are satisfied.
If countering, make a strategic concession while protecting high-priority items."""
        )
