# 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

"""
Browser API Routes for Dashboard.

Provides REST endpoints for the embedded browser:
- /api/browser/browse - Fetch and filter a URL
- /api/browser/ask - Ask AI about page content
- /api/browser/save - Save page to archive
- /api/browser/archive - List/retrieve archived pages
- /api/browser/extract - Extract structured data
- /api/browser/search - Private web search
"""

import logging

logger = logging.getLogger(__name__)


def register_browser_routes(app, browser_skill):
    """
    Register browser API routes with Flask app.

    Args:
        app: Flask application
        browser_skill: PrivateBrowserSkill instance
    """
    from functools import wraps

    from flask import jsonify, request
    from flask import session as flask_session

    def require_auth(f):
        """Require a valid session or API token for browser API access."""

        @wraps(f)
        async def decorated(*args, **kwargs):
            # Check session-based auth (PWA / admin panel)
            if flask_session.get("user_id"):
                return await f(*args, **kwargs)

            # Check Bearer token auth (API clients)
            auth_header = request.headers.get("Authorization", "")
            if auth_header.startswith("Bearer "):
                token = auth_header[7:]
                try:
                    from familiar.core.users import get_user_manager

                    um = get_user_manager()
                    if um and um.authenticate_session(token):
                        return await f(*args, **kwargs)
                except Exception:
                    pass

            return jsonify({"error": "Authentication required"}), 401

        return decorated

    @app.route("/api/browser/browse", methods=["POST"])
    @require_auth
    async def browser_browse():
        """Browse to a URL through the privacy proxy."""
        try:
            data = request.get_json()
            url = data.get("url")

            if not url:
                return jsonify({"error": "URL required"}), 400

            result = await browser_skill.browse(
                url=url,
                reader_mode=data.get("reader_mode"),
                summarize=data.get("summarize", False),
                archive=data.get("archive", False),
            )

            return jsonify(
                {
                    "url": result.url,
                    "final_url": result.final_url,
                    "title": result.title,
                    "content_html": result.content_html,
                    "content_text": result.content_text[:5000],  # Truncate for response
                    "reader_html": result.reader_html,
                    "summary": result.summary,
                    "links": result.links[:50],
                    "images": result.images[:20],
                    "meta": result.meta,
                    "blocked": result.blocked,
                    "load_time_ms": result.load_time_ms,
                    "archived": result.archived,
                    "archive_id": result.archive_id,
                }
            )

        except Exception as e:
            logger.error(f"Browse error: {e}")
            return jsonify({"error": str(e)}), 500

    @app.route("/api/browser/search", methods=["POST"])
    @require_auth
    async def browser_search():
        """Private web search."""
        try:
            data = request.get_json()
            query = data.get("query")
            engine = data.get("engine", "duckduckgo")

            if not query:
                return jsonify({"error": "Query required"}), 400

            results = await browser_skill.search(query, engine)

            return jsonify(
                {
                    "query": query,
                    "engine": engine,
                    "results": results,
                }
            )

        except Exception as e:
            logger.error(f"Search error: {e}")
            return jsonify({"error": str(e)}), 500

    @app.route("/api/browser/ask", methods=["POST"])
    @require_auth
    async def browser_ask():
        """Ask AI about page content."""
        try:
            data = request.get_json()
            question = data.get("question")
            url = data.get("url")

            if not question:
                return jsonify({"error": "Question required"}), 400

            answer = await browser_skill.ask(question, url)

            return jsonify(
                {
                    "question": question,
                    "answer": answer,
                }
            )

        except Exception as e:
            logger.error(f"Ask error: {e}")
            return jsonify({"error": str(e)}), 500

    @app.route("/api/browser/extract", methods=["POST"])
    @require_auth
    async def browser_extract():
        """Extract structured data from a page."""
        try:
            data = request.get_json()
            url = data.get("url")
            data_type = data.get("data_type", "auto")

            if not url:
                return jsonify({"error": "URL required"}), 400

            extracted = await browser_skill.extract_data(url, data_type)

            return jsonify(
                {
                    "url": url,
                    "data_type": data_type,
                    "data": extracted,
                }
            )

        except Exception as e:
            logger.error(f"Extract error: {e}")
            return jsonify({"error": str(e)}), 500

    @app.route("/api/browser/save", methods=["POST"])
    @require_auth
    async def browser_save():
        """Save current page to archive."""
        try:
            data = request.get_json()
            url = data.get("url")

            archive_id = await browser_skill.save_page(url)

            return jsonify(
                {
                    "success": True,
                    "archive_id": archive_id,
                }
            )

        except Exception as e:
            logger.error(f"Save error: {e}")
            return jsonify({"error": str(e)}), 500

    @app.route("/api/browser/archive", methods=["GET"])
    @require_auth
    async def browser_archive_list():
        """List archived pages."""
        try:
            limit = request.args.get("limit", 50, type=int)
            search = request.args.get("search")

            pages = await browser_skill.list_archived(limit, search)

            return jsonify(
                {
                    "pages": pages,
                    "count": len(pages),
                }
            )

        except Exception as e:
            logger.error(f"Archive list error: {e}")
            return jsonify({"error": str(e)}), 500

    @app.route("/api/browser/archive/<archive_id>", methods=["GET"])
    @require_auth
    async def browser_archive_get(archive_id: str):
        """Get a specific archived page."""
        try:
            page = await browser_skill.get_archived(archive_id)

            if not page:
                return jsonify({"error": "Page not found"}), 404

            return jsonify(page)

        except Exception as e:
            logger.error(f"Archive get error: {e}")
            return jsonify({"error": str(e)}), 500

    @app.route("/api/browser/archive/<archive_id>", methods=["DELETE"])
    @require_auth
    async def browser_archive_delete(archive_id: str):
        """Delete an archived page."""
        try:
            success = await browser_skill.delete_archived(archive_id)

            return jsonify(
                {
                    "success": success,
                }
            )

        except Exception as e:
            logger.error(f"Archive delete error: {e}")
            return jsonify({"error": str(e)}), 500

    @app.route("/api/browser/archive/search", methods=["POST"])
    @require_auth
    async def browser_archive_search():
        """Full-text search across archived pages."""
        try:
            data = request.get_json()
            query = data.get("query")

            if not query:
                return jsonify({"error": "Query required"}), 400

            results = await browser_skill.search_archive(query)

            return jsonify(
                {
                    "query": query,
                    "results": results,
                }
            )

        except Exception as e:
            logger.error(f"Archive search error: {e}")
            return jsonify({"error": str(e)}), 500

    @app.route("/api/browser/history", methods=["GET"])
    @require_auth
    async def browser_history():
        """Get browsing history (session only)."""
        limit = request.args.get("limit", 20, type=int)
        history = browser_skill.get_history(limit)

        return jsonify(
            {
                "history": history,
            }
        )

    @app.route("/api/browser/history", methods=["DELETE"])
    @require_auth
    async def browser_history_clear():
        """Clear browsing history."""
        browser_skill.clear_history()

        return jsonify(
            {
                "success": True,
            }
        )

    @app.route("/api/browser/stats", methods=["GET"])
    @require_auth
    async def browser_stats():
        """Get browser statistics."""
        try:
            stats = await browser_skill.get_stats()

            return jsonify(stats)

        except Exception as e:
            logger.error(f"Stats error: {e}")
            return jsonify({"error": str(e)}), 500

    logger.info("Browser API routes registered")
