import requests
from pxy_openai.assistants import OpenAIAssistant as OpenAIService  # Import the assistant service
import logging
from .models import FacebookPageAssistant
from django.core.exceptions import ObjectDoesNotExist
from pxy_neo4j.neo4j_connector import Neo4jDatabase
from .storage_backends import Neo4jStorage, PostgresStorage
from .models import FacebookPageAssistant, BotInteraction

logger = logging.getLogger(__name__)


class FacebookService:
    """
    A service to interact with the Facebook Graph API.
    """

    def __init__(self, user_access_token, facebook_api_version="v22.0"):
        self.user_access_token = user_access_token
        self.facebook_api_version = facebook_api_version
        self.base_url = f"https://graph.facebook.com/{self.facebook_api_version}"
        self.neo4j_db = Neo4jDatabase()  # Initialize Neo4j connection
        self._storages = [
            Neo4jStorage(),       # always log to Neo4j
            PostgresStorage(),    # always log to Postgres
        ]

    def reply_to_comment(self, page_id, comment_id, message):
        """
        Replies to a specific comment using the Facebook API and OpenAI Assistant.
        """
        # Retrieve the Page Access Token dynamically
        page_access_token = self._get_page_access_token(page_id)
        if not page_access_token:
            logger.error(f"Unable to retrieve access token for page ID: {page_id}")
            return None

        # Fetch the appropriate OpenAI assistant for the page
        try:
            page_assistant = FacebookPageAssistant.objects.get(page_id=page_id)
            openai_assistant_model = page_assistant.assistant
            logger.info(f"Using assistant '{openai_assistant_model.name}' for page '{page_assistant.page_name}'")
        except ObjectDoesNotExist:
            logger.error(f"No assistant configured for page ID: {page_id}")
            return None
        # Use a default message if the received message is empty
        if not message or message.strip() == "":
            message = "Thank you for sharing this comment! What do you think about it?"

        openai_service = OpenAIService(name=openai_assistant_model.name)  # Pass the model's name to the service
        bot_response = openai_service.handle_message(message)

        # Send the response to Facebook
        url = f"{self.base_url}/{comment_id}/comments"
        payload = {"message": bot_response, "access_token": page_access_token}
        try:
            response = requests.post(url, data=payload)
            response.raise_for_status()
            logger.info(f"Replied to comment ID: {comment_id}")
                        # Store the interaction in Neo4j
            self.neo4j_db.store_interaction(
                user_id=f"fb_user_{comment_id}",
                bot_id=f"fb_bot_{page_id}",
                user_message=message,
                bot_response=bot_response,
                platform="Facebook"
            )
            return response.json()
        except requests.exceptions.RequestException as e:
            logger.error(f"Failed to reply to comment ID: {comment_id}. Error: {e}")
            return None
        
    def post_comment_on_share(self, page_id, post_id, message, sender_id=None):
        """
        Posts a comment on a shared post and then on the original post.
        """

        # *Idempotency guard*:
        if BotInteraction.objects.filter(
            page__page_id=page_id,
            object_id=post_id,
            platform="Facebook"
        ).exists():
            logger.info(f"Already commented on share {post_id}, skipping.")
            return None
        
        # 1) Fetch token
        page_access_token = self._get_page_access_token(page_id)
        if not page_access_token:
            logger.error(f"Unable to retrieve access token for page ID: {page_id}")
            return None

        # 2) Fetch details
        post_details = self._get_post_details(post_id, page_access_token)
        if not post_details:
            logger.error(f"Failed to retrieve post details for post ID: {post_id}")
            return None

        description     = post_details.get("parent_message")
        parent_id       = post_details.get("parent_id")
        author_page_id  = post_details.get("parent_from_id")

        # 3) Load assistant
        try:
            page_assistant        = FacebookPageAssistant.objects.get(page_id=page_id)
            openai_assistant_model = page_assistant.assistant
        except ObjectDoesNotExist:
            logger.error(f"No assistant configured for page ID: {page_id}")
            return None

        # 4) Build prompt & get AI response
        prompt       = self._build_prompt(message, description)
        openai_svc   = OpenAIService(name=openai_assistant_model.name)
        bot_response = openai_svc.handle_message(prompt)

        # 5) Post on shared post
        shared = self._post_facebook_comment(
            post_id,
            bot_response,
            page_access_token,
            sender_id=author_page_id
        )
        if shared:
            self._store_interaction(
                page_id          = page_id,
                object_id        = post_id,
                parent_object_id = parent_id,
                prompt           = prompt,
                bot_response     = bot_response,
                platform         = "Facebook"
            )

        # 6) Post on original post
        if parent_id and shared:
            orig = self._post_facebook_comment(parent_id, bot_response, page_access_token)
        return shared

    # ─── Helper: prompt builder ────────────────────────────────────────────

    def _build_prompt(self, message: str, description: str) -> str:
        """
        Generate the same prompt logic you had inline.
        """
        if not message or message.strip() == "":
            if description:
                return (
                    f"Dr. Dr. Ekaropolus previously said: '{description}'. "
                    "Based on this, write an insightful response in the most appropriate language that engages people in scientific discussion."
                )
            else:
                return "Say something truly inspiring about science, a fact or idea that will amaze people."
        else:
            if description:
                return (
                    f"Dr. Dr. Ekaropolus previously said: '{message}', "
                    f"and the shared post describes: '{description}'. "
                    "Combine these thoughts into an engaging, fun, and insightful response in the most appropriate language."
                )
            else:
                return f"Dr. Dr. Ekaropolus said: '{message}'. Expand on this with an insightful scientific thought."


    def _store_interaction(
        self,
        page_id: str,
        object_id: str,
        parent_object_id: str | None,
        prompt: str,
        bot_response: str,
        platform: str
    ) -> None:
        """
        Dispatch this interaction to all registered storage backends.
        """
        for backend in self._storages:
            backend.store(
                page_id=page_id,
                object_id=object_id,
                parent_object_id=parent_object_id,
                prompt=prompt,
                bot_response=bot_response,
                platform=platform
            )


    
    def get_system_user_id(self):
        """
        Retrieves the system user ID using the user access token.
        """
        try:
            return '122106889202727657'
        except requests.exceptions.RequestException as e:
            logger.error(f"Error fetching system user ID: {e}")
        return None

    def _get_page_access_token(self, page_id):
        """
        Retrieves the Page Access Token for a specific Page ID.
        """
        url = f"{self.base_url}/122106889202727657/accounts?access_token={self.user_access_token}"
        try:
            response = requests.get(url)
            response.raise_for_status()
            data = response.json()

            if "data" in data:
                for page in data["data"]:
                    if page.get("id") == str(page_id):
                        page_name = page.get("name", "Unknown")
                        access_token = page.get("access_token", "No Token")
                        logger.info(f"Retrieved access token for page {page_id}: {page_name}")
                        return access_token
                logger.error(f"Error: Page ID {page_id} not found.")
            else:
                logger.error("Error: Unexpected response format from Facebook API.")
        except requests.exceptions.RequestException as e:
            logger.error(f"Error fetching Page Access Token: {e}")
        return None
    
    def _get_post_details(self, post_id, access_token):
        """
        Retrieves details of a post, including:
        - message           (the post’s own text)
        - description       (from attachments)
        - parent_id         (if it’s a share)
        - from_id           (author of THIS post)
        - parent_from_id    (author of the ORIGINAL post, if shared)
        - parent_message    (text of the ORIGINAL post, if shared)
        """
        try:
            # 1st call: get this post’s text, description, parent_id, and author
            fields = (
                "message,"
                "attachments.limit(10){description,media,media_type,target,url},"
                "parent_id,from"
            )
            url = f"{self.base_url}/{post_id}?fields={fields}&access_token={access_token}"
            resp = requests.get(url)
            resp.raise_for_status()
            data = resp.json()

            message       = data.get("message", "")
            attachments   = data.get("attachments", {}).get("data", [{}])
            description   = attachments[0].get("description", "") if attachments else ""
            parent_id     = data.get("parent_id")
            from_id       = data.get("from", {}).get("id")

            # Defaults if there is no parent
            parent_from_id  = None
            parent_message  = None

            # 2nd call: if this is a share, fetch the ORIGINAL post’s author and text
            if parent_id:
                parent_fields = "from,message"
                parent_url = f"{self.base_url}/{parent_id}?fields={parent_fields}&access_token={access_token}"
                p_resp = requests.get(parent_url)
                p_resp.raise_for_status()
                p_data = p_resp.json()
                parent_from_id  = p_data.get("from", {}).get("id")
                parent_message  = p_data.get("message", "")

            return {
                "message":         message,
                "description":     description,
                "parent_id":       parent_id,
                "from_id":         from_id,
                "parent_from_id":  parent_from_id,
                "parent_message":  parent_message,
            }

        except requests.exceptions.RequestException as e:
            logger.error(f"Failed to fetch post details for {post_id}: {e}")
            return {}

    def _post_facebook_comment(self, post_id, message, access_token, sender_id=None):
        """
        Helper function to post a comment to a specific post.
        """
    # Build the “mention” link (your Page)
        prefix = f"https://www.facebook.com/{sender_id}" if sender_id else ""

        # WhatsApp CTA link
        whatsapp_link = "https://wa.me/447887147696"

        # Assemble the final message with labels and spacing
        formatted = "\n\n".join(filter(None, [
            prefix,
            message.strip(),
            f"📱 Chat with us on WhatsApp: {whatsapp_link}"
        ]))

        url = f"{self.base_url}/{post_id}/comments"
        payload = {"message": formatted, "access_token": access_token}
        try:
            response = requests.post(url, data=payload)
            response.raise_for_status()
            logger.info(f"Posted a comment on post ID: {post_id}")
            return response.json()
        except requests.exceptions.RequestException as e:
            logger.error(f"Failed to comment on post ID: {post_id}. Error: {e}")
            return None

    