# pxy_meta_pages/admin.py
from __future__ import annotations

import json
from typing import Optional, Dict, Any

import requests
from django.conf import settings
from django.contrib import admin, messages

from .models import FacebookPageAssistant, EventType, BotInteraction
from .services import FacebookService


# -----------------------------------------------------------------------------
# Config
# -----------------------------------------------------------------------------
FACEBOOK_API_VERSION: str = getattr(settings, "FACEBOOK_API_VERSION", "v22.0")
APP_ID: Optional[str] = getattr(settings, "FACEBOOK_APP_ID", None)

# Fields we require on every Page subscription (Page Feed + Messenger)
REQUIRED_FIELDS = [
    # Page feed (comments/shares/mentions)
    "feed",
    "mention",
    # Messenger
    "messages",
    "messaging_postbacks",
    "message_reads",
    "message_deliveries",
    "message_reactions",
    "message_echoes",
]


# -----------------------------------------------------------------------------
# Small Graph helpers with consistent error handling
# -----------------------------------------------------------------------------
def _graph_get(url: str, params: Dict[str, Any]) -> Dict[str, Any]:
    """GET wrapper that raises RequestException on Graph errors."""
    resp = requests.get(url, params=params, timeout=15)
    data = resp.json() if resp.content else {}
    if isinstance(data, dict) and "error" in data:
        # Normalize to RequestException so callers can unify handling
        raise requests.RequestException(json.dumps(data["error"]))
    resp.raise_for_status()
    return data or {}


def _graph_post(url: str, data: Dict[str, Any]) -> Dict[str, Any]:
    """POST wrapper that raises RequestException on Graph errors."""
    resp = requests.post(url, data=data, timeout=15)
    payload = resp.json() if resp.content else {}
    if isinstance(payload, dict) and "error" in payload:
        raise requests.RequestException(json.dumps(payload["error"]))
    resp.raise_for_status()
    return payload or {}


def _decode_graph_error(e: requests.RequestException) -> str:
    """
    Attempt to pretty-print a Graph API error dict, else return the raw message.
    """
    msg = str(e)
    try:
        err = json.loads(msg)
        # Typical Graph error shape
        code = err.get("code")
        sub = err.get("error_subcode")
        text = err.get("message", "Graph error")
        return f"Graph error (code={code}, subcode={sub}): {text}"
    except Exception:
        return msg


def _get_page_token(fb_service: FacebookService, page_id: str) -> Optional[str]:
    """
    Works with either a public get_page_access_token or the private _get_page_access_token.
    """
    getter = getattr(fb_service, "get_page_access_token", None)
    if callable(getter):
        return getter(page_id)
    private_getter = getattr(fb_service, "_get_page_access_token", None)
    if callable(private_getter):
        return private_getter(page_id)
    return None


# -----------------------------------------------------------------------------
# Admins
# -----------------------------------------------------------------------------
@admin.register(FacebookPageAssistant)
class FacebookPageAssistantAdmin(admin.ModelAdmin):
    """
    Admin for wiring a Facebook Page to an OpenAI assistant and managing webhook subscriptions.
    """
    list_display = (
        "page_name",
        "page_id",
        "assistant",
        "is_subscribed",
        "created_at",
        "comment_count",
        "share_count",
    )
    search_fields = ("page_name", "page_id", "assistant__name")
    list_filter = ("is_subscribed", "assistant")

    actions = [
        "ensure_feed_and_messenger_subscription",
        "check_subscription_status",
        "probe_messenger_access",
    ]

    # ----- Counters ----------------------------------------------------------
    def comment_count(self, obj: FacebookPageAssistant) -> int:
        return obj.events.filter(event_type__code="comment").count()

    comment_count.short_description = "Comments"

    def share_count(self, obj: FacebookPageAssistant) -> int:
        return obj.events.filter(event_type__code="share").count()

    share_count.short_description = "Shares"

    # ----- Action 1: Ensure required fields (feed + Messenger) --------------
    def ensure_feed_and_messenger_subscription(self, request, queryset):
        """
        For each selected Page:
          1) Fetch the Page Access Token via FacebookService.
          2) Read current subscribed_fields.
          3) Add any missing REQUIRED_FIELDS in a single POST.
        """
        fb_service = FacebookService(user_access_token=settings.PAGE_ACCESS_TOKEN)

        for page in queryset:
            try:
                page_access_token = _get_page_token(fb_service, page.page_id)
                if not page_access_token:
                    self.message_user(
                        request,
                        f"[{page.page_name}] Unable to obtain Page Access Token.",
                        level=messages.ERROR,
                    )
                    continue

                list_url = f"https://graph.facebook.com/{FACEBOOK_API_VERSION}/{page.page_id}/subscribed_apps"
                current_data = _graph_get(list_url, {"access_token": page_access_token})
                entries = current_data.get("data", [])

                # If APP_ID is known, narrow to our app row; otherwise use first row if present
                app_entry = None
                if APP_ID:
                    app_entry = next((e for e in entries if str(e.get("id")) == str(APP_ID)), None)
                if app_entry is None and entries:
                    app_entry = entries[0]

                current_fields = set(app_entry.get("subscribed_fields", [])) if app_entry else set()
                required = set(REQUIRED_FIELDS)

                if required - current_fields:
                    new_fields_csv = ",".join(sorted(current_fields | required))
                    _graph_post(list_url, {
                        "subscribed_fields": new_fields_csv,
                        "access_token": page_access_token,
                    })
                    page.is_subscribed = True
                    page.save(update_fields=["is_subscribed"])
                    self.message_user(
                        request,
                        f"[{page.page_name}] Subscribed/updated. Now includes: {new_fields_csv}",
                        level=messages.SUCCESS,
                    )
                else:
                    page.is_subscribed = True
                    page.save(update_fields=["is_subscribed"])
                    self.message_user(
                        request,
                        f"[{page.page_name}] Already has required fields.",
                        level=messages.INFO,
                    )

            except requests.RequestException as e:
                self.message_user(
                    request,
                    f"[{page.page_name}] {_decode_graph_error(e)}",
                    level=messages.ERROR,
                )
            except Exception as e:
                self.message_user(
                    request,
                    f"[{page.page_name}] Unexpected error: {e}",
                    level=messages.ERROR,
                )

    ensure_feed_and_messenger_subscription.short_description = "Ensure Webhooks (feed + Messenger)"

    # ----- Action 2: Check subscription status ------------------------------
    def check_subscription_status(self, request, queryset):
        """
        Shows the exact subscribed_fields currently active for each Page.
        """
        fb_service = FacebookService(user_access_token=settings.PAGE_ACCESS_TOKEN)

        for page in queryset:
            try:
                page_access_token = _get_page_token(fb_service, page.page_id)
                if not page_access_token:
                    self.message_user(
                        request,
                        f"[{page.page_name}] Unable to obtain Page Access Token.",
                        level=messages.ERROR,
                    )
                    continue

                url = f"https://graph.facebook.com/{FACEBOOK_API_VERSION}/{page.page_id}/subscribed_apps"
                data = _graph_get(url, {"access_token": page_access_token})
                entries = data.get("data", [])

                app_entry = None
                if APP_ID:
                    app_entry = next((e for e in entries if str(e.get("id")) == str(APP_ID)), None)
                if app_entry is None and entries:
                    app_entry = entries[0]

                fields = app_entry.get("subscribed_fields", []) if app_entry else []
                page.is_subscribed = bool(fields)
                page.save(update_fields=["is_subscribed"])

                has_all = set(REQUIRED_FIELDS).issubset(set(fields))
                level = messages.SUCCESS if has_all else messages.WARNING
                self.message_user(
                    request,
                    f"[{page.page_name}] Subscribed fields: {', '.join(fields) if fields else '(none)'}",
                    level=level,
                )

            except requests.RequestException as e:
                self.message_user(
                    request,
                    f"[{page.page_name}] {_decode_graph_error(e)}",
                    level=messages.ERROR,
                )
            except Exception as e:
                self.message_user(
                    request,
                    f"[{page.page_name}] Unexpected error: {e}",
                    level=messages.ERROR,
                )

    check_subscription_status.short_description = "Check webhook subscription fields"

    # ----- Action 3: Probe Messenger access ---------------------------------
    def probe_messenger_access(self, request, queryset):
        """
        Light probe for Messenger perms using /{PAGE_ID}/conversations.
        (In Dev Mode, you’ll only see app-role users here.)
        """
        fb_service = FacebookService(user_access_token=settings.PAGE_ACCESS_TOKEN)

        for page in queryset:
            try:
                page_access_token = _get_page_token(fb_service, page.page_id)
                if not page_access_token:
                    self.message_user(
                        request,
                        f"[{page.page_name}] Unable to obtain Page Access Token.",
                        level=messages.ERROR,
                    )
                    continue

                url = f"https://graph.facebook.com/{FACEBOOK_API_VERSION}/{page.page_id}/conversations"
                data = _graph_get(url, {"access_token": page_access_token, "limit": 1})
                total = len(data.get("data", []))
                self.message_user(
                    request,
                    (
                        f"[{page.page_name}] Messenger probe OK. Conversations sample: {total}. "
                        "Note: in Dev Mode you’ll only see app-role users."
                    ),
                    level=messages.SUCCESS,
                )

            except requests.RequestException as e:
                msg = _decode_graph_error(e)
                # Add quick hints for common codes
                hint = ""
                if '"code": 190' in msg or "Invalid OAuth 2.0" in msg:
                    hint = " (Token invalid/expired)"
                elif '"code": 200' in msg:
                    hint = " (Permissions error: check pages_messaging & pages_manage_metadata; app roles or Advanced Access)"
                elif '"code": 10' in msg:
                    hint = " (Permission denied: user role or access level missing)"
                self.message_user(
                    request,
                    f"[{page.page_name}] Messenger probe failed: {msg}{hint}",
                    level=messages.ERROR,
                )
            except Exception as e:
                self.message_user(
                    request,
                    f"[{page.page_name}] Unexpected error: {e}",
                    level=messages.ERROR,
                )

    probe_messenger_access.short_description = "Probe Messenger access"


@admin.register(EventType)
class EventTypeAdmin(admin.ModelAdmin):
    list_display = ("code", "label")
    search_fields = ("code", "label")


@admin.register(BotInteraction)
class BotInteractionAdmin(admin.ModelAdmin):
    list_display = ("page", "object_id", "parent_object_id", "platform", "created_at")
    search_fields = ("object_id", "prompt", "bot_response")
    list_filter = ("platform",)
