from typing import Dict, List, Optional

import httpx

from common import logging

logger = logging.get_logger(__name__)


class FacebookPublisher:
    FB_API_VERSION = "v23.0"
    GRAPH = f"https://graph.facebook.com/{FB_API_VERSION}"
    GRAPH_VIDEO = f"https://graph-video.facebook.com/{FB_API_VERSION}"

    @staticmethod
    async def get_user_id(access_token: str) -> str:
        url = f"{FacebookPublisher.GRAPH}/me"
        params = {"fields": "id,name", "access_token": access_token}
        async with httpx.AsyncClient() as client:
            try:
                response = await client.get(url, params=params)
                response.raise_for_status()
                data = response.json()
                user_id = data.get("id")
                if not user_id:
                    raise RuntimeError("Error fetching user id from Facebook API.")
                return user_id
            except httpx.HTTPStatusError as e:
                logger.error(
                    f"[Facebook] Error HTTP {e.response.status_code}: {e.response.text}"
                )
                raise
            except Exception as e:
                logger.error(f"[Facebook] Error fetching user_id: {e}")
                raise

    @staticmethod
    async def get_user_pages_tokens(
        user_id: str, access_token: str
    ) -> List[Dict[str, str]]:
        url = f"{FacebookPublisher.GRAPH}/{user_id}/accounts"
        params = {"fields": "id,access_token", "access_token": access_token}
        async with httpx.AsyncClient() as client:
            try:
                response = await client.get(url, params=params)
                response.raise_for_status()
                data = response.json()
                if "data" not in data:
                    raise RuntimeError(
                        "Unexpected Facebook API response: missing 'data' field."
                    )
                pages_info = []
                for page in data["data"]:
                    page_id = page.get("id")
                    page_token = page.get("access_token")
                    if not (page_id and page_token):
                        continue
                    pages_info.append({"page_id": page_id, "page_token": page_token})
                return pages_info
            except httpx.HTTPStatusError as e:
                logger.error(
                    f"[Facebook API] HTTP {e.response.status_code}: {e.response.text}"
                )
                raise
            except RuntimeError as e:
                logger.error(f"[Facebook API] Data error: {e}")
                raise
            except Exception as e:
                logger.error(
                    f"[Facebook API] Unexpected error while fetching page tokens: {e}"
                )
                raise

    @staticmethod
    async def publish_video(
        page_id: str,
        page_access_token: str,
        video_url: str,
        title: Optional[str] = None,
        description: Optional[str] = None,
    ) -> str:
        url = f"{FacebookPublisher.GRAPH_VIDEO}/{page_id}/videos"
        data = {"access_token": page_access_token, "file_url": video_url}
        if title:
            data["title"] = title
        if description:
            data["description"] = description
        async with httpx.AsyncClient(timeout=None) as client:
            resp = await client.post(url, data=data)
            resp.raise_for_status()
            payload = resp.json()
            return payload["id"]

    @staticmethod
    async def publish_video_story(
        page_id: str,
        page_access_token: str,
        video_url: str,
    ) -> dict:
        start_url = f"{FacebookPublisher.GRAPH}/{page_id}/video_stories"
        start_params = {
            "upload_phase": "start",
            "access_token": page_access_token,
        }

        async with httpx.AsyncClient(timeout=None) as client:
            start_resp = await client.post(start_url, params=start_params)
            start_resp.raise_for_status()
            start_payload = start_resp.json()

            video_id = start_payload["video_id"]
            upload_url = start_payload["upload_url"]

            upload_headers = {
                "Authorization": f"OAuth {page_access_token}",
                "file_url": video_url,
            }
            upload_resp = await client.post(upload_url, headers=upload_headers)
            upload_resp.raise_for_status()

            finish_params = {
                "upload_phase": "finish",
                "video_id": video_id,
                "access_token": page_access_token,
            }
            finish_resp = await client.post(start_url, params=finish_params)
            finish_resp.raise_for_status()
            return finish_resp.json()
