# Familiar - Self-Hosted AI Companion Platform
# Copyright (c) 2026 George Scott Foley
# ORCID: 0009-0006-4957-0540
# Email: Georgescottfoley@proton.me
# Licensed under the MIT License - see LICENSE file for details

"""
Cloudinary Image Management Skill

Upload, browse, transform, and generate URLs for images.
Uses the Cloudinary REST API directly (no Python SDK needed).

Setup:
    CLOUDINARY_CLOUD_NAME=your_cloud_name
    CLOUDINARY_API_KEY=your_api_key
    CLOUDINARY_API_SECRET=your_api_secret

Get credentials at: https://cloudinary.com/console

API: https://api.cloudinary.com/v1_1/
"""

import hashlib
import logging
import time

from familiar.core.api_cache import cached
from familiar.skills._api_utils import (
    APIError,
    api_get,
    api_post,
    get_env,
)

logger = logging.getLogger(__name__)


def _cloud_name() -> str:
    return get_env("CLOUDINARY_CLOUD_NAME") or ""


def _api_key() -> str:
    return get_env("CLOUDINARY_API_KEY") or ""


def _api_secret() -> str:
    return get_env("CLOUDINARY_API_SECRET") or ""


def _base_url() -> str:
    return f"https://api.cloudinary.com/v1_1/{_cloud_name()}"


def _check_config() -> str:
    if not _cloud_name() or not _api_key() or not _api_secret():
        return (
            "Cloudinary not configured.\n"
            "Set CLOUDINARY_CLOUD_NAME, CLOUDINARY_API_KEY, and CLOUDINARY_API_SECRET.\n"
            "Get credentials at: https://cloudinary.com/console"
        )
    return ""


def _auth_headers() -> dict:
    """Return basic-auth header for the Cloudinary admin API."""
    import base64

    creds = base64.b64encode(f"{_api_key()}:{_api_secret()}".encode()).decode()
    return {"Authorization": f"Basic {creds}"}


def _sign_params(params: dict) -> dict:
    """Sign request params with API secret for upload API."""
    params["timestamp"] = str(int(time.time()))
    params["api_key"] = _api_key()

    # Build signature string: sorted params joined with &
    sign_parts = []
    for key in sorted(params.keys()):
        if key in ("api_key", "api_secret", "resource_type", "file"):
            continue
        sign_parts.append(f"{key}={params[key]}")
    sign_string = "&".join(sign_parts) + _api_secret()

    params["signature"] = hashlib.sha1(sign_string.encode()).hexdigest()
    return params


# ---------------------------------------------------------------------------
# Tool handlers
# ---------------------------------------------------------------------------


def gallery_images(data: dict) -> str:
    """Browse images in your Cloudinary account."""
    err = _check_config()
    if err:
        return err

    prefix = data.get("folder", "")
    max_results = min(int(data.get("limit", 20)), 100)
    resource_type = data.get("resource_type", "image")

    try:
        result = _gallery_cached(prefix, max_results, resource_type)

        resources = result.get("resources", [])
        if not resources:
            if prefix:
                return f"No images found in folder '{prefix}'."
            return "No images found in your Cloudinary account."

        total = result.get("total_count", len(resources))
        lines = []
        if prefix:
            lines.append(f"**Images in '{prefix}'** ({total} total):")
        else:
            lines.append(f"**Recent Images** ({total} total):")
        lines.append("")

        for i, r in enumerate(resources, 1):
            public_id = r.get("public_id", "")
            fmt = r.get("format", "")
            width = r.get("width", 0)
            height = r.get("height", 0)
            size_bytes = r.get("bytes", 0)
            created = r.get("created_at", "")
            url = r.get("secure_url", r.get("url", ""))

            size_kb = size_bytes / 1024 if size_bytes else 0
            lines.append(f"{i}. **{public_id}.{fmt}**")
            details = []
            if width and height:
                details.append(f"{width}x{height}")
            if size_kb:
                details.append(f"{size_kb:.0f} KB")
            if created:
                details.append(created[:10])
            if details:
                lines.append(f"   {' | '.join(details)}")
            if url:
                lines.append(f"   {url}")
            lines.append("")

        return "\n".join(lines)

    except APIError as e:
        return str(e)
    except Exception as e:
        logger.error("Cloudinary gallery error: %s", e)
        return f"Error fetching images: {e}"


@cached(prefix="cloudinary_gallery", ttl=300)
def _gallery_cached(prefix: str, max_results: int, resource_type: str) -> dict:
    params = {"max_results": max_results, "resource_type": resource_type}
    if prefix:
        params["prefix"] = prefix
        params["type"] = "upload"
    return api_get(
        f"{_base_url()}/resources/{resource_type}",
        params=params,
        headers=_auth_headers(),
        service_name="Cloudinary",
    )


def upload_image(data: dict) -> str:
    """Upload an image to Cloudinary from a URL."""
    err = _check_config()
    if err:
        return err

    image_url = data.get("url", "").strip()
    if not image_url:
        return "Please provide an image URL to upload."

    public_id = data.get("public_id", "")
    folder = data.get("folder", "")
    tags = data.get("tags", "")

    try:
        params = {"file": image_url}
        if public_id:
            params["public_id"] = public_id
        if folder:
            params["folder"] = folder
        if tags:
            params["tags"] = tags

        signed = _sign_params(params)

        result = api_post(
            f"{_base_url()}/image/upload",
            data=signed,
            service_name="Cloudinary",
        )

        pid = result.get("public_id", "")
        secure_url = result.get("secure_url", "")
        width = result.get("width", 0)
        height = result.get("height", 0)
        fmt = result.get("format", "")
        size_bytes = result.get("bytes", 0)

        lines = [
            "**Image uploaded successfully!**",
            "",
            f"  Public ID: {pid}",
            f"  Format: {fmt}",
            f"  Size: {width}x{height} ({size_bytes / 1024:.0f} KB)",
            f"  URL: {secure_url}",
        ]
        return "\n".join(lines)

    except APIError as e:
        return str(e)
    except Exception as e:
        logger.error("Cloudinary upload error: %s", e)
        return f"Error uploading image: {e}"


def transform_image(data: dict) -> str:
    """Generate a transformed image URL with Cloudinary transformations."""
    err = _check_config()
    if err:
        return err

    public_id = data.get("public_id", "").strip()
    if not public_id:
        return "Please provide a public_id of the image to transform."

    width = data.get("width", "")
    height = data.get("height", "")
    crop = data.get("crop", "")
    quality = data.get("quality", "")
    fmt = data.get("format", "")
    effect = data.get("effect", "")

    # Build transformation string
    transforms = []
    if width:
        transforms.append(f"w_{width}")
    if height:
        transforms.append(f"h_{height}")
    if crop:
        transforms.append(f"c_{crop}")
    if quality:
        transforms.append(f"q_{quality}")
    if fmt:
        transforms.append(f"f_{fmt}")
    if effect:
        transforms.append(f"e_{effect}")

    if not transforms:
        return (
            "Please provide at least one transformation:\n"
            "  width, height, crop (fill/fit/scale/thumb),\n"
            "  quality (auto/1-100), format (webp/png/jpg), effect (grayscale/sepia)"
        )

    transform_str = ",".join(transforms)
    cloud = _cloud_name()

    # Determine file extension
    ext = fmt if fmt else "jpg"
    url = f"https://res.cloudinary.com/{cloud}/image/upload/{transform_str}/{public_id}.{ext}"

    lines = [
        "**Transformed Image URL:**",
        "",
        f"  {url}",
        "",
        f"  Transformations: {transform_str}",
        f"  Public ID: {public_id}",
    ]
    return "\n".join(lines)


def image_url(data: dict) -> str:
    """Get the URL for an image by public ID."""
    err = _check_config()
    if err:
        return err

    public_id = data.get("public_id", "").strip()
    if not public_id:
        return "Please provide a public_id."

    fmt = data.get("format", "jpg")
    cloud = _cloud_name()

    original = f"https://res.cloudinary.com/{cloud}/image/upload/{public_id}.{fmt}"
    thumb = f"https://res.cloudinary.com/{cloud}/image/upload/w_300,h_300,c_thumb/{public_id}.{fmt}"

    lines = [
        f"**Image: {public_id}**",
        "",
        f"  Original: {original}",
        f"  Thumbnail: {thumb}",
    ]
    return "\n".join(lines)


# ---------------------------------------------------------------------------
# Tool definitions
# ---------------------------------------------------------------------------

TOOLS = [
    {
        "name": "gallery_images",
        "description": (
            "Browse images in your Cloudinary account."
            " Shows public IDs, dimensions, sizes, and URLs."
            " Filter by folder prefix."
        ),
        "input_schema": {
            "type": "object",
            "properties": {
                "folder": {
                    "type": "string",
                    "description": "Folder prefix to filter by (empty for all)",
                    "default": "",
                },
                "limit": {
                    "type": "integer",
                    "description": "Max results (1-100, default 20)",
                    "default": 20,
                },
            },
        },
        "handler": gallery_images,
        "category": "cloudinary_img",
    },
    {
        "name": "upload_image",
        "description": (
            "Upload an image to Cloudinary from a URL."
            " Supports custom public IDs, folders, and tags."
        ),
        "input_schema": {
            "type": "object",
            "properties": {
                "url": {
                    "type": "string",
                    "description": "Image URL to upload",
                },
                "public_id": {
                    "type": "string",
                    "description": "Custom public ID (auto-generated if empty)",
                },
                "folder": {
                    "type": "string",
                    "description": "Target folder in Cloudinary",
                },
                "tags": {
                    "type": "string",
                    "description": "Comma-separated tags",
                },
            },
            "required": ["url"],
        },
        "handler": upload_image,
        "category": "cloudinary_img",
    },
    {
        "name": "transform_image",
        "description": (
            "Generate a transformed image URL using Cloudinary transformations."
            " Resize, crop, change quality/format, apply effects."
        ),
        "input_schema": {
            "type": "object",
            "properties": {
                "public_id": {
                    "type": "string",
                    "description": "Image public ID",
                },
                "width": {"type": "integer", "description": "Target width"},
                "height": {"type": "integer", "description": "Target height"},
                "crop": {
                    "type": "string",
                    "description": "Crop mode: fill, fit, scale, thumb, crop",
                },
                "quality": {
                    "type": "string",
                    "description": "Quality: auto, or 1-100",
                },
                "format": {
                    "type": "string",
                    "description": "Output format: webp, png, jpg, avif",
                },
                "effect": {
                    "type": "string",
                    "description": "Effect: grayscale, sepia, blur, sharpen",
                },
            },
            "required": ["public_id"],
        },
        "handler": transform_image,
        "category": "cloudinary_img",
    },
    {
        "name": "image_url",
        "description": ("Get the original and thumbnail URLs for an image by public ID."),
        "input_schema": {
            "type": "object",
            "properties": {
                "public_id": {
                    "type": "string",
                    "description": "Image public ID",
                },
                "format": {
                    "type": "string",
                    "description": "Image format (default: jpg)",
                    "default": "jpg",
                },
            },
            "required": ["public_id"],
        },
        "handler": image_url,
        "category": "cloudinary_img",
    },
]
