# 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

"""
Artwork provenance — certificate generation, chain anchoring, and verification.

Integrates with the genesis block chain to provide immutable proof of authorship
for digital artwork. Each registration creates a ``watermark`` block containing
SHA-256 hashes of both the original and watermarked images.
"""

import json
import logging
import os
import uuid
from datetime import datetime, timezone
from pathlib import Path

from familiar.skills.gallery.watermark import (
    apply_invisible_watermark,
    apply_visible_watermark,
    compute_image_hash,
    generate_thumbnail,
)

logger = logging.getLogger(__name__)


def _get_gallery_dir() -> Path:
    """Get gallery data directory, creating subdirs as needed."""
    from familiar.core.paths import DATA_DIR

    gallery = DATA_DIR / "gallery"
    for sub in ("originals", "watermarked", "thumbnails", "certificates"):
        (gallery / sub).mkdir(parents=True, exist_ok=True)
    return gallery


def _load_gallery_data() -> list:
    """Load gallery.json artwork registry."""
    gallery_dir = _get_gallery_dir()
    data_file = gallery_dir / "gallery.json"
    if data_file.exists():
        try:
            return json.loads(data_file.read_text())
        except (json.JSONDecodeError, OSError):
            logger.warning("Failed to load gallery.json, starting fresh")
    return []


def _save_gallery_data(artworks: list):
    """Save gallery.json artwork registry."""
    gallery_dir = _get_gallery_dir()
    data_file = gallery_dir / "gallery.json"
    data_file.write_text(json.dumps(artworks, indent=2))


def register_artwork(
    image_path: str,
    title: str,
    artist: str,
    description: str = "",
    medium: str = "",
    dimensions: str = "",
    license_type: str = "All Rights Reserved",
    tags: list = None,
    watermark_types: list = None,
) -> dict:
    """
    Full artwork registration pipeline.

    1. Hash the original image
    2. Copy original to gallery/originals/
    3. Apply requested watermarks
    4. Hash the watermarked image
    5. Anchor to chain (watermark block)
    6. Generate provenance certificate
    7. Save artwork record to gallery.json

    Returns:
        Artwork record dict with all metadata.
    """
    if tags is None:
        tags = []
    if watermark_types is None:
        watermark_types = ["visible", "invisible", "certificate"]

    gallery_dir = _get_gallery_dir()
    artwork_id = str(uuid.uuid4())[:12]
    now = datetime.now(timezone.utc).isoformat()

    # Hash original
    original_hash = compute_image_hash(image_path)

    # Copy original to gallery
    src = Path(image_path)
    ext = src.suffix or ".png"
    original_dest = gallery_dir / "originals" / f"{artwork_id}{ext}"
    original_dest.write_bytes(src.read_bytes())

    # Apply watermarks to a working copy
    watermarked_path = str(gallery_dir / "watermarked" / f"{artwork_id}{ext}")
    # Start from original
    import shutil
    shutil.copy2(str(original_dest), watermarked_path)

    applied_types = []

    if "visible" in watermark_types:
        watermark_text = f"\u00a9 {artist}"
        watermarked_path = apply_visible_watermark(
            watermarked_path, watermark_text, output_path=watermarked_path
        )
        applied_types.append("visible")

    if "invisible" in watermark_types:
        embed_data = json.dumps({
            "artwork_id": artwork_id,
            "artist": artist,
            "title": title,
            "registered": now,
            "hash": original_hash,
        })
        # Invisible watermark forces PNG
        png_path = str(gallery_dir / "watermarked" / f"{artwork_id}.png")
        watermarked_path = apply_invisible_watermark(
            watermarked_path, embed_data, output_path=png_path
        )
        applied_types.append("invisible")

    # Hash watermarked image
    watermarked_hash = compute_image_hash(watermarked_path)

    # Generate thumbnail
    thumb_path = str(gallery_dir / "thumbnails" / f"{artwork_id}.png")
    generate_thumbnail(str(original_dest), output_path=thumb_path)

    # File metadata
    file_size = os.path.getsize(image_path)
    file_format = ext.lstrip(".").upper()

    # Anchor to chain
    block_hash = ""
    block_index = -1
    genesis_hash = ""
    try:
        from familiar.skills.training.bridge import anchor_watermark, get_chain_status

        chain_status = get_chain_status()
        if chain_status.get("initialized"):
            genesis_hash = chain_status.get("genesis_hash", "")

        block_hash = anchor_watermark({
            "artwork_id": artwork_id,
            "title": title,
            "artist": artist,
            "original_hash": original_hash,
            "watermarked_hash": watermarked_hash,
            "watermark_types": applied_types,
            "license": license_type,
            "certificate_hash": "",  # updated after certificate generation
            "metadata": {
                "medium": medium,
                "dimensions": dimensions,
                "file_size": file_size,
                "format": file_format,
            },
        })

        if block_hash:
            chain_status = get_chain_status()
            latest = chain_status.get("latest_block", {})
            block_index = latest.get("index", -1) if latest else -1
    except Exception as e:
        logger.debug("Chain anchoring skipped: %s", e)

    if "certificate" in watermark_types:
        applied_types.append("certificate")

    # Build artwork record
    artwork = {
        "artwork_id": artwork_id,
        "title": title,
        "artist": artist,
        "description": description,
        "medium": medium,
        "dimensions": dimensions,
        "license": license_type,
        "tags": tags,
        "original_path": str(original_dest),
        "original_hash": original_hash,
        "watermarked_path": watermarked_path,
        "watermarked_hash": watermarked_hash,
        "thumbnail_path": thumb_path,
        "watermark_types": applied_types,
        "block_hash": block_hash,
        "block_index": block_index,
        "certificate_path": "",
        "registered_at": now,
        "genesis_hash": genesis_hash,
    }

    # Generate certificate
    if "certificate" in watermark_types:
        cert_md = generate_certificate(artwork)
        cert_path = gallery_dir / "certificates" / f"{artwork_id}.md"
        cert_path.write_text(cert_md)
        artwork["certificate_path"] = str(cert_path)

        # Update chain block with certificate hash if anchored
        if block_hash:
            cert_hash = compute_image_hash(str(cert_path))
            artwork["certificate_hash"] = cert_hash

    # Save to gallery registry
    artworks = _load_gallery_data()
    artworks.append(artwork)
    _save_gallery_data(artworks)

    logger.info("Registered artwork '%s' by %s (id=%s)", title, artist, artwork_id)
    return artwork


def generate_certificate(artwork: dict) -> str:
    """
    Generate a markdown provenance certificate for an artwork.

    Args:
        artwork: Artwork record dict from register_artwork().

    Returns:
        Markdown string with full provenance details.
    """
    lines = [
        "# Provenance Certificate",
        "",
        f"**Title:** {artwork.get('title', 'Untitled')}",
        f"**Artist:** {artwork.get('artist', 'Unknown')}",
        f"**Date Registered:** {artwork.get('registered_at', 'N/A')}",
        f"**Artwork ID:** {artwork.get('artwork_id', 'N/A')}",
        "",
        "## Integrity Hashes",
        "",
        f"- **Original SHA-256:** `{artwork.get('original_hash', 'N/A')}`",
        f"- **Watermarked SHA-256:** `{artwork.get('watermarked_hash', 'N/A')}`",
        "",
        "## Chain Notarization",
        "",
    ]

    if artwork.get("block_hash"):
        lines.extend([
            f"- **Block Hash:** `{artwork['block_hash']}`",
            f"- **Block Index:** {artwork.get('block_index', 'N/A')}",
            f"- **Genesis Hash:** `{artwork.get('genesis_hash', 'N/A')}`",
        ])
    else:
        lines.append("- *Chain not initialized — notarization pending*")

    lines.extend([
        "",
        "## Watermark Types",
        "",
    ])
    for wt in artwork.get("watermark_types", []):
        lines.append(f"- {wt}")

    lines.extend([
        "",
        "## Details",
        "",
        f"- **Medium:** {artwork.get('medium', 'N/A')}",
        f"- **Dimensions:** {artwork.get('dimensions', 'N/A')}",
        f"- **License:** {artwork.get('license', 'All Rights Reserved')}",
    ])

    if artwork.get("tags"):
        lines.append(f"- **Tags:** {', '.join(artwork['tags'])}")

    if artwork.get("description"):
        lines.extend(["", "## Description", "", artwork["description"]])

    lines.extend([
        "",
        "---",
        "*Generated by Familiar Gallery Vault*",
    ])

    return "\n".join(lines)


def verify_artwork(artwork_id: str) -> dict:
    """
    Verify provenance chain integrity for a registered artwork.

    Re-hashes the watermarked image file, compares to stored hash, looks up
    the chain block, and verifies chain integrity.

    Returns:
        Dict with verified, block, chain_valid, hash_match, details.
    """
    artworks = _load_gallery_data()
    artwork = None
    for a in artworks:
        if a["artwork_id"] == artwork_id:
            artwork = a
            break

    if artwork is None:
        return {
            "verified": False,
            "block": None,
            "chain_valid": False,
            "hash_match": False,
            "details": f"Artwork {artwork_id} not found in gallery",
        }

    # Re-hash the watermarked file
    hash_match = False
    details = []
    if Path(artwork["watermarked_path"]).exists():
        current_hash = compute_image_hash(artwork["watermarked_path"])
        hash_match = current_hash == artwork["watermarked_hash"]
        if hash_match:
            details.append("Watermarked image hash verified")
        else:
            details.append("WARNING: Watermarked image hash mismatch — file may be altered")
    else:
        details.append("WARNING: Watermarked image file not found")

    # Check chain
    chain_valid = False
    block_info = None
    try:
        from familiar.skills.training.bridge import get_chain_status

        status = get_chain_status()
        if status.get("initialized"):
            integrity = status.get("integrity", {})
            chain_valid = integrity.get("valid", False)
            if chain_valid:
                details.append("Chain integrity verified")
            else:
                details.append(
                    f"Chain integrity error: {integrity.get('error', 'unknown')}"
                )

            # Look up the block
            blocks = get_chain_blocks_for_artwork(artwork_id)
            if blocks:
                block_info = blocks[-1]  # most recent
                details.append(f"Found {len(blocks)} chain block(s)")
            else:
                details.append("No chain blocks found for this artwork")
        else:
            details.append("Chain not initialized")
    except Exception as e:
        details.append(f"Chain verification error: {e}")

    verified = hash_match and chain_valid and block_info is not None

    return {
        "verified": verified,
        "block": block_info,
        "chain_valid": chain_valid,
        "hash_match": hash_match,
        "details": "; ".join(details),
    }


def get_chain_blocks_for_artwork(artwork_id: str) -> list:
    """
    Filter chain for blocks matching a specific artwork.

    Returns list of block dicts with block_type='watermark' and matching artwork_id.
    """
    try:
        from familiar.skills.training.bridge import _get_store

        store = _get_store()
        genesis = store.get_genesis()
        if genesis is None:
            return []

        blocks = []
        length = store.chain_length()
        for i in range(length):
            block = store.get_block(i)
            if block and block.block_type == "watermark":
                payload = block.payload if isinstance(block.payload, dict) else {}
                if payload.get("artwork_id") == artwork_id:
                    blocks.append({
                        "index": block.index,
                        "timestamp": block.timestamp,
                        "block_hash": block.block_hash,
                        "prev_hash": block.prev_hash,
                        "block_type": block.block_type,
                        "payload": payload,
                    })
        return blocks
    except Exception as e:
        logger.debug("Error fetching chain blocks: %s", e)
        return []
