# -*- coding: utf-8 -*-
"""유튜브(Google OAuth + YouTube Data API v3) 클라이언트.

castad app/social/oauth/youtube.py + uploader/youtube.py 이식·축약.
- OAuth: 인증 URL 생성 → 코드 교환(access/refresh) → 리프레시 → 내 채널 정보
- 업로드: resumable upload 세션 시작 → 파일 PUT → video_id
"""
from urllib.parse import urlencode

import aiohttp
from fastapi import HTTPException

from .config import settings

AUTHORIZATION_URL = "https://accounts.google.com/o/oauth2/v2/auth"
TOKEN_URL = "https://oauth2.googleapis.com/token"
CHANNELS_URL = "https://www.googleapis.com/youtube/v3/channels"
UPLOAD_URL = "https://www.googleapis.com/upload/youtube/v3/videos"

SCOPES = [
    "https://www.googleapis.com/auth/youtube.upload",
    "https://www.googleapis.com/auth/youtube.readonly",
]


def get_authorization_url(state: str) -> str:
    if not (settings.YOUTUBE_CLIENT_ID and settings.YOUTUBE_CLIENT_SECRET):
        raise HTTPException(501, "유튜브 연동 미설정 — YOUTUBE_CLIENT_ID/SECRET 필요")
    params = {
        "client_id": settings.YOUTUBE_CLIENT_ID,
        "redirect_uri": settings.YOUTUBE_REDIRECT_URI,
        "response_type": "code",
        "scope": " ".join(SCOPES),
        "access_type": "offline",   # refresh_token 발급
        "prompt": "consent",        # 매번 동의 → refresh_token 보장
        "state": state,
    }
    return f"{AUTHORIZATION_URL}?{urlencode(params)}"


async def exchange_code(code: str) -> dict:
    """인가코드 → {access_token, refresh_token, expires_in}."""
    data = {
        "client_id": settings.YOUTUBE_CLIENT_ID,
        "client_secret": settings.YOUTUBE_CLIENT_SECRET,
        "code": code,
        "grant_type": "authorization_code",
        "redirect_uri": settings.YOUTUBE_REDIRECT_URI,
    }
    async with aiohttp.ClientSession() as s:
        async with s.post(TOKEN_URL, data=data) as r:
            res = await r.json()
    if "error" in res:
        raise HTTPException(400, f"유튜브 토큰 교환 실패: {res.get('error_description', res.get('error'))}")
    return res


async def refresh_access_token(refresh_token: str) -> str:
    data = {
        "client_id": settings.YOUTUBE_CLIENT_ID,
        "client_secret": settings.YOUTUBE_CLIENT_SECRET,
        "refresh_token": refresh_token,
        "grant_type": "refresh_token",
    }
    async with aiohttp.ClientSession() as s:
        async with s.post(TOKEN_URL, data=data) as r:
            res = await r.json()
    if "error" in res:
        raise HTTPException(401, f"유튜브 토큰 갱신 실패: {res.get('error_description', res.get('error'))}")
    return res["access_token"]


async def get_channel_info(access_token: str) -> dict:
    """내 유튜브 채널 → {id, title}."""
    headers = {"Authorization": f"Bearer {access_token}"}
    params = {"part": "snippet", "mine": "true"}
    async with aiohttp.ClientSession() as s:
        async with s.get(CHANNELS_URL, headers=headers, params=params) as r:
            data = await r.json()
    items = data.get("items") or []
    if not items:
        return {"id": "", "title": "내 채널"}
    return {"id": items[0]["id"], "title": items[0]["snippet"]["title"]}


async def upload_video(video_path: str, access_token: str, title: str,
                       description: str = "", tags: list[str] | None = None,
                       privacy: str = "public") -> dict:
    """영상 업로드(resumable). → {video_id, url}."""
    import os
    if not os.path.exists(video_path):
        raise HTTPException(404, f"업로드할 파일이 없습니다: {video_path}")
    file_size = os.path.getsize(video_path)
    body = {
        "snippet": {
            "title": title[:100] or "썰박스",
            "description": (description or "").replace("<", "").replace(">", ""),
            "tags": tags or ["썰박스", "쇼츠", "홍보"],
            "categoryId": "22",
        },
        "status": {"privacyStatus": privacy, "selfDeclaredMadeForKids": False},
    }
    init_headers = {
        "Authorization": f"Bearer {access_token}",
        "Content-Type": "application/json; charset=utf-8",
        "X-Upload-Content-Type": "video/*",
        "X-Upload-Content-Length": str(file_size),
    }
    async with aiohttp.ClientSession() as s:
        # 1) resumable 세션 시작
        async with s.post(UPLOAD_URL, params={"uploadType": "resumable", "part": "snippet,status"},
                          headers=init_headers, json=body) as r:
            if r.status != 200:
                err = await r.json()
                raise HTTPException(502, f"유튜브 업로드 세션 실패: {err.get('error', {}).get('message', r.status)}")
            upload_url = r.headers.get("Location")
        if not upload_url:
            raise HTTPException(502, "유튜브 업로드 URL을 받지 못했습니다.")
        # 2) 파일 업로드(단일 PUT — 쇼츠는 소용량)
        with open(video_path, "rb") as f:
            content = f.read()
        put_headers = {
            "Authorization": f"Bearer {access_token}",
            "Content-Type": "video/*",
            "Content-Length": str(file_size),
        }
        async with s.put(upload_url, headers=put_headers, data=content) as r:
            res = await r.json()
    vid = res.get("id")
    if not vid:
        raise HTTPException(502, f"유튜브 업로드 실패: {res.get('error', {}).get('message', '알 수 없는 오류')}")
    return {"video_id": vid, "url": f"https://www.youtube.com/watch?v={vid}"}
