import math
import httpx
from common import logging
from common.models.stream_signal import TikTokSettings

logger = logging.get_logger(__name__)


class TiktokPublisher:
    MIN_CHUNKS = 1
    MAX_CHUNKS = 1000
    MIN_CHUNK_SIZE = 5242880
    MAX_CHUNK_SIZE = 67108864

    @classmethod
    def calculate_chunking(cls, video_size: int) -> tuple[int, int]:
        """
        Returns (chunk_size, total_chunks) minimizing chunks while honoring limits.
        """
        total_chunks = math.ceil(video_size / cls.MAX_CHUNK_SIZE)
        total_chunks = min(max(total_chunks, cls.MIN_CHUNKS), cls.MAX_CHUNKS)
        chunk_size = math.floor(video_size / total_chunks)
        if chunk_size < cls.MIN_CHUNK_SIZE:
            chunk_size = cls.MIN_CHUNK_SIZE
            total_chunks = math.ceil(video_size / chunk_size)
        return chunk_size, total_chunks

    @staticmethod
    async def initiate_tiktok_upload(
        access_token: str, title: str, video_size: int, tiktok_settings: TikTokSettings
    ) -> tuple[str, str]:
        url = "https://open.tiktokapis.com/v2/post/publish/video/init/"
        headers = {
            "Authorization": f"Bearer {access_token}",
            "Content-Type": "application/json",
        }
        chunk_size, total_chunks = TiktokPublisher.calculate_chunking(video_size)
        payload = {
            "post_info": {
                "title": title or "Check this out!!",
                "privacy_level": tiktok_settings.privacy_settings,
                "disable_duet": not tiktok_settings.duet,
                "disable_comment": not tiktok_settings.comment,
                "disable_stitch": not tiktok_settings.stitch,
                "brand_content_toggle": tiktok_settings.paid_partnership,
                "brand_organic_toggle": tiktok_settings.promoting_yourself,
                "video_cover_timestamp_ms": 1000,
            },
            "source_info": {
                "source": "FILE_UPLOAD",
                "video_size": video_size,
                "chunk_size": chunk_size,
                "total_chunk_count": total_chunks,
            },
        }

        logger.info("[StreamSignal] Tiktok payload", extra={"payload": payload})
        async with httpx.AsyncClient() as client:
            response = await client.post(url, headers=headers, json=payload)
            response.raise_for_status()
            data = response.json()["data"]
            return data["upload_url"], data["publish_id"]

    @staticmethod
    async def upload_video_to_tiktok(
        upload_url: str, video_size: int, video_bytes: bytes
    ) -> None:
        chunk_size, total_chunks = TiktokPublisher.calculate_chunking(video_size)
        async with httpx.AsyncClient(timeout=None) as client:
            try:
                for i in range(total_chunks):
                    start = i * chunk_size
                    end = video_size if i == total_chunks - 1 else start + chunk_size
                    chunk = video_bytes[start:end]
                    headers = {
                        "Content-Length": str(len(chunk)),
                        "Content-Type": "video/mp4",
                        "Content-Range": f"bytes {start}-{end - 1}/{video_size}",
                    }
                    put_response = await client.put(
                        upload_url, headers=headers, content=chunk
                    )
                    put_response.raise_for_status()
                logger.info("[TikTok] Upload completed successfully.")
            except httpx.HTTPStatusError as e:
                logger.error(
                    f"[TikTok] Upload failed with status {e.response.status_code}: {e.response.text}"
                )
                raise
            except Exception as e:
                logger.error(f"[TikTok] Unexpected error during upload: {e}")
                raise
