"""
Image & Video Media Processor
Adapted từ BrightBean Studio apps/media_library/services.py
Xử lý ảnh sản phẩm Canifa cho social media: resize/crop/thumbnail
"""

import io
import json
import logging
import os
import subprocess
import uuid
from datetime import datetime, timezone
from pathlib import Path
from typing import Optional

logger = logging.getLogger(__name__)

MEDIA_DIR = os.path.join(
    os.path.dirname(os.path.abspath(__file__)), "..", "..", "data", "media"
)
MEDIA_INDEX_FILE = os.path.join(MEDIA_DIR, "index.json")

# Platform-specific output sizes (px)
PLATFORM_SIZES = {
    "instagram_square":  (1080, 1080),  # Instagram 1:1
    "instagram_portrait": (1080, 1350), # Instagram 4:5
    "instagram_story":   (1080, 1920),  # Instagram 9:16 / Story
    "tiktok":            (1080, 1920),  # TikTok 9:16
    "facebook":          (1200, 630),   # Facebook link preview
    "facebook_square":   (1080, 1080),  # Facebook post
    "thumbnail":         (400, 400),    # Dashboard thumbnail
}


def _ensure_dir():
    os.makedirs(MEDIA_DIR, exist_ok=True)
    thumbs_dir = os.path.join(MEDIA_DIR, "thumbs")
    os.makedirs(thumbs_dir, exist_ok=True)


def _load_index() -> list[dict]:
    _ensure_dir()
    if not os.path.exists(MEDIA_INDEX_FILE):
        return []
    try:
        with open(MEDIA_INDEX_FILE, "r", encoding="utf-8") as f:
            return json.load(f)
    except Exception:
        return []


def _save_index(data: list[dict]):
    with open(MEDIA_INDEX_FILE, "w", encoding="utf-8") as f:
        json.dump(data, f, ensure_ascii=False, indent=2, default=str)


def _append_asset(asset: dict):
    index = _load_index()
    index.insert(0, asset)
    _save_index(index[:1000])


# ─── Image Processing (requires Pillow) ──────────────────────────────────────

def generate_image_thumbnail(
    image_bytes: bytes,
    size: tuple[int, int] = (400, 400),
    output_format: str = "JPEG",
) -> bytes:
    """
    Generate thumbnail từ image bytes.
    Từ BrightBean: LANCZOS resize, RGBA→RGB convert để đảm bảo JPEG compat.
    """
    try:
        from PIL import Image
    except ImportError:
        logger.warning("Pillow không có — skip thumbnail generation")
        return image_bytes

    img = Image.open(io.BytesIO(image_bytes))

    # Convert RGBA, P modes sang RGB (JPEG không hỗ trợ)
    if img.mode in ("RGBA", "P", "LA"):
        background = Image.new("RGB", img.size, (255, 255, 255))
        if img.mode == "RGBA":
            background.paste(img, mask=img.split()[3])
        else:
            background.paste(img)
        img = background
    elif img.mode != "RGB":
        img = img.convert("RGB")

    # LANCZOS (Antialiased resize — chất lượng tốt nhất)
    img.thumbnail(size, Image.LANCZOS)

    out = io.BytesIO()
    img.save(out, format=output_format, quality=85, optimize=True)
    return out.getvalue()


def resize_for_platform(
    image_bytes: bytes,
    platform: str,
) -> bytes:
    """
    Resize và crop ảnh theo đúng kích thước platform.
    Canifa use case: ảnh sản phẩm → fit cho từng social platform.
    """
    try:
        from PIL import Image, ImageOps
    except ImportError:
        return image_bytes

    size = PLATFORM_SIZES.get(platform)
    if not size:
        return image_bytes

    img = Image.open(io.BytesIO(image_bytes))
    if img.mode not in ("RGB", "L"):
        img = img.convert("RGB")

    # ImageOps.fit: crop center + resize giữ nguyên tỷ lệ
    img = ImageOps.fit(img, size, method=Image.LANCZOS, centering=(0.5, 0.5))

    out = io.BytesIO()
    img.save(out, format="JPEG", quality=90, optimize=True)
    return out.getvalue()


def get_image_dimensions(image_bytes: bytes) -> dict:
    """Extract width/height từ image bytes."""
    try:
        from PIL import Image
        img = Image.open(io.BytesIO(image_bytes))
        return {"width": img.width, "height": img.height, "mode": img.mode}
    except Exception:
        return {"width": 0, "height": 0, "mode": "unknown"}


# ─── Video Processing (requires ffmpeg) ──────────────────────────────────────

def generate_video_thumbnail(video_path: str, timestamp_seconds: float = 1.0) -> bytes | None:
    """
    Extract frame từ video dùng ffmpeg.
    Từ BrightBean: dùng ffmpeg -ss {ts} -vframes 1 -f image2pipe.
    """
    cmd = [
        "ffmpeg",
        "-ss", str(timestamp_seconds),
        "-i", video_path,
        "-vframes", "1",
        "-f", "image2",
        "-vf", "scale=400:400:force_original_aspect_ratio=decrease",
        "pipe:1",
        "-loglevel", "quiet",
    ]
    try:
        result = subprocess.run(cmd, capture_output=True, timeout=30)
        if result.returncode == 0 and result.stdout:
            return result.stdout
    except (FileNotFoundError, subprocess.TimeoutExpired) as e:
        logger.warning("ffmpeg thumbnail failed: %s", e)
    return None


def get_video_metadata(video_path: str) -> dict:
    """
    Extract video metadata via ffprobe.
    Từ BrightBean: parse JSON output từ ffprobe.
    """
    cmd = [
        "ffprobe",
        "-v", "quiet",
        "-print_format", "json",
        "-show_streams",
        "-show_format",
        video_path,
    ]
    try:
        result = subprocess.run(cmd, capture_output=True, text=True, timeout=15)
        if result.returncode != 0:
            return {}
        data = json.loads(result.stdout)
        video_stream = next(
            (s for s in data.get("streams", []) if s.get("codec_type") == "video"),
            {},
        )
        fmt = data.get("format", {})
        return {
            "duration": float(fmt.get("duration", 0)),
            "width":    video_stream.get("width", 0),
            "height":   video_stream.get("height", 0),
            "codec":    video_stream.get("codec_name", ""),
            "size_bytes": int(fmt.get("size", 0)),
        }
    except Exception as e:
        logger.warning("ffprobe Error: %s", e)
        return {}


# ─── Asset Management ─────────────────────────────────────────────────────────

def save_uploaded_asset(
    filename: str,
    content_bytes: bytes,
    content_type: str,
    uploaded_by: str = "user",
    tags: list[str] | None = None,
) -> dict:
    """
    Lưu asset vào media library, generate thumbnail.
    Returns asset metadata dict.
    """
    _ensure_dir()
    ext = Path(filename).suffix.lower()
    asset_id = uuid.uuid4().hex
    stored_name = f"{asset_id}{ext}"
    asset_path = os.path.join(MEDIA_DIR, stored_name)

    with open(asset_path, "wb") as f:
        f.write(content_bytes)

    is_image = content_type.startswith("image/")
    is_video = content_type.startswith("video/")

    # Generate thumbnail
    thumb_path = None
    try:
        if is_image:
            thumb_bytes = generate_image_thumbnail(content_bytes)
            thumb_path = os.path.join(MEDIA_DIR, "thumbs", f"{asset_id}.jpg")
            with open(thumb_path, "wb") as f:
                f.write(thumb_bytes)
        elif is_video:
            thumb_bytes = generate_video_thumbnail(asset_path)
            if thumb_bytes:
                thumb_path = os.path.join(MEDIA_DIR, "thumbs", f"{asset_id}.jpg")
                with open(thumb_path, "wb") as f:
                    f.write(thumb_bytes)
    except Exception as e:
        logger.warning("Thumbnail generation failed: %s", e)

    # Metadata
    if is_image:
        dims = get_image_dimensions(content_bytes)
    elif is_video:
        dims = get_video_metadata(asset_path)
    else:
        dims = {}

    asset = {
        "id":          asset_id,
        "filename":    filename,
        "stored_name": stored_name,
        "content_type": content_type,
        "size_bytes":  len(content_bytes),
        "path":        asset_path,
        "thumb_path":  thumb_path,
        "url":         f"/api/media/{asset_id}",
        "thumb_url":   f"/api/media/{asset_id}/thumb" if thumb_path else None,
        "uploaded_by": uploaded_by,
        "tags":        tags or [],
        "metadata":    dims,
        "created_at":  datetime.now(timezone.utc).isoformat(),
    }

    _append_asset(asset)
    logger.info("📁 Asset saved: %s (%d bytes)", filename, len(content_bytes))
    return asset


def list_assets(
    content_type: str | None = None,
    tag: str | None = None,
    limit: int = 50,
    offset: int = 0,
) -> dict:
    assets = _load_index()
    if content_type:
        assets = [a for a in assets if a.get("content_type", "").startswith(content_type)]
    if tag:
        assets = [a for a in assets if tag in a.get("tags", [])]
    total = len(assets)
    return {"total": total, "assets": assets[offset: offset + limit]}


def get_asset(asset_id: str) -> dict | None:
    for a in _load_index():
        if a.get("id") == asset_id:
            return a
    return None


def delete_asset(asset_id: str) -> bool:
    index = _load_index()
    asset = next((a for a in index if a.get("id") == asset_id), None)
    if not asset:
        return False
    try:
        if os.path.exists(asset.get("path", "")):
            os.remove(asset["path"])
        if asset.get("thumb_path") and os.path.exists(asset["thumb_path"]):
            os.remove(asset["thumb_path"])
    except OSError as e:
        logger.warning("delete_asset: %s", e)
    _save_index([a for a in index if a.get("id") != asset_id])
    return True
