import json
import traceback

from flask import Blueprint, jsonify, make_response, session, request

from ...database.models import ResearchHistory
from ...database.models.library import Document as Document
from ...database.session_context import get_user_db_session
from ..auth.decorators import login_required
from ..models.database import (
    get_logs_for_research,
    get_total_logs_for_research,
)
from ..routes.globals import get_globals
from ..services.research_service import get_research_strategy
from ..utils.rate_limiter import limiter
from ..utils.templates import render_template_with_defaults

# Create a Blueprint for the history routes
history_bp = Blueprint("history", __name__, url_prefix="/history")


# resolve_report_path removed - reports are now stored in database


@history_bp.route("/")
@login_required
def history_page():
    """Render the history page"""
    return render_template_with_defaults("pages/history.html")


@history_bp.route("/api", methods=["GET"])
@login_required
def get_history():
    """Get the research history JSON data"""
    username = session.get("username")
    if not username:
        return jsonify({"status": "error", "message": "Not authenticated"}), 401

    try:
        with get_user_db_session(username) as db_session:
            # Get all history records ordered by latest first
            results = (
                db_session.query(ResearchHistory)
                .order_by(ResearchHistory.created_at.desc())
                .all()
            )

            # Convert to list of dicts
            history = []
            for research in results:
                # Count documents in the library for this research
                doc_count = (
                    db_session.query(Document)
                    .filter_by(research_id=research.id)
                    .count()
                )

                item = {
                    "id": research.id,
                    "title": research.title,
                    "query": research.query,
                    "mode": research.mode,
                    "status": research.status,
                    "created_at": research.created_at,
                    "completed_at": research.completed_at,
                    "duration_seconds": research.duration_seconds,
                    "report_path": research.report_path,
                    "document_count": doc_count,  # Add document count
                    "research_meta": json.dumps(research.research_meta)
                    if research.research_meta
                    else "{}",
                    "progress_log": json.dumps(research.progress_log)
                    if research.progress_log
                    else "[]",
                }

                # Parse research_meta as metadata for the frontend
                try:
                    metadata = json.loads(item["research_meta"])
                    item["metadata"] = metadata
                except:
                    item["metadata"] = {}

                # Ensure timestamps are in ISO format
                if item["created_at"] and "T" not in item["created_at"]:
                    try:
                        # Convert to ISO format if it's not already
                        from dateutil import parser

                        dt = parser.parse(item["created_at"])
                        item["created_at"] = dt.isoformat()
                    except Exception:
                        pass

                if item["completed_at"] and "T" not in item["completed_at"]:
                    try:
                        # Convert to ISO format if it's not already
                        from dateutil import parser

                        dt = parser.parse(item["completed_at"])
                        item["completed_at"] = dt.isoformat()
                    except Exception:
                        pass

                # Recalculate duration based on timestamps if it's null but both timestamps exist
                if (
                    item["duration_seconds"] is None
                    and item["created_at"]
                    and item["completed_at"]
                ):
                    try:
                        from dateutil import parser

                        start_time = parser.parse(item["created_at"])
                        end_time = parser.parse(item["completed_at"])
                        item["duration_seconds"] = int(
                            (end_time - start_time).total_seconds()
                        )
                    except Exception as e:
                        print(f"Error recalculating duration: {e!s}")

                history.append(item)

        # Format response to match what client expects
        response_data = {
            "status": "success",
            "items": history,  # Use 'items' key as expected by client
        }

        # Add CORS headers
        response = make_response(jsonify(response_data))
        response.headers.add("Access-Control-Allow-Origin", "*")
        response.headers.add(
            "Access-Control-Allow-Headers", "Content-Type,Authorization"
        )
        response.headers.add(
            "Access-Control-Allow-Methods", "GET,PUT,POST,DELETE,OPTIONS"
        )
        return response
    except Exception as e:
        print(f"Error getting history: {e!s}")
        print(traceback.format_exc())
        # Return empty array with CORS headers
        response = make_response(
            jsonify(
                {
                    "status": "error",
                    "items": [],
                    "message": "Failed to retrieve history",
                }
            )
        )
        response.headers.add("Access-Control-Allow-Origin", "*")
        response.headers.add(
            "Access-Control-Allow-Headers", "Content-Type,Authorization"
        )
        response.headers.add(
            "Access-Control-Allow-Methods", "GET,PUT,POST,DELETE,OPTIONS"
        )
        return response


@history_bp.route("/status/<string:research_id>")
@limiter.exempt
@login_required
def get_research_status(research_id):
    username = session.get("username")
    if not username:
        return jsonify({"status": "error", "message": "Not authenticated"}), 401

    with get_user_db_session(username) as db_session:
        research = (
            db_session.query(ResearchHistory).filter_by(id=research_id).first()
        )

    if not research:
        return jsonify(
            {"status": "error", "message": "Research not found"}
        ), 404

    result = {
        "id": research.id,
        "query": research.query,
        "mode": research.mode,
        "status": research.status,
        "created_at": research.created_at,
        "completed_at": research.completed_at,
        "progress_log": research.progress_log,
        "report_path": research.report_path,
    }

    globals_dict = get_globals()
    active_research = globals_dict["active_research"]

    # Add progress information
    if research_id in active_research:
        result["progress"] = active_research[research_id]["progress"]
        result["log"] = active_research[research_id]["log"]
    elif result.get("status") == "completed":
        result["progress"] = 100
        try:
            result["log"] = json.loads(result.get("progress_log", "[]"))
        except Exception:
            result["log"] = []
    else:
        result["progress"] = 0
        try:
            result["log"] = json.loads(result.get("progress_log", "[]"))
        except Exception:
            result["log"] = []

    return jsonify(result)


@history_bp.route("/details/<string:research_id>")
@login_required
def get_research_details(research_id):
    """Get detailed progress log for a specific research"""
    from loguru import logger

    logger.info(f"Details route accessed for research_id: {research_id}")
    logger.info(f"Request headers: {dict(request.headers)}")
    logger.info(f"Request URL: {request.url}")

    username = session.get("username")
    if not username:
        logger.error("No username in session")
        return jsonify({"status": "error", "message": "Not authenticated"}), 401

    try:
        with get_user_db_session(username) as db_session:
            # Log all research IDs for this user
            all_research = db_session.query(
                ResearchHistory.id, ResearchHistory.query
            ).all()
            logger.info(
                f"All research for user {username}: {[(r.id, r.query[:30]) for r in all_research]}"
            )

            research = (
                db_session.query(ResearchHistory)
                .filter_by(id=research_id)
                .first()
            )
            logger.info(f"Research query result: {research}")
    except Exception:
        logger.exception("Database error")
        return jsonify(
            {
                "status": "error",
                "message": "An internal database error occurred.",
            }
        ), 500

    if not research:
        logger.error(f"Research not found for id: {research_id}")
        return jsonify(
            {"status": "error", "message": "Research not found"}
        ), 404

    # Get logs from the dedicated log database
    logs = get_logs_for_research(research_id)

    # Get strategy information
    strategy_name = get_research_strategy(research_id)

    globals_dict = get_globals()
    active_research = globals_dict["active_research"]

    # If this is an active research, merge with any in-memory logs
    if research_id in active_research:
        # Use the logs from memory temporarily until they're saved to the database
        memory_logs = active_research[research_id]["log"]

        # Filter out logs that are already in the database by timestamp
        db_timestamps = {log["time"] for log in logs}
        unique_memory_logs = [
            log for log in memory_logs if log["time"] not in db_timestamps
        ]

        # Add unique memory logs to our return list
        logs.extend(unique_memory_logs)

        # Sort logs by timestamp
        logs.sort(key=lambda x: x["time"])

    return jsonify(
        {
            "research_id": research_id,
            "query": research.query,
            "mode": research.mode,
            "status": research.status,
            "strategy": strategy_name,
            "progress": active_research.get(research_id, {}).get(
                "progress", 100 if research.status == "completed" else 0
            ),
            "created_at": research.created_at,
            "completed_at": research.completed_at,
            "log": logs,
        }
    )


@history_bp.route("/report/<string:research_id>")
@login_required
def get_report(research_id):
    from ...storage import get_report_storage
    from ..auth.decorators import current_user

    username = current_user()

    with get_user_db_session(username) as db_session:
        research = (
            db_session.query(ResearchHistory).filter_by(id=research_id).first()
        )

        if not research:
            return jsonify(
                {"status": "error", "message": "Report not found"}
            ), 404

        try:
            # Get report using storage abstraction
            storage = get_report_storage(session=db_session)
            report_data = storage.get_report_with_metadata(
                research_id, username
            )

            if not report_data:
                return jsonify(
                    {"status": "error", "message": "Report content not found"}
                ), 404

            # Extract content and metadata
            content = report_data.get("content", "")
            stored_metadata = report_data.get("metadata", {})

            # Create an enhanced metadata dictionary with database fields
            enhanced_metadata = {
                "query": research.query,
                "mode": research.mode,
                "created_at": research.created_at,
                "completed_at": research.completed_at,
                "duration": research.duration_seconds,
            }

            # Merge with stored metadata
            enhanced_metadata.update(stored_metadata)

            return jsonify(
                {
                    "status": "success",
                    "content": content,
                    "query": research.query,
                    "mode": research.mode,
                    "created_at": research.created_at,
                    "completed_at": research.completed_at,
                    "metadata": enhanced_metadata,
                }
            )
        except Exception:
            return jsonify(
                {"status": "error", "message": "Failed to retrieve report"}
            ), 500


@history_bp.route("/markdown/<string:research_id>")
@login_required
def get_markdown(research_id):
    """Get markdown export for a specific research"""
    from ...storage import get_report_storage
    from ..auth.decorators import current_user

    username = current_user()

    with get_user_db_session(username) as db_session:
        research = (
            db_session.query(ResearchHistory).filter_by(id=research_id).first()
        )

        if not research:
            return jsonify(
                {"status": "error", "message": "Report not found"}
            ), 404

        try:
            # Get report using storage abstraction
            storage = get_report_storage(session=db_session)
            content = storage.get_report(research_id, username)

            if not content:
                return jsonify(
                    {"status": "error", "message": "Report content not found"}
                ), 404

            return jsonify({"status": "success", "content": content})
        except Exception:
            return jsonify(
                {"status": "error", "message": "Failed to retrieve report"}
            ), 500


@history_bp.route("/logs/<string:research_id>")
@login_required
def get_research_logs(research_id):
    """Get logs for a specific research ID"""
    username = session.get("username")
    if not username:
        return jsonify({"status": "error", "message": "Not authenticated"}), 401

    # First check if the research exists
    with get_user_db_session(username) as db_session:
        research = (
            db_session.query(ResearchHistory).filter_by(id=research_id).first()
        )

    if not research:
        return jsonify(
            {"status": "error", "message": "Research not found"}
        ), 404

    # Retrieve logs from the database
    logs = get_logs_for_research(research_id)

    # Format logs correctly if needed
    formatted_logs = []
    for log in logs:
        log_entry = log.copy()
        # Ensure each log has time, message, and type fields
        log_entry["time"] = log.get("time", "")
        log_entry["message"] = log.get("message", "No message")
        log_entry["type"] = log.get("type", "info")
        formatted_logs.append(log_entry)

    return jsonify({"status": "success", "logs": formatted_logs})


@history_bp.route("/log_count/<string:research_id>")
@login_required
def get_log_count(research_id):
    """Get the total number of logs for a specific research ID"""
    # Get the total number of logs for this research ID
    total_logs = get_total_logs_for_research(research_id)

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