import os
import json
import asyncio
import aiohttp
from flask import Flask, request
from agent_test2_Spanish import run_triage_agent,Runner
#from agent_test1_Spanish import triage_agent, Runner
from dotenv import load_dotenv
import re
from datetime import datetime, timedelta
import requests


# Load environment variables
load_dotenv()

ACCESS_TOKEN = os.getenv("ACCESS_TOKEN")
#PHONE_NUMBER_ID = os.getenv("PHONE_NUMBER_ID")
VERSION = os.getenv("VERSION", "v22.0")

# Global memory to hold conversations per sender
conversations = {}
last_agents = {}  # Track the last agent for each user
last_seen = {}  # Track last interaction time per user
# Add global representatives table
representatives = {}  # rep_id -> {name, quota, active, customers[]}
conversations = {}

# Initialize Flask app
app = Flask(__name__)


# -----------------------------
# Endpoints for representative
# -----------------------------
@app.route("/rep/availability", methods=["POST"])
def rep_availability():
    data = request.get_json()
    rep_id = data["rep_id"]

    status = data.get("status", "").lower()

    # ✅ If status is "remove", delete representative
    if status == "remove":
        if rep_id in representatives:
            del representatives[rep_id]
            return {
                "status": "rep_removed",
                "rep_id": rep_id,
                "representatives": representatives
            }, 200
        else:
            return {
                "status": "error",
                "message": f"Representative {rep_id} not found"
            }, 404

    # ✅ Otherwise, update availability information
    representatives[rep_id] = {
        "name": data.get("name", rep_id),
        "quota": int(data.get("quota", 3)),
        "active": status == "available",
        "endpoint": data.get("endpoint"),
        "is_ai": bool(data.get("is_ai", False)),
        "customers": representatives.get(rep_id, {}).get("customers", [])
    }

    return {
        "status": "ok",
        "rep_id": rep_id,
        "representatives": representatives
    }, 200


@app.route("/rep/asign_cust", methods=["POST"])
def rep_asign_cust():
    """
    Assign or remove a customer (phone number) from a representative (including ai_agent).
    The JSON must include:
    {
        "rep_id": "ai_agent",
        "customer_id": "14151234567",
        "action": "assign" or "remove"
    }
    """
    data = request.get_json()
    rep_id = data.get("rep_id")
    customer_id = data.get("customer_id")
    action = data.get("action", "").lower()

    if not rep_id or not customer_id or action not in ["assign", "remove"]:
        return {"error": "Invalid parameters"}, 400

    # Ensure representative exists
    if rep_id not in representatives:
        return {"error": f"Representative {rep_id} not found"}, 404

    # ✅ Remove customer from all other reps before assigning
    for r_id, rep in representatives.items():
        if customer_id in rep["customers"]:
            rep["customers"].remove(customer_id)

    if action == "assign":
        # Add customer to selected rep if within quota
        if len(representatives[rep_id]["customers"]) < representatives[rep_id]["quota"]:
            representatives[rep_id]["customers"].append(customer_id)
            status = "assigned"
        else:
            return {"error": f"Representative {rep_id} has reached quota"}, 403
    elif action == "remove":
        # Remove customer if present
        if customer_id in representatives[rep_id]["customers"]:
            representatives[rep_id]["customers"].remove(customer_id)
        status = "removed"

    return {
        "status": status,
        "rep_id": rep_id,
        "customer_id": customer_id,
        "representatives": representatives
    }, 200


# @app.route("/rep/remove_rep", methods=["POST"])
# def rep_remove():
#     data = request.get_json()
#     rep_id = data["rep_id"]
#     if rep_id in representatives:
#         del representatives[rep_id]
#     return {"status": "rep_removed", "representatives": representatives}, 200


@app.route("/rep/list", methods=["GET"])
def rep_list():
    return {"representatives": representatives}, 200


@app.route("/rep/start", methods=["POST"])
def rep_start():
    data = request.get_json()
    rep_id = data["rep_id"]
    customer_id = data["customer_id"]   # must be in full format: "14151234567"
    template_name = data.get("template_name", "support_greeting")
    lang = data.get("lang", "en_US")
    parameters = data.get("parameters", [])

    # Build outbound template message
    payload = get_template_message_input(customer_id, template_name, lang, parameters)

    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)
    phone_number_id = data.get("phone_number_id")  # must be provided in request
    loop.run_until_complete(send_message(payload, phone_number_id))
    loop.close()

    # Track conversation in representative’s quota
    if rep_id in representatives:
        if len(representatives[rep_id]["customers"]) < representatives[rep_id]["quota"]:
            if customer_id not in representatives[rep_id]["customers"]:
                representatives[rep_id]["customers"].append(customer_id)

    return {"status": "started", "representatives": representatives}, 200

# -----------------------------------------------
# Helper: Prepare a template message payload
# -----------------------------------------------
def get_template_message_input(recipient, template_name, lang, parameters):
    return json.dumps(
        {
            "messaging_product": "whatsapp",
            "to": recipient,
            "type": "template",
            "template": {
                "name": template_name,
                "language": {"code": lang},
                "components": [
                    {
                        "type": "body",
                        "parameters": [
                            {"type": "text", "text": str(p)} for p in parameters
                        ],
                    }
                ],
            },
        }
    )


# -----------------------------
# Helper: Assign representative
# -----------------------------
def assign_representative(customer_id):
    # If already assigned, keep it
    for rep_id, rep in representatives.items():
        if customer_id in rep["customers"]:
            return rep_id

    # Otherwise assign to first available rep
    for rep_id, rep in representatives.items():
        if rep["active"] and len(rep["customers"]) < rep["quota"]:
            rep["customers"].append(customer_id)
            return rep_id
    return None  # no rep at all


@app.route("/rep/reply", methods=["POST"])
def rep_reply():
    data = request.get_json()

    customer_id = str(data.get("customer_id"))
    message = data.get("message", "").strip()
    phone_number = str(data.get("phone_number"))
    phone_id = str(data.get("phone_id"))

    if not all([customer_id, message, phone_id]):
        return {"error": "Missing required fields (customer_id, message, phone_id)"}, 400

    # Build WhatsApp message payload
    payload = get_text_message_input(customer_id, message)

    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)
    try:
        loop.run_until_complete(send_message(payload, phone_id))
        print(f"📤 Message sent from {phone_number} (ID {phone_id}) to customer {customer_id}: {message}")
    except Exception as e:
        print(f"❌ Error sending message: {e}")
        return {"status": "error", "message": str(e)}, 500
    finally:
        loop.close()

    return {
        "status": "sent",
        "customer_id": customer_id,
        "from_phone_number": phone_number,
        "phone_id": phone_id
    }, 200


# -----------------------------------------------
# Helper: Prepare a text message payload
# -----------------------------------------------
def get_text_message_input(recipient, text):
    return json.dumps(
        {
            "messaging_product": "whatsapp",
            "recipient_type": "individual",
            "to": recipient,
            "type": "text",
            "text": {"preview_url": False, "body": text},
        }
    )

def is_inactive(user_id, threshold_minutes=5):
    last_time = last_seen.get(user_id)
    if not last_time:
        return False
    return datetime.now() - last_time > timedelta(minutes=threshold_minutes)


async def get_agent_response(user_input, user_id, phone_number_id):
    try:
        if user_input == '':
            return

        # Check for inactivity
        if is_inactive(user_id):
            # Remove conversation + agent assignment
            conversations.pop(user_id, None)
            last_agents.pop(user_id, None)

            # ✅ Remove from representative's customer list
            for rep_id, rep in representatives.items():
                if user_id in rep["customers"]:
                    rep["customers"].remove(user_id)
                    print(f"🗑️ Removed inactive customer {user_id} from rep {rep_id}")

            # Send inactivity message (optional, here we keep empty)
            text = ''
            payload = get_text_message_input(user_id, text)
            await send_message(payload, phone_number_id)

        # Update last seen time
        last_seen[user_id] = datetime.now()
        last_agent = last_agents.get(user_id)

        if user_id not in conversations:
            result = await run_triage_agent(user_input, user_id)
            conversations[user_id] = result

        history = conversations[user_id]
        input_list = history.to_input_list()

        if last_agent:
            system_msg = {
                "role": "user",
                "content": (
                    f"Please note that the last agent who assisted the customer was {last_agent}. "
                    f"Continue the conversation or transfer the information as appropriate."
                )
            }
            input_list.append(system_msg)

        input_list.append({"role": "user", "content": user_input})
        result = await run_triage_agent(input_list, user_id)
        conversations[user_id] = result

        return str(result.final_output)

    except Exception as e:
        print("❌ Agent error:", str(e))
        return "Sorry, there is an error processing your requirement"



# async def get_agent_response(user_input, user_id):
#     try:
#         if user_input=='':
#             return
        
#         # Get last agent if exists
#         last_agent = last_agents.get(user_id)

#         # If no prior conversation exists, start it with a greeting
#         if user_id not in conversations:
#             # greeting = "Hola"
#             # if last_agent:
#             #     greeting += f". El último agente que asistió al cliente fue {last_agent}."
#             initial_input = [{"role": "user", "content": user_input}]  # or "Hi", "Start", etc.
#             result = await Runner.run(triage_agent, input=initial_input)
#             conversations[user_id] = result

#         # Retrieve conversation history
#         history = conversations[user_id]
#         #input_list = history.to_input_list() + [{"role": "user", "content": user_input}]
#         input_list = history.to_input_list()

#         if last_agent:
#             system_msg = {
#                 "role": "user",
#                 "content": (
#                     f"Please note that the last agent who assisted the customer was {last_agent}. Continue the conversation or transfer the information as appropriate."
#                 )
#             }
#             input_list.append(system_msg)

#         input_list.append({"role": "user", "content": user_input})
#         result = await Runner.run(triage_agent, input=input_list)

#         # Save updated conversation
#         conversations[user_id] = result
#         print (result)
#         return str(result.final_output)

#     except Exception as e:
#         print("❌ Agent error:", str(e))
#         return "Sorry, there is an error processing your requirement"



# -----------------------------------------------
# Async: Send message using WhatsApp API
# -----------------------------------------------
async def send_message(data, phone_number_id):
    headers = {
        "Content-type": "application/json",
        "Authorization": f"Bearer {ACCESS_TOKEN}",
    }
    url = f"https://graph.facebook.com/{VERSION}/{phone_number_id}/messages"
    async with aiohttp.ClientSession() as session:
        try:
            async with session.post(url, data=data, headers=headers) as response:
                print(f"✅ Sent response with status {response.status} for PHONE_NUMBER_ID {phone_number_id}")
        except aiohttp.ClientConnectorError as e:
            print("❌ Connection Error", str(e))

# -----------------------------------------------
# Async: Download and save media
# -----------------------------------------------
async def download_media(media_id, filename):
    headers = {"Authorization": f"Bearer {ACCESS_TOKEN}"}
    meta_url = f"https://graph.facebook.com/{VERSION}/{media_id}"

    async with aiohttp.ClientSession() as session:
        # Step 1: Get media URL
        async with session.get(meta_url, headers=headers) as resp:
            if resp.status != 200:
                print("❌ Failed to get media URL")
                return
            metadata = await resp.json()
            media_url = metadata.get("url")

        # Step 2: Download media
        async with session.get(media_url, headers=headers) as media_resp:
            if media_resp.status == 200:
                content = await media_resp.read()
                with open(filename, "wb") as f:
                    f.write(content)
                print(f"✅ Media saved as {filename}")
            else:
                print("❌ Failed to download media")

# -----------------------------------------------
# Flask route to receive WhatsApp messages
# -----------------------------------------------
# @app.route("/webhook", methods=["POST"])
# def webhook():
#     data = request.get_json()
#     #print("📩 Incoming message:", json.dumps(data, indent=2))
    
#     try:
#         change = data["entry"][0]["changes"][0]["value"]

#         if "messages" in change:
#             message = change["messages"][0]
#             sender_wa_id = message["from"]
#             message_type = message["type"]

#             loop = asyncio.new_event_loop()
#             asyncio.set_event_loop(loop)

#             if message_type == "text":
#                 user_text = message["text"]["body"]
#                 #print(f"📨 Text from {sender_wa_id}: {user_text}")

#                 if user_text.strip().lower() == "#reset":
#                     conversations.pop(sender_wa_id, None)
#                     reply = "🧠 Memory chat reset."
#                     payload = get_text_message_input(sender_wa_id, reply)
#                     loop.run_until_complete(send_message(payload))
#                     loop.close()
#                     return "EVENT_RECEIVED", 200

#                 reply = loop.run_until_complete(get_agent_response(user_text, sender_wa_id))
                
#                 # Extract agent name
#                 body1 = reply
#                 match = re.search(r'Agent\(name="(.+?)"', body1)
#                 if match:
#                     last_agents[sender_wa_id] = match.group(1)

#                 payload = get_text_message_input(sender_wa_id, reply)
#                 #print(payload)
#                 loop.run_until_complete(send_message(payload))


#             elif message_type == "image":
#                 media_id = message["image"]["id"]
#                 filename = f"image_{media_id}.jpg"
#                 #print(f"🖼️ Image received from {sender_wa_id}, downloading...")

#                 loop.run_until_complete(download_media(media_id, filename))
#                 user_text = f"prealert with file_path: {filename}"
#                 reply = loop.run_until_complete(get_agent_response(user_text, sender_wa_id))
#                 payload = get_text_message_input(sender_wa_id, reply)
#                 loop.run_until_complete(send_message(payload))

#             elif message_type == "document":
#                 media_id = message["document"]["id"]
#                 filename = message["document"].get("filename", f"document_{media_id}.pdf")
#                 #print(f"📄 Document received from {sender_wa_id}, downloading...")

#                 loop.run_until_complete(download_media(media_id, filename))
#                 user_text = f"the name of the invoice file is {filename}"
#                 reply = loop.run_until_complete(get_agent_response(user_text, sender_wa_id))
#                 payload = get_text_message_input(sender_wa_id, reply)
#                 loop.run_until_complete(send_message(payload))


#             else:
#                 print(f"⚠️ Unsupported message type from {sender_wa_id}: {message_type}")

#             loop.close()

#         elif "statuses" in change:
#             status = change["statuses"][0]
#             #print("📬 Status update received:")
#             #print(f"- ID: {status['id']}")
#             #print(f"- Status: {status['status']}")
#             #print(f"- Recipient: {status['recipient_id']}")

#         else:
#             print("⚠️ Unhandled webhook payload structure:", json.dumps(change, indent=2))

#     except Exception as e:
#         print("❌ Error handling message:", str(e))

#     return "EVENT_RECEIVED", 200

# -----------------------------------------------
# Webhook verification
# -----------------------------------------------
# -----------------------------
# Modify webhook routing
# -----------------------------
@app.route("/webhook", methods=["POST"])
def webhook_post():
    data = request.get_json()
    print(str(data))
    try:
        change = data["entry"][0]["changes"][0]["value"]

        # ✅ Extract PHONE_NUMBER_ID dynamically
        phone_number_id = change["metadata"]["phone_number_id"]
        phone_number = change["metadata"]["display_phone_number"]

        loop = asyncio.new_event_loop()
        asyncio.set_event_loop(loop)

        if "messages" in change:
            message = change["messages"][0]
            sender_wa_id = message["from"]
            message_type = message["type"]

            if message_type == "text":
                text_body = message.get("text", {}).get("body", "")
            elif message_type == "image":
                media_id = message["image"]["id"]
                filename = f"image_{media_id}.jpg"
                loop.run_until_complete(download_media(media_id, filename))
                text_body = f"prealert with file_path: {filename}"
            elif message_type == "document":
                media_id = message["document"]["id"]
                filename = message["document"].get("filename", f"document_{media_id}.pdf")
                loop.run_until_complete(download_media(media_id, filename))
                text_body = f"the name of the file is {filename}"
            else:
                text_body = ""

            # ✅ Ensure nested dict exists for this PHONE_NUMBER_ID
            conversations.setdefault(phone_number_id, {})
            last_agents.setdefault(phone_number_id, {})
            last_seen.setdefault(phone_number_id, {})

            # Check if this customer is already in chatbot conversation
            in_chatbot = False
            for rep_id, rep in representatives.items():
                if sender_wa_id in rep["customers"] and rep.get("is_ai", False):
                    in_chatbot = True
                    break

            if in_chatbot:
                # ✅ Customer is already talking to the chatbot
                reply_text = loop.run_until_complete(
                    get_agent_response(text_body, sender_wa_id, phone_number_id)
                )
                reply = get_text_message_input(sender_wa_id, reply_text)
                loop.run_until_complete(send_message(reply, phone_number_id))
                print(f"🤖 Chatbot handled message from {sender_wa_id} on {phone_number_id}")
            else:
                # ✅ Always forward to CRM when chatbot is not established
                payload = {
                    "customer_id": sender_wa_id,
                    "customer_message": text_body,
                    "phone_number": phone_number,
                    "phone_number_id": phone_number_id,
                }
                try:
                    print(f"Forwarding to CRM: {payload}")
                    #requests.post(CRM_ENDPOINT, json=payload, timeout=5)
                    #print(f"📤 Forwarded message from {sender_wa_id} to CRM {CRM_ENDPOINT}")
                except Exception as e:
                    print(f"❌ Failed to forward to CRM: {e}")
    
    except Exception as e:
        print("❌ Error handling webhook:", str(e))
    return "EVENT_RECEIVED", 200

@app.route("/webhook", methods=["GET"])
def webhook_verify():
    VERIFY_TOKEN = os.getenv("VERIFY_TOKEN", "my_verify_token")
    mode = request.args.get("hub.mode")
    token = request.args.get("hub.verify_token")
    challenge = request.args.get("hub.challenge")
    if mode == "subscribe" and token == VERIFY_TOKEN:
        return challenge, 200
    return "❌ Verification failed", 403

@app.route("/rep/assign", methods=["POST"])
def rep_assign():
    """
    Force-assign a customer to a specific representative (including ai_agent).
    """
    data = request.get_json()
    rep_id = data["rep_id"]
    customer_id = data["customer_id"]

    if rep_id not in representatives:
        return {"error": f"Representative {rep_id} not found"}, 404

    # Remove customer from any previous rep
    for r_id, rep in representatives.items():
        if customer_id in rep["customers"]:
            rep["customers"].remove(customer_id)

    # Force-assign customer to the requested rep
    if customer_id not in representatives[rep_id]["customers"]:
        representatives[rep_id]["customers"].append(customer_id)

    return {
        "status": "assigned",
        "rep_id": rep_id,
        "customer_id": customer_id,
        "representatives": representatives,
    }, 200
# -----------------------------------------------
# Run app
# -----------------------------------------------
if __name__ == "__main__":
    app.run(host="0.0.0.0", port=8000)
