"""Helper functions shared across CLI modes."""

import argparse
import json
import os
import shutil
import sys

from .fanart_composer import FANART_SUFFIX, FANART_WIDTH_4K, FANART_HEIGHT_4K, compose_fanart
from .metadata import build_metadata, embed_metadata
from .poster_composer import compose_landscape_with_text, compose_poster

EXIT_SUCCESS = 0
EXIT_ERROR = 1
EXIT_NO_SELECTION = 2
EXIT_AI_FAILED = 3


def _resolve_output_path(
    input_path: str,
    output_dir: str | None,
    output_name_suffix: str,
) -> str:
    """Resolve the final output path for the poster image."""
    base_dir = output_dir or os.path.dirname(os.path.abspath(input_path))
    os.makedirs(base_dir, exist_ok=True)
    input_stem = os.path.splitext(os.path.basename(input_path))[0]
    return os.path.join(base_dir, f"{input_stem}{output_name_suffix}.jpg")


def _emit_result(
    poster_path: str,
    frame_index: int,
    mode: str,
    reasoning: str,
    input_path: str,
    use_json: bool,
    fmt: str = "poster",
    crop_position: str = "",
    overlay_title: str = "",
    source: str = "frame",
    overlay_category: str = "",
    overlay_note: str = "",
    badges: list[str] | None = None,
    fanart_path: str | None = None,
) -> None:
    """Write result to stdout."""
    if use_json:
        payload: dict = {
            "poster_path": os.path.abspath(poster_path),
            "frame_index": frame_index,
            "mode": mode,
            "format": fmt,
            "source": source,
            "reasoning": reasoning,
            "input_path": os.path.abspath(input_path),
        }
        if crop_position:
            payload["crop_position"] = crop_position
        if overlay_title:
            payload["overlay_title"] = overlay_title
        if overlay_category:
            payload["overlay_category"] = overlay_category
        if overlay_note:
            payload["overlay_note"] = overlay_note
        if badges:
            payload["badges"] = badges
        if fanart_path:
            payload["fanart_path"] = os.path.abspath(fanart_path)
        print(json.dumps(payload, ensure_ascii=False))
    else:
        print(os.path.abspath(poster_path))


def _resolve_overlay_title(args: argparse.Namespace) -> str:
    """Return the overlay title to use, or an empty string if none."""
    if getattr(args, "overlay_title", None):
        return args.overlay_title
    if getattr(args, "overlay_title_from_filename", False):
        return os.path.splitext(os.path.basename(args.input_path))[0]
    return ""


def _resolve_category(args: argparse.Namespace) -> tuple[str | None, str | None]:
    """Return (overlay_category, overlay_category_logo_path) based on CLI args.

    If both ``--overlay-category`` and ``--overlay-category-logo`` are provided,
    the logo takes precedence and a warning is emitted to stderr.
    """
    category: str | None = getattr(args, "overlay_category", None)
    category_logo: str | None = getattr(args, "overlay_category_logo", None)

    if category and category_logo:
        print(
            "Warning: both --overlay-category and --overlay-category-logo provided; logo takes precedence.",
            file=sys.stderr,
        )
        return None, category_logo

    return category or None, category_logo or None


def _apply_postprocess(
    highres_path: str,
    poster_path: str,
    fmt: str,
    crop_position: str,
    overlay_title: str,
    overlay_category: str | None = None,
    overlay_category_logo_path: str | None = None,
    overlay_note: str | None = None,
    template: dict | None = None,
    badges: list[str] | None = None,
) -> None:
    """Apply format-specific post-processing to a high-res frame."""
    if fmt == "poster":
        compose_poster(
            highres_path, crop_position or "center", overlay_title or None, poster_path,
            overlay_category=overlay_category,
            overlay_category_logo_path=overlay_category_logo_path,
            overlay_note=overlay_note,
            template=template,
            badges=badges,
        )
    elif overlay_title:
        compose_landscape_with_text(highres_path, overlay_title, poster_path, template=template)
    else:
        shutil.copy2(highres_path, poster_path)


def _generate_fanart_if_requested(
    args: argparse.Namespace,
    highres_path: str,
    video_properties: dict | None = None,
) -> str | None:
    """Generate a fanart image if ``--fanart`` was requested.

    Parameters
    ----------
    args:
        Parsed CLI arguments.
    highres_path:
        Path to the already-converted sRGB JPEG source frame.
    video_properties:
        Video properties dict (from :func:`get_video_properties`), or ``None``
        for image input.  When ``None`` the source image dimensions are used to
        determine 4K vs HD.

    Returns
    -------
    The absolute path to the created fanart file, or ``None`` when fanart was
    not requested or failed.
    """
    if not getattr(args, "fanart", False):
        return None

    if video_properties is not None:
        is_4k = bool(video_properties.get("is_4k", False))
    else:
        # Image input: check source dimensions directly
        try:
            from PIL import Image as _Image
            with _Image.open(highres_path) as _img:
                _w, _h = _img.size
            is_4k = (_w >= FANART_WIDTH_4K or _h >= FANART_HEIGHT_4K)
        except Exception:
            is_4k = False

    fanart_path = _resolve_output_path(args.input_path, args.output_dir, FANART_SUFFIX)
    try:
        compose_fanart(highres_path, fanart_path, is_4k=is_4k)
        print(f"   🖼️  Fanart-Bild erstellt: {fanart_path}", file=sys.stderr)
    except Exception as exc:
        print(f"   Error creating fanart: {exc}", file=sys.stderr)
        return None

    return fanart_path


def _finalize_frame(
    args: argparse.Namespace,
    frame_index: int,
    mode: str,
    reasoning: str,
    highres_path: str,
    crop_position: str,
) -> int:
    """Common post-processing logic for all three frame-selection modes.

    Applies overlays, embeds metadata, optionally creates fanart, and emits the
    result.  Returns an exit code.
    """
    overlay_title = _resolve_overlay_title(args)
    category, category_logo_path = _resolve_category(args)
    note: str | None = getattr(args, "overlay_note", None)
    detected_badges: list[str] = getattr(args, "detected_badges", [])
    poster_path = _resolve_output_path(args.input_path, args.output_dir, args.output_name_suffix)
    try:
        _apply_postprocess(
            highres_path, poster_path, args.format, crop_position, overlay_title,
            overlay_category=category, overlay_category_logo_path=category_logo_path,
            overlay_note=note, template=getattr(args, "template", None),
            badges=detected_badges,
        )
    except Exception as exc:
        print(f"   Error composing output image: {exc}", file=sys.stderr)
        return EXIT_ERROR

    metadata = build_metadata(
        source="frame", frame_index=frame_index, crop_position=crop_position,
        fmt=args.format, mode=mode, input_file=args.input_path,
        overlay_title=overlay_title, overlay_category=category or "",
        overlay_category_logo=category_logo_path or "", overlay_note=note or "",
        ai_reasoning=reasoning,
        poster_template=getattr(args, "style", "") or "",
    )
    embed_metadata(poster_path, metadata)

    fanart_path = _generate_fanart_if_requested(
        args, highres_path, getattr(args, "video_properties", None)
    )
    _emit_result(
        poster_path, frame_index, mode, reasoning, args.input_path, args.json,
        fmt=args.format, crop_position=crop_position, overlay_title=overlay_title,
        source="frame", overlay_category=category or "", overlay_note=note or "",
        badges=detected_badges or None, fanart_path=fanart_path,
    )
    return EXIT_SUCCESS
