# Familiar - Self-Hosted AI Companion Platform
# Copyright (c) 2026 George Scott Foley
# Licensed under the MIT License

"""Gallery routes — extracted from memory.py."""

from __future__ import annotations

import json
import logging
import os
import threading
from datetime import datetime
from pathlib import Path

from flask import Blueprint, Response, jsonify, request, send_file

from ..auth import require_auth
from ..helpers import get_agent, get_service_manager, get_marketplace_catalog, DATA_DIR, safe_error

logger = logging.getLogger(__name__)

bp = Blueprint("gallery", __name__)


@bp.route("/api/gallery")
@require_auth
def api_gallery_list():
    """List all artworks in the gallery vault."""
    try:
        from familiar.skills.gallery.provenance import _load_gallery_data

        artworks = _load_gallery_data()
        items = []
        for a in artworks:
            items.append(
                {
                    "artwork_id": a["artwork_id"],
                    "title": a["title"],
                    "artist": a["artist"],
                    "description": a.get("description", ""),
                    "medium": a.get("medium", ""),
                    "dimensions": a.get("dimensions", ""),
                    "license": a.get("license", "All Rights Reserved"),
                    "tags": a.get("tags", []),
                    "watermark_types": a.get("watermark_types", []),
                    "block_hash": a.get("block_hash", ""),
                    "block_index": a.get("block_index", -1),
                    "registered_at": a.get("registered_at", ""),
                    "has_thumbnail": bool(a.get("thumbnail_path")),
                }
            )
        return jsonify({"artworks": items, "count": len(items)})
    except Exception as e:
        logger.debug("Gallery list error: %s", e)
        return jsonify({"artworks": [], "count": 0, "error": safe_error(e)}), 502


@bp.route("/api/gallery/<artwork_id>")
@require_auth
def api_gallery_detail(artwork_id):
    """Get full artwork details including chain block info."""
    try:
        from familiar.skills.gallery.provenance import (
            _load_gallery_data,
            get_chain_blocks_for_artwork,
        )

        artworks = _load_gallery_data()
        artwork = None
        for a in artworks:
            if a["artwork_id"] == artwork_id:
                artwork = a
                break

        if artwork is None:
            return jsonify({"error": "Artwork not found"}), 404

        blocks = get_chain_blocks_for_artwork(artwork_id)
        artwork["chain_blocks"] = blocks
        return jsonify(artwork)
    except Exception as e:
        logger.debug("Gallery detail error: %s", e)
        return jsonify({"error": safe_error(e)}), 502


@bp.route("/api/gallery/upload", methods=["POST"])
@require_auth
def api_gallery_upload():
    """Upload an image to the gallery originals directory."""
    try:
        import uuid

        from familiar.skills.gallery.provenance import _get_gallery_dir
        from familiar.skills.gallery.watermark import generate_thumbnail

        if "file" not in request.files:
            return jsonify({"error": "No file provided"}), 400

        file = request.files["file"]
        if not file.filename:
            return jsonify({"error": "No filename"}), 400

        gallery_dir = _get_gallery_dir()
        temp_id = str(uuid.uuid4())[:12]
        ext = Path(file.filename).suffix or ".png"
        dest = gallery_dir / "originals" / f"{temp_id}{ext}"
        file.save(str(dest))

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

        return jsonify(
            {
                "success": True,
                "temp_id": temp_id,
                "filename": file.filename,
                "path": str(dest),
                "thumbnail_path": thumb_path,
            }
        )
    except Exception as e:
        logger.warning("Gallery upload error: %s", e)
        return jsonify({"error": safe_error(e), "success": False}), 500


@bp.route("/api/gallery/watermark", methods=["POST"])
@require_auth
def api_gallery_watermark():
    """Apply watermark(s) to an uploaded artwork."""
    try:
        from familiar.skills.gallery.watermark import (
            apply_invisible_watermark,
            apply_visible_watermark,
            compute_image_hash,
        )

        data = request.get_json(force=True)
        image_path = data.get("image_path", "")
        if not image_path or not Path(image_path).exists():
            return jsonify({"error": "Image file not found"}), 400

        wm_type = data.get("type", "visible")
        text = data.get("text", "")
        output_path = data.get("output_path", "")

        if wm_type == "invisible":
            embed_data = data.get("data", text or "watermark")
            result_path = apply_invisible_watermark(image_path, embed_data, output_path=output_path)
        else:
            if not text:
                return jsonify({"error": "text is required for visible watermarks"}), 400
            result_path = apply_visible_watermark(
                image_path,
                text,
                position=data.get("position", "bottom-right"),
                opacity=data.get("opacity", 0.3),
                output_path=output_path,
            )

        return jsonify(
            {
                "success": True,
                "output_path": result_path,
                "type": wm_type,
                "hash": compute_image_hash(result_path),
            }
        )
    except Exception as e:
        logger.debug("Gallery watermark error: %s", e)
        return jsonify({"error": safe_error(e), "success": False}), 500


@bp.route("/api/gallery/register", methods=["POST"])
@require_auth
def api_gallery_register():
    """Register + chain-notarize an artwork."""
    try:
        from familiar.skills.gallery.provenance import register_artwork

        data = request.get_json(force=True)
        image_path = data.get("image_path", "")
        if not image_path or not Path(image_path).exists():
            return jsonify({"error": "Image file not found"}), 400

        artwork = register_artwork(
            image_path=image_path,
            title=data.get("title", "Untitled"),
            artist=data.get("artist", "Unknown"),
            description=data.get("description", ""),
            medium=data.get("medium", ""),
            dimensions=data.get("dimensions", ""),
            license_type=data.get("license", "All Rights Reserved"),
            tags=data.get("tags", []),
            watermark_types=data.get("watermark_types", ["visible", "invisible", "certificate"]),
        )

        return jsonify(
            {
                "success": True,
                "artwork_id": artwork["artwork_id"],
                "title": artwork["title"],
                "artist": artwork["artist"],
                "block_hash": artwork.get("block_hash", ""),
                "watermark_types": artwork["watermark_types"],
                "certificate_path": artwork.get("certificate_path", ""),
            }
        )
    except Exception as e:
        logger.warning("Gallery register error: %s", e)
        return jsonify({"error": safe_error(e), "success": False}), 500


@bp.route("/api/gallery/verify/<artwork_id>")
@require_auth
def api_gallery_verify(artwork_id):
    """Verify chain integrity for an artwork."""
    try:
        from familiar.skills.gallery.provenance import verify_artwork

        result = verify_artwork(artwork_id)
        return jsonify(result)
    except Exception as e:
        logger.debug("Gallery verify error: %s", e)
        return jsonify({"error": safe_error(e), "verified": False}), 502


@bp.route("/api/gallery/certificate/<artwork_id>")
@require_auth
def api_gallery_certificate(artwork_id):
    """Download provenance certificate markdown."""
    try:
        from familiar.skills.gallery.provenance import _load_gallery_data

        artworks = _load_gallery_data()
        artwork = None
        for a in artworks:
            if a["artwork_id"] == artwork_id:
                artwork = a
                break

        if artwork is None:
            return jsonify({"error": "Artwork not found"}), 404

        cert_path = artwork.get("certificate_path", "")
        if not cert_path or not Path(cert_path).exists():
            return jsonify({"error": "Certificate not found"}), 404

        return send_file(
            cert_path,
            as_attachment=True,
            download_name=f"certificate_{artwork_id}.md",
            mimetype="text/markdown",
        )
    except Exception as e:
        logger.debug("Gallery certificate error: %s", e)
        return jsonify({"error": safe_error(e)}), 502


@bp.route("/api/gallery/image/<artwork_id>")
@require_auth
def api_gallery_image(artwork_id):
    """Serve artwork image file. Use ?type=original or ?type=watermarked."""
    try:
        from familiar.skills.gallery.provenance import _load_gallery_data

        artworks = _load_gallery_data()
        artwork = None
        for a in artworks:
            if a["artwork_id"] == artwork_id:
                artwork = a
                break

        if artwork is None:
            return jsonify({"error": "Artwork not found"}), 404

        img_type = request.args.get("type", "watermarked")
        if img_type == "original":
            img_path = artwork.get("original_path", "")
        else:
            img_path = artwork.get("watermarked_path", "")

        if not img_path or not Path(img_path).exists():
            return jsonify({"error": "Image file not found"}), 404

        ext = Path(img_path).suffix.lower()
        mime_map = {
            ".png": "image/png",
            ".jpg": "image/jpeg",
            ".jpeg": "image/jpeg",
            ".gif": "image/gif",
            ".webp": "image/webp",
            ".bmp": "image/bmp",
        }
        mimetype = mime_map.get(ext, "image/png")
        return send_file(img_path, mimetype=mimetype)
    except Exception as e:
        logger.debug("Gallery image error: %s", e)
        return jsonify({"error": safe_error(e)}), 502


@bp.route("/api/gallery/thumbnail/<artwork_id>")
@require_auth
def api_gallery_thumbnail(artwork_id):
    """Serve artwork thumbnail."""
    try:
        from familiar.skills.gallery.provenance import _load_gallery_data

        artworks = _load_gallery_data()
        artwork = None
        for a in artworks:
            if a["artwork_id"] == artwork_id:
                artwork = a
                break

        if artwork is None:
            return jsonify({"error": "Artwork not found"}), 404

        thumb_path = artwork.get("thumbnail_path", "")
        if not thumb_path or not Path(thumb_path).exists():
            return jsonify({"error": "Thumbnail not found"}), 404

        return send_file(thumb_path, mimetype="image/png")
    except Exception as e:
        logger.debug("Gallery thumbnail error: %s", e)
        return jsonify({"error": safe_error(e)}), 502



@bp.route("/api/gallery/generated/<filename>")
@require_auth
def api_gallery_generated(filename: str):
    """Serve a generated image by filename."""
    # Sanitise — only allow simple filenames, no path traversal
    safe = Path(filename).name
    img_path = DATA_DIR / "gallery" / "generated" / safe
    if not img_path.exists():
        return jsonify({"error": "Image not found"}), 404

    ext = img_path.suffix.lower()
    mime_map = {
        ".png": "image/png", ".jpg": "image/jpeg", ".jpeg": "image/jpeg",
        ".gif": "image/gif", ".webp": "image/webp", ".bmp": "image/bmp",
    }
    return send_file(img_path, mimetype=mime_map.get(ext, "image/png"))


# ── Batch Gallery Operations ─────────────────────────────────────────


@bp.route("/api/gallery/batch/delete", methods=["POST"])
@require_auth
def api_gallery_batch_delete():
    """Delete multiple artworks by ID."""
    data = request.get_json(silent=True) or {}
    ids = data.get("artwork_ids", [])
    if not ids:
        return jsonify({"error": "No artwork_ids provided"}), 400

    gallery_dir = DATA_DIR / "gallery"
    registry_path = gallery_dir / "gallery.json"
    try:
        registry = json.loads(registry_path.read_text()) if registry_path.exists() else {"artworks": []}
    except Exception:
        registry = {"artworks": []}

    deleted = []
    for aid in ids:
        # Remove from registry
        before = len(registry["artworks"])
        registry["artworks"] = [a for a in registry["artworks"] if a.get("artwork_id") != aid]
        if len(registry["artworks"]) < before:
            deleted.append(aid)
        # Remove files
        for subdir in ["originals", "watermarked", "thumbnails", "certificates"]:
            for f in (gallery_dir / subdir).glob(f"{aid}*"):
                try:
                    f.unlink()
                except Exception:
                    pass

    registry_path.write_text(json.dumps(registry, indent=2, default=str))
    return jsonify({"deleted": deleted, "count": len(deleted)})


@bp.route("/api/gallery/batch/watermark", methods=["POST"])
@require_auth
def api_gallery_batch_watermark():
    """Apply watermark to multiple artworks."""
    data = request.get_json(silent=True) or {}
    ids = data.get("artwork_ids", [])
    text = data.get("watermark_text", "")
    position = data.get("position", "bottom-right")
    opacity = data.get("opacity", 0.3)

    if not ids or not text:
        return jsonify({"error": "artwork_ids and watermark_text required"}), 400

    gallery_dir = DATA_DIR / "gallery"
    results = {"success": [], "failed": []}

    try:
        from familiar.skills.gallery.watermark import apply_visible_watermark
    except ImportError:
        return jsonify({"error": "Watermark module not available"}), 500

    for aid in ids:
        # Find original
        originals = list((gallery_dir / "originals").glob(f"{aid}*"))
        if not originals:
            results["failed"].append({"id": aid, "error": "Original not found"})
            continue

        wm_dir = gallery_dir / "watermarked"
        wm_dir.mkdir(parents=True, exist_ok=True)
        out_path = str(wm_dir / f"{aid}_wm{originals[0].suffix}")

        try:
            apply_visible_watermark(str(originals[0]), text, position=position, opacity=opacity, output_path=out_path)
            results["success"].append(aid)
        except Exception as e:
            results["failed"].append({"id": aid, "error": safe_error(e)})

    return jsonify(results)


@bp.route("/api/gallery/batch/export", methods=["POST"])
@require_auth
def api_gallery_batch_export():
    """Export multiple artworks as a ZIP file."""
    import io
    import zipfile

    data = request.get_json(silent=True) or {}
    ids = data.get("artwork_ids", [])
    include = data.get("include", ["originals", "certificates"])

    if not ids:
        return jsonify({"error": "No artwork_ids provided"}), 400

    gallery_dir = DATA_DIR / "gallery"
    buf = io.BytesIO()

    with zipfile.ZipFile(buf, "w", zipfile.ZIP_DEFLATED) as zf:
        for aid in ids:
            for subdir in include:
                folder = gallery_dir / subdir
                if not folder.exists():
                    continue
                for f in folder.glob(f"{aid}*"):
                    zf.write(f, f"{subdir}/{f.name}")

    buf.seek(0)
    return Response(
        buf.getvalue(),
        mimetype="application/zip",
        headers={"Content-Disposition": f"attachment; filename=gallery_export_{len(ids)}_artworks.zip"},
    )


@bp.route("/api/gallery/batch/register", methods=["POST"])
@require_auth
def api_gallery_batch_register():
    """Register multiple uploaded artworks with shared metadata."""
    data = request.get_json(silent=True) or {}
    files = data.get("file_paths", [])
    artist = data.get("artist", "Unknown")
    license_type = data.get("license", "All Rights Reserved")
    tags = data.get("tags", [])
    watermark_types = data.get("watermark_types", ["visible"])

    if not files:
        return jsonify({"error": "No file_paths provided"}), 400

    results = {"registered": [], "failed": []}

    try:
        from familiar.skills.gallery.provenance import register_artwork
    except ImportError:
        return jsonify({"error": "Provenance module not available"}), 500

    for fp in files:
        path = Path(fp).expanduser()
        if not path.exists():
            results["failed"].append({"file": fp, "error": "Not found"})
            continue
        try:
            result = register_artwork(
                image_path=str(path),
                title=path.stem.replace("_", " ").replace("-", " ").title(),
                artist=artist,
                license=license_type,
                tags=tags,
                watermark_types=watermark_types,
            )
            results["registered"].append({"file": fp, "artwork_id": result.get("artwork_id", "")})
        except Exception as e:
            results["failed"].append({"file": fp, "error": safe_error(e)})

    return jsonify(results)


@bp.route("/api/gallery/certificate/<artwork_id>/pdf")
@require_auth
def api_gallery_certificate_pdf(artwork_id):
    """Download provenance certificate as PDF."""
    gallery_dir = DATA_DIR / "gallery"
    cert_path = gallery_dir / "certificates" / f"{artwork_id}.md"

    if not cert_path.exists():
        return jsonify({"error": "Certificate not found"}), 404

    md_content = cert_path.read_text()

    # Try WeasyPrint (already in docs extra)
    try:
        import markdown
        from weasyprint import HTML

        # Convert markdown to HTML
        html_body = markdown.markdown(md_content, extensions=["tables", "fenced_code"])

        # Add thumbnail if available
        thumb_path = gallery_dir / "thumbnails" / f"{artwork_id}_thumb.png"
        thumb_html = ""
        if thumb_path.exists():
            import base64
            thumb_b64 = base64.b64encode(thumb_path.read_bytes()).decode()
            thumb_html = f'<img src="data:image/png;base64,{thumb_b64}" style="max-width:200px;margin:16px auto;display:block;" />'

        html = f"""<!DOCTYPE html>
<html><head>
<meta charset="utf-8">
<style>
    body {{ font-family: 'Helvetica Neue', Arial, sans-serif; max-width: 700px; margin: 40px auto; padding: 20px; color: #1a1a2e; }}
    h1 {{ color: #e94560; border-bottom: 2px solid #e94560; padding-bottom: 8px; }}
    h2 {{ color: #0f3460; margin-top: 24px; }}
    table {{ width: 100%; border-collapse: collapse; margin: 12px 0; }}
    th, td {{ border: 1px solid #ddd; padding: 8px; text-align: left; }}
    th {{ background: #f4f4f8; }}
    code {{ background: #f0f0f5; padding: 2px 6px; border-radius: 3px; font-size: 0.85em; }}
    .footer {{ margin-top: 40px; padding-top: 16px; border-top: 1px solid #ddd; font-size: 0.8em; color: #666; text-align: center; }}
</style>
</head><body>
{thumb_html}
{html_body}
<div class="footer">
    Generated by Familiar — Self-Hosted AI Companion Platform<br>
    Provenance secured by Dross Chain
</div>
</body></html>"""

        pdf_bytes = HTML(string=html).write_pdf()
        return Response(
            pdf_bytes,
            mimetype="application/pdf",
            headers={"Content-Disposition": f"attachment; filename=certificate_{artwork_id}.pdf"},
        )

    except ImportError:
        # Fallback: serve markdown as download
        return Response(
            md_content,
            mimetype="text/markdown",
            headers={"Content-Disposition": f"attachment; filename=certificate_{artwork_id}.md"},
        )
