import os
from datetime import datetime, timezone
from pathlib import Path

from flask import Blueprint, current_app, jsonify, render_template, request, url_for
from flask_babel import _
from werkzeug.utils import secure_filename

from DocumentManager.Constants import NET_ACCESS, TEMP_CHAT_RESPONSE, get_temp_chat_response_by_lang
from config import DEFULT_TEXT_MODEL_NAME
from extensions import db, socketio
from flask_socketio import emit

from models.ai_model import AITaskModelConfig, ModelType
from services import auth_service
from services.chat_service import ChatService

from models.chats import ChatMessage, SenderTypeEnum, ChatMessageImage, ChatSession
from models.incident_model import IncidentAnalysisModel, IncidentModel
from Copilot.Utils.CopilotUtils import gen_incident_analyze_message, gen_incident_message
from utils.services import detect_message_language
from models.doc_manager import DocConfig
from extensions import INDUSTRIAL_COPILOT


chatbot_bp = Blueprint("chatbot", __name__)


@chatbot_bp.route("/chat", endpoint="chat_page")
@auth_service.login_required("web.home_page")
def chat_page():
    return render_template("chat.html", 
                           is_admin = auth_service.is_admin(),
                           industrial_copilot = INDUSTRIAL_COPILOT)


@chatbot_bp.route("/chat/<string:session_url>", methods=["GET"])
@auth_service.login_required("web.home_page")
def chat_page_by_session(session_url):
    """
    Render chat page for a specific session (owner only).
    NOTE: session_url is the session token (slug) stored in DB (NOT "/chat/<token>").
    """
    user = auth_service.current_user()

    # Ensure the session belongs to the current user
    session = ChatSession.query.filter_by(session_url=session_url, user_id=user.id).first()
    if not session:
        return "Session not found", 404

    # Pass token/slug to template (if template wants it)
    return render_template("chat.html", 
                           session_url=session.session_url,
                           industrial_copilot = INDUSTRIAL_COPILOT)


# -------------------------
# Sessions APIs
# -------------------------
@chatbot_bp.route("/api/chat/sessions", methods=["GET"], endpoint="list_sessions_api")
@auth_service.login_required("web.home_page")
def list_sessions_api():
    """
    Return user's sessions ordered by most recently updated (OpenAI-like sidebar).
    Frontend gets:
      - id: numeric id
      - title
      - updated_at
      - session_url: FULL PATH "/chat/<token>" for pushState/links
    """
    user = auth_service.current_user()

    sessions = ChatSession.list_user_sessions(user.id, limit=200)
    if not sessions:
        # Ensure at least one session exists
        sess = ChatSession.get_or_create_latest_session(user.id)
        sessions = [sess]

    out = []
    for s in sessions:
        s:ChatSession
        out.append(
            {
                "id": s.id,
                "incident_id": s.get_incident_id(),
                "title": s.title,
                "updated_at": s.updated_at.isoformat() if s.updated_at else None,
                # IMPORTANT: full URL path for routing
                "session_url": url_for(
                    "chatbot.chat_page_by_session", session_url=s.session_url, _external=False
                ),
            }
        )

    active_session_url = out[0]["session_url"]

    return jsonify(
        {
            "success": True,
            "active_session_url": active_session_url,
            "sessions": out,
        }
    )


@chatbot_bp.route("/api/chat/session/create", methods=["POST"])
@auth_service.login_required("web.home_page")
def create_session_api():
    """
    Create a new empty chat session.
    IMPORTANT:
      - DB stores ONLY the token in ChatSession.session_url (e.g. "Xd7rtjHIeoXO2rkL")
      - Frontend receives a FULL PATH "/chat/<token>" as session_url.
    """
    user = auth_service.current_user()

    sess = ChatSession(user_id=user.id, title=_("گفتگوی جدید"))
    db.session.add(sess)
    db.session.commit()

    session_full_url = url_for(
        "chatbot.chat_page_by_session", session_url=sess.session_url, _external=False
    )

    return jsonify(
        {
            "success": True,
            "session_url": session_full_url,  # "/chat/<token>"
            "session_id": sess.id,
            "title": sess.title,
        }
    )


@chatbot_bp.route("/api/chat/session/delete", methods=["POST"], endpoint="delete_session_api")
@auth_service.login_required("web.home_page")
def delete_session_api():
    """
    Delete a single session and its resources (messages/images).

    Backward compatible:
      - Accepts either session_id (preferred) OR session_url (token OR "/chat/<token>").

    Returns:
      - fallback_session_url: FULL PATH "/chat/<token>" for redirect/pushState
      - fallback_session_id: numeric id (optional but useful)
    """
    user = auth_service.current_user()
    data = request.get_json(silent=True) or {}

    session_id = data.get("session_id")
    session_url = data.get("session_url")

    sess = None

    # Resolve by session_id first (matches your current JS)
    if session_id:
        try:
            sess = ChatSession.query.filter_by(user_id=user.id, id=int(session_id)).first()
        except Exception:
            sess = None

    # Fallback resolve by session_url (token or "/chat/<token>")
    if not sess and session_url:
        if isinstance(session_url, str) and session_url.startswith("/chat/"):
            session_url = session_url[len("/chat/") :]
        sess = ChatSession.query.filter_by(user_id=user.id, session_url=session_url).first()

    if not sess:
        return jsonify({"success": False, "message": "نشست یافت نشد"}), 404

    # Delete image files linked to this session before deleting DB rows
    remove_session_image_files(user.id, sess.id)

    # Delete DB rows (session + messages/images)
    # This method expects token stored in DB (NOT "/chat/<token>")
    ok = ChatSession.delete_session_by_url(user.id, sess.session_url)
    if not ok:
        return jsonify({"success": False, "message": "نشست یافت نشد"}), 404

    # Always keep at least one session available
    fallback = ChatSession.get_or_create_latest_session(user.id)

    return jsonify(
        {
            "success": True,
            "fallback_session_url": url_for(
                "chatbot.chat_page_by_session",
                session_url=fallback.session_url,
                _external=False,
            ),
            "fallback_session_id": fallback.id,
        }
    )


# -------------------------
# Session-aware history
# -------------------------
@chatbot_bp.route("/api/load_chat_history", methods=["GET"], endpoint="load_chat_history")
@auth_service.login_required("web.home_page")
def load_chat_history():
    """
    Load chat history for a session.

    Backward compatible:
      - Accepts either session_id OR session_url (token OR "/chat/<token>").
      - If missing/invalid, falls back to latest session.

    Returns:
      - active_session_url: FULL PATH "/chat/<token>"
      - active_session_id: numeric id
      - messages: list
    """
    user = auth_service.current_user()

    session_id = request.args.get("session_id", type=int)
    session_url = request.args.get("session_url", type=str)

    sess = None

    # Resolve by session_id first
    if session_id:
        sess = ChatSession.query.filter_by(user_id=user.id, id=session_id).first()

    

    # Fallback resolve by session_url (token or "/chat/<token>")
    if not sess and session_url:
        if session_url.startswith("/chat/"):
            session_url = session_url[len("/chat/") :]
        sess = ChatSession.query.filter_by(user_id=user.id, session_url=session_url).first()

    if not sess:
        sess = ChatSession.get_or_create_latest_session(user.id)

    messages = ChatMessage.get_user_chat_history(
        user_id=user.id,
        session_id=sess.id,
        limit=100,
    )

    result = []
    for msg in messages:
        result.append(
            {
                "id": msg.id,
                "message": ChatService.remove_harakat(msg.message),
                "sender_type": msg.sender_type.value,  # 'user' or 'bot'
                "images": [img.image_url for img in msg.images.order_by(ChatMessageImage.id)],
                "created_at": msg.created_at.isoformat(),
            }
        )

    return jsonify(
        {
            "success": True,
            "active_session_url": url_for(
                "chatbot.chat_page_by_session", session_url=sess.session_url, _external=False
            ),
            "active_session_id": sess.id,
            "incident_id": sess.get_incident_id(),
            "messages": result,

        }
    )


# -------------------------
# Share session
# -------------------------
@chatbot_bp.route("/api/chat/session/share", methods=["POST"], endpoint="share_session_api")
@auth_service.login_required("web.home_page")
def share_session_api():
    """
    Enable sharing for a session and return a public share URL (token-based).
    """
    user = auth_service.current_user()
    data = request.get_json(silent=True) or {}
    session_id = data.get("session_id")

    if not session_id:
        return jsonify({"success": False, "message": "شناسه نشست الزامی است"}), 400

    sess = ChatSession.query.filter_by(user_id=user.id, id=int(session_id)).first()
    if not sess:
        return jsonify({"success": False, "message": "نشست یافت نشد"}), 404

    # Ensure token exists
    sess.ensure_share_token()
    db.session.commit()

    share_url = url_for("chatbot.shared_chat_page", token=sess.share_token, _external=True)

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


@chatbot_bp.route("/api/chat/session/unshare", methods=["POST"], endpoint="unshare_session_api")
@auth_service.login_required("web.home_page")
def unshare_session_api():
    """
    Disable sharing for a session (revokes the share token).
    """
    user = auth_service.current_user()
    data = request.get_json(silent=True) or {}
    session_id = data.get("session_id")

    if not session_id:
        return jsonify({"success": False, "message": "شناسه نشست الزامی است"}), 400

    sess = ChatSession.query.filter_by(user_id=user.id, id=int(session_id)).first()
    if not sess:
        return jsonify({"success": False, "message": "نشست یافت نشد"}), 404

    sess.is_shared = False
    sess.share_token = None
    sess.shared_at = None
    db.session.commit()

    return jsonify({"success": True})


@chatbot_bp.route("/share/<string:token>", methods=["GET"], endpoint="shared_chat_page")
def shared_chat_page(token):
    """
    Render the SAME chat.html, but in read-only shared mode.
    No login_required here.
    """
    return render_template("chat.html", share_token=token, shared_view=True)


@chatbot_bp.route("/api/share/history", methods=["GET"])
def shared_history_api():
    """
    Public (token-based) read-only history endpoint for shared sessions.
    """
    token = request.args.get("token", "").strip()
    if not token:
        return jsonify({"success": False, "message": "توکن الزامی است"}), 400

    sess = ChatSession.query.filter_by(share_token=token, is_shared=True).first()
    if not sess:
        return jsonify({"success": False, "message": "یافت نشد"}), 404

    messages = (
        ChatMessage.query.filter_by(session_id=sess.id, user_id=sess.user_id)
        .order_by(ChatMessage.id.asc())
        .limit(200)
        .all()
    )

    result = []
    for msg in messages:
        result.append(
            {
                "id": msg.id,
                "message": ChatService.remove_harakat(msg.message),
                "sender_type": msg.sender_type.value,
                "images": [img.image_url for img in msg.images.order_by(ChatMessageImage.id)],
                "created_at": msg.created_at.isoformat(),
            }
        )

    return jsonify(
        {
            "success": True,
            "session_title": sess.title,
            "messages": result,
        }
    )


# -------------------------
# Send message (session-aware)
# -------------------------
@chatbot_bp.route("/api/chat", methods=["POST"], endpoint="api_chat")
@auth_service.login_required("web.home_page")
def api_chat():
    """
    Main chat endpoint; session-aware but backward-compatible.
    Accepts:
      - message (form)
      - images (files)
      - session_id (form) [preferred]
      - session_url (form) [token OR "/chat/<token>"] (optional fallback)
    """
    files = request.files.getlist("images")
    message = request.form.get("message", "")
    session_id = request.form.get("session_id", type=int)
    session_url = request.form.get("session_url", type=str)
    

    image_urls = []
    for file in files:
        if file:
            status, url = save_image(file=file)
            if status:
                image_urls.append(url)

    if not message and not image_urls:
        return jsonify({"success": False, "message": "پیام خالی است"}), 400

    user = auth_service.current_user()


    # Resolve session by session_id first
    sess = None
    if session_id:
        sess = ChatSession.query.filter_by(user_id=user.id, id=session_id).first()

    # Fallback resolve by session_url token
    if not sess and session_url:
        if session_url.startswith("/chat/"):
            session_url = session_url[len("/chat/") :]
            
        sess = ChatSession.query.filter_by(user_id=user.id, session_url=session_url).first()

    # Final fallback to latest session
    if not sess:
        sess = ChatSession.get_or_create_latest_session(user.id)

    # Fetch last messages within the session
    incident_msgs = []
    if INDUSTRIAL_COPILOT:
        incident_analyze_id = sess.get_incident_id()
        if incident_analyze_id:
            incident_msgs.append(
                gen_incident_message(incident_analyze_id)
                )
            incident_msgs.append(
                gen_incident_analyze_message(incident_analyze_id)
            )
            

  
        

    history = ChatMessage.get_user_chat_history(user.id, 20, session_id=sess.id)
    if incident_msgs:
        history = incident_msgs + history 

    doc_config = DocConfig.query.get(1)  # تک‌سطر
    top_k = doc_config.top_k
    doc_manager = current_app.doc_manager
    retrieved_chunks, retrieved_metadata = doc_manager.search(message,top_k=top_k)
    source_prompt = ChatService.chunks_to_prompt(retrieved_chunks)
    text_model = AITaskModelConfig.get_model_for_task(ModelType.TEXT)
    text_model_name = text_model.name
    if NET_ACCESS:
        # Ask OpenAI
        reply, success = ChatService.ask_openai(
            user_message=message,
            history=history,
            image_urls=image_urls,
            resources=source_prompt,
            text_model_name=text_model_name,
            enable_web_search=text_model.supports_web_search

        )
    else:
        current_app.logger.warning("Network access disabled")
        reply = get_temp_chat_response_by_lang()
        success = True
    if not success:

        return jsonify({"success": False, "reply": "خطا در ارتباط با سرور"})


    lang = detect_message_language(message)
    
    # Save user message
    user_msg = ChatMessage(
        user_id=user.id,
        session_id=sess.id,
        sender_type=SenderTypeEnum.USER,
        message=message,
        language = lang
    )
    db.session.add(user_msg)
    db.session.flush()

    # Save images if any
    for img_url in image_urls or []:
        chat_image = ChatMessageImage(chat_message_id=user_msg.id, image_url=img_url)
        db.session.add(chat_image)
    lang = detect_message_language(reply)

    # Save bot message
    bot_msg = ChatMessage(
        user_id=user.id,
        session_id=sess.id,
        sender_type=SenderTypeEnum.BOT,
        message=reply,
        language = lang

    )
    db.session.add(bot_msg)

    # Touch session updated_at
    sess.updated_at = datetime.now(timezone.utc)

    db.session.commit()

    # Update session title if still default
    ChatService.maybe_update_session_title(sess.id, message,text_model_name = text_model_name)

    return jsonify(
        {
            "success": True,
            "reply": ChatService.remove_harakat(reply),
            "session_id": sess.id,
            "session_url": url_for(
                "chatbot.chat_page_by_session", session_url=sess.session_url, _external=False
            ),
        }
    )


# -------------------------
# Reset ALL history (keep existing behavior)
# -------------------------
@chatbot_bp.route("/api/chat/reset", methods=["POST"], endpoint="reset_chat_api")
@auth_service.login_required("web.home_page")
def reset_chat_api():
    """
    Delete all sessions/messages/images for the user (global clear).
    """
    user = auth_service.current_user()
    remove_user_image_files(user.id)
    ChatMessage.reset_history(user.id)

    return jsonify(
        {
            "success": True,
            "message": "تاریخچه گفتگو پاک شد. می‌توانید گفتگوی جدیدی شروع کنید",
        }
    )


# -------------------------
# Image upload endpoint (kept)
# -------------------------
@chatbot_bp.route("/upload-image", methods=["POST"], endpoint="upload_image_api")
def upload_image_api():
    file = request.files.get("file")
    msg = request.form.get("message", "")

    if not file:
        return jsonify({"success": False, "error": "فایلی یافته نشد"}), 400

    status, image_url = save_image(file=file)

    return jsonify(
        {
            "success": status,
            "image_url": image_url,
            "text": "",
        }
    )


# -------------------------
# Helpers
# -------------------------
def save_image(file):
    """
    Save image into /static/uploads and return (status, url).
    """
    status = False
    image_url = ""
    try:
        static_folder = current_app.static_folder
        upload_dir = Path(static_folder) / "uploads"
        upload_dir.mkdir(parents=True, exist_ok=True)

        filename = secure_filename(file.filename)
        name, ext = os.path.splitext(filename)
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        filename = f"{name}_{timestamp}{ext}"

        save_path = upload_dir / filename
        file.save(save_path)

        image_url = url_for("static", filename=f"uploads/{filename}", _external=False)
        status = True
    except Exception as e:
        current_app.logger.warning("save_image failed: %s", e, exc_info=True)
        status = False

    return status, image_url


def remove_user_image_files(user_id: int):
    """
    Delete all image files on disk linked to the user's chat messages.
    NOTE: This function currently only queries rows; it does not delete files.
    """
    image_rows = (
        db.session.query(ChatMessageImage.image_url)
        .join(ChatMessage, ChatMessage.id == ChatMessageImage.chat_message_id)
        .filter(ChatMessage.user_id == user_id)
        .all()
    )

    for (image_url,) in image_rows:
        _delete_local_image_path(image_url)


def remove_session_image_files(user_id: int, session_id: int):
    """
    Delete image files on disk linked to a specific session.
    """
    image_rows = (
        db.session.query(ChatMessageImage.image_url)
        .join(ChatMessage, ChatMessage.id == ChatMessageImage.chat_message_id)
        .filter(ChatMessage.user_id == user_id, ChatMessage.session_id == session_id)
        .all()
    )

    for (image_url,) in image_rows:
        _delete_local_image_path(image_url)


def _delete_local_image_path(image_url: str):
    """
    Delete a local stored image path safely.
    """
    if not image_url:
        return

    # Skip remote URLs
    if image_url.startswith("http://") or image_url.startswith("https://"):
        return

    static_folder = current_app.static_folder

    # Stored URLs look like "/static/uploads/<filename>"
    relative_part = image_url
    if relative_part.startswith("/static/"):
        relative_part = relative_part[len("/static/") :]
    elif relative_part.startswith("static/"):
        relative_part = relative_part[len("static/") :]

    file_path = Path(static_folder) / relative_part.lstrip("/")
    try:
        file_path.unlink(missing_ok=True)
    except Exception:
        current_app.logger.warning("Failed to delete image file %s", file_path, exc_info=True)


# --------------------
# WebSocket events
# --------------------
@socketio.on("connect")
def handle_connect():
    print("Client connected")
    emit("server_status", {"status": "online"})
