"""
High-level embed API for clawID.
"""

import time
import uuid
from PIL import Image

from .payload import encode, to_bits
from ..algorithms.dwt_qim import embed_bits as _qim_embed, DELTA as QIM_DELTA, REPEAT as QIM_REPEAT
from ..algorithms.fourier_mellin import embed_bits as _fm_embed, DELTA as FM_DELTA, REPEAT as FM_REPEAT
from ..algorithms.visible import embed_visible
from ..algorithms.qr_mark import embed_qr as _qr_embed, DEFAULT_OPACITY as QR_DEFAULT_OPACITY

# Default constants
DELTA = QIM_DELTA
REPEAT = QIM_REPEAT

_INVISIBLE_ALGORITHMS = ('qim', 'fm')
_ALL_ALGORITHMS = ('qim', 'fm', 'qr', 'all')


def embed(
    source,
    output_path: str,
    metadata: dict,
    mode: str = 'invisible',
    algorithm: str = 'qim',
    delta: float = None,
    repeat: int = None,
    watermark_text: str = None,
    position: str = 'bottom-right',
    opacity: float = 0.6,
    font_size: int = 20,
    qr_opacity: float = QR_DEFAULT_OPACITY,
) -> dict:
    """
    Embed a clawID watermark into an image.

    Args:
        source:         file path (str) or PIL Image
        output_path:    path to save the watermarked image
        metadata:       dict with creator info, e.g.:
                          {'uid': 'user123', 'platform': 'hawky.ai', 'asset_id': '...'}
        mode:           'invisible' — steganographic DWT-QIM (undetectable by eye)
                        'visible'   — text overlay
                        'both'      — invisible + visible text
        algorithm:      'qim'  — DWT-QIM (fast, PNG/JPEG, no resize robustness)
                        'fm'   — Fourier-Mellin (resize-robust ±35%, slower)
                        'qr'   — AI-readable invisible QR code (readable by GPT-4V,
                                 Gemini, Grok, and any QR scanner app)
                        'all'  — DWT-QIM + QR together (maximum coverage)
        delta:          DWT watermark strength (auto-selected per algorithm if None)
        repeat:         DWT error-correction repetition factor (auto-selected if None)
        watermark_text: override text for visible mode (auto-generated if None)
        position:       visible watermark position (default 'bottom-right')
        opacity:        visible text watermark opacity 0–1 (default 0.6)
        font_size:      visible watermark font size in px (default 20)
        qr_opacity:     QR code blend opacity 0–1 (default 0.15)
                        0.10 = very subtle  |  0.15 = default  |  0.25 = scan-safe

    Returns:
        The finalised metadata dict (including auto-added 'clawid' and 'ts' fields)
    """
    if mode not in ('invisible', 'visible', 'both'):
        raise ValueError(f"mode must be 'invisible', 'visible', or 'both', got '{mode}'")
    if algorithm not in _ALL_ALGORITHMS:
        raise ValueError(
            f"algorithm must be one of {_ALL_ALGORITHMS}, got '{algorithm}'"
        )

    image = Image.open(source).convert('RGB') if isinstance(source, str) else source.convert('RGB')

    # Enrich metadata with auto-fields (never overwrite caller-supplied values)
    metadata = dict(metadata)
    if 'ts' not in metadata:
        metadata['ts'] = int(time.time())
    if 'clawid' not in metadata:
        metadata['clawid'] = str(uuid.uuid4())

    # ── QR watermark (applied first so DWT-QIM is the final step) ───────────
    # Order matters: QR first → DWT last. This prevents the QR overlay
    # pattern from corrupting DWT-QIM coefficients in 'all' mode.
    if algorithm in ('qr', 'all'):
        image = _qr_embed(image, metadata, opacity=qr_opacity)

    # ── Invisible DWT embedding ──────────────────────────────────────────────
    if mode in ('invisible', 'both') and algorithm in ('qim', 'fm', 'all'):
        payload_bytes = encode(metadata)
        bits = to_bits(payload_bytes)
        if algorithm == 'fm':
            _delta = delta if delta is not None else FM_DELTA
            _repeat = repeat if repeat is not None else FM_REPEAT
            image = _fm_embed(image, bits, delta=_delta, repeat=_repeat)
        else:
            # 'qim' or 'all' — use QIM as base
            _delta = delta if delta is not None else QIM_DELTA
            _repeat = repeat if repeat is not None else QIM_REPEAT
            image = _qim_embed(image, bits, delta=_delta, repeat=_repeat)

    # ── Visible text overlay ─────────────────────────────────────────────────
    if mode in ('visible', 'both'):
        if watermark_text is None:
            parts = []
            if metadata.get('uid'):
                parts.append(metadata['uid'])
            if metadata.get('platform'):
                parts.append(metadata['platform'])
            parts.append(f"clawid:{metadata['clawid'][:8]}")
            watermark_text = ' | '.join(parts)
        image = embed_visible(
            image, watermark_text,
            position=position,
            opacity=opacity,
            font_size=font_size,
        )

    _save(image, output_path)
    return metadata


def _save(image: Image.Image, path: str) -> None:
    ext = path.rsplit('.', 1)[-1].lower() if '.' in path else 'png'
    if ext in ('jpg', 'jpeg'):
        image.save(path, 'JPEG', quality=95, subsampling=0)
    else:
        image.save(path)
