# -*- coding: utf-8 -*-
"""
troubleshoot.py — 排查相关 API 路由

从原 server.py 迁入：troubleshoot / search_cases / analyze / analyze_stream
/ format_matched_cases / health_check / get_projects / get_categories。

页面路由已迁移到 Vue SPA，本文件仅保留 API 端点。
"""

import json
import time
from datetime import datetime

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

import container
from decorators import page_login_required
from services.ai_service import build_prompt, call_claude_api, call_claude_api_stream, build_offline_response
from utils.audit import log_audit
from utils.response import error_response
from utils.error_codes import ErrorCodes
from utils.logger import get_logger
from utils.offline_config import is_offline_mode

logger = get_logger(__name__)

bp = Blueprint('troubleshoot', __name__)

# 页面路由 /troubleshoot 已迁移到 Vue SPA
# 由 server.py 的 spa_fallback 处理


def format_matched_cases(matched_cases_data):
    """格式化匹配案例数据为标准返回格式"""
    if not matched_cases_data:
        return []
    return [
        {
            'rank': c['rank'],
            'score': c['score'],
            'project': c.get('record', {}).get('project', ''),
            'title': c.get('record', {}).get('title', ''),
            'file': c.get('record', {}).get('file', ''),
            'phenomenon': c.get('record', {}).get('phenomenon', ''),
        }
        for c in matched_cases_data
    ]


@bp.route('/api/troubleshoot', methods=['POST'])
def troubleshoot():
    """排查问题 API（原有完整流程，保持兼容）"""
    data = request.get_json() or {}

    project_name = data.get('project_name', '').strip()
    system_type = data.get('system_type', '').strip()
    apk_product = data.get('apk_product', '').strip()
    query = data.get('query', '').strip()

    if not query:
        return jsonify(error_response(ErrorCodes.INVALID_PARAM, '请输入问题描述')), 400

    try:
        # 1. 搜索匹配案例
        engine = container.get_search_engine()
        matched_cases_data = engine.search(
            query,
            top_k=5,
            project_filter=project_name if project_name else None,
        )

        # ============================================================
        # 【离线模式】跳过 Claude API，直接返回搜索结果（PRD §3.4）
        # ============================================================
        if is_offline_mode():
            result = build_offline_response(matched_cases_data)
            log_audit({
                'timestamp': datetime.now().isoformat(),
                'user': session.get('user', {}).get('username', ''),
                'module': 'troubleshoot',
                'action': 'analyze',
                'target': query[:50] if query else '',
                'ip': request.remote_addr or '',
                'project': project_name,
                'system_type': system_type,
                'apk_product': apk_product,
                'query': query,
                'matched_count': len(matched_cases_data),
                'api_time': 0.0,
                'mode': 'offline',
            })
            return jsonify({
                'success': True,
                'response': result['response'],
                'matched_cases': format_matched_cases(matched_cases_data),
                'offline': True,
                'api_time': 0.0,
            })

        # 2. 构建 Prompt
        prompt = build_prompt(query, project_name, system_type, apk_product, matched_cases_data)

        # 3. 调用 Claude API
        start_time = time.time()
        raw_response = call_claude_api(prompt)
        api_time = time.time() - start_time

        # 4. 安全过滤
        sf = container.get_safety_filter()
        filter_result = sf.filter_output(raw_response, query)

        # 5. 审计日志
        log_audit({
            'timestamp': datetime.now().isoformat(),
            'user': session.get('user', {}).get('username', ''),
            'module': 'troubleshoot',
            'action': 'analyze',
            'target': query[:50] if query else '',
            'ip': request.remote_addr or '',
            'project': project_name,
            'system_type': system_type,
            'apk_product': apk_product,
            'query': query,
            'matched_count': len(matched_cases_data),
            'api_time': round(api_time, 2),
            'removed_lines': len(filter_result.get('removed_lines', [])),
        })

        # 6. 返回结果
        return jsonify({
            'success': True,
            'response': filter_result['filtered_text'],
            'matched_cases': format_matched_cases(matched_cases_data),
            'filter_warnings': filter_result.get('removed_lines', []),
            'api_time': round(api_time, 2),
        })

    except Exception as e:
        logger.exception("排查接口服务异常")
        return jsonify(error_response(ErrorCodes.UNKNOWN_ERROR, f'服务异常：{str(e)}')), 500


@bp.route('/api/search', methods=['POST'])
def search_cases():
    """渐进式排查 — 阶段一：仅搜索匹配案例（快速返回，<3s）"""
    data = request.get_json() or {}

    project_name = data.get('project_name', '').strip()
    query = data.get('query', '').strip()

    if not query:
        return jsonify(error_response(ErrorCodes.INVALID_PARAM, '请输入问题描述')), 400

    try:
        start_time = time.time()
        engine = container.get_search_engine()
        matched_cases_data = engine.search(
            query,
            top_k=5,
            project_filter=project_name if project_name else None,
        )
        search_time = time.time() - start_time

        return jsonify({
            'success': True,
            'matched_cases': format_matched_cases(matched_cases_data),
            'matched_count': len(matched_cases_data),
            'search_time': round(search_time, 2),
        })

    except Exception as e:
        logger.exception("搜索接口异常")
        return jsonify(error_response(ErrorCodes.SEARCH_QUERY_ERROR, f'搜索异常：{str(e)}')), 500


@bp.route('/api/analyze', methods=['POST'])
def analyze():
    """渐进式排查 — 阶段二：AI 深度分析（慢速返回，20-30s）"""
    data = request.get_json() or {}

    project_name = data.get('project_name', '').strip()
    system_type = data.get('system_type', '').strip()
    apk_product = data.get('apk_product', '').strip()
    query = data.get('query', '').strip()
    matched_cases = data.get('matched_cases', [])

    if not query:
        return jsonify(error_response(ErrorCodes.INVALID_PARAM, '请输入问题描述')), 400

    try:
        # ============================================================
        # 【离线模式】跳过 Claude API（PRD §3.4）
        # ============================================================
        if is_offline_mode():
            # analyze 收到的 matched_cases 是前端传来的已格式化数据
            # 直接用于离线响应（可能缺失 solution，但 title/phenomenon/score 等齐全）
            result = build_offline_response(matched_cases)
            log_audit({
                'timestamp': datetime.now().isoformat(),
                'user': session.get('user', {}).get('username', ''),
                'module': 'troubleshoot',
                'action': 'analyze',
                'target': query[:50] if query else '',
                'ip': request.remote_addr or '',
                'project': project_name,
                'system_type': system_type,
                'apk_product': apk_product,
                'query': query,
                'matched_count': len(matched_cases),
                'api_time': 0.0,
                'mode': 'offline_analyze',
            })
            return jsonify({
                'success': True,
                'response': result['response'],
                'offline': True,
                'api_time': 0.0,
            })

        # 1. 构建 Prompt（使用前端传来的匹配案例数据）
        prompt = build_prompt(query, project_name, system_type, apk_product, matched_cases)

        # 2. 调用 Claude API
        start_time = time.time()
        raw_response = call_claude_api(prompt)
        api_time = time.time() - start_time

        # 3. 安全过滤
        sf = container.get_safety_filter()
        filter_result = sf.filter_output(raw_response, query)

        # 4. 审计日志
        log_audit({
            'timestamp': datetime.now().isoformat(),
            'user': session.get('user', {}).get('username', ''),
            'module': 'troubleshoot',
            'action': 'analyze',
            'target': query[:50] if query else '',
            'ip': request.remote_addr or '',
            'project': project_name,
            'system_type': system_type,
            'apk_product': apk_product,
            'query': query,
            'matched_count': len(matched_cases),
            'api_time': round(api_time, 2),
            'removed_lines': len(filter_result.get('removed_lines', [])),
        })

        return jsonify({
            'success': True,
            'response': filter_result['filtered_text'],
            'filter_warnings': filter_result.get('removed_lines', []),
            'api_time': round(api_time, 2),
        })

    except Exception as e:
        logger.exception("分析接口异常")
        return jsonify(error_response(ErrorCodes.AI_API_ERROR, f'分析异常：{str(e)}')), 500


@bp.route('/api/analyze/stream', methods=['GET'])
def analyze_stream():
    """
    流式返回 AI 分析结果（SSE）。

    参数通过 URL query string 传递：
      - project_name: 项目名称
      - system_type: 系统类型
      - apk_product: APK 产品
      - query: 问题描述
      - model: 模型选择（可选）

    返回格式（SSE）：
      data: {"type": "start", "message": "正在分析..."}
      data: {"type": "matched_cases", "cases": [...]}
      data: {"type": "chunk", "content": "..."}
      data: {"type": "done", "api_time": 45.2}
    """
    project_name = request.args.get('project_name', '').strip()
    system_type = request.args.get('system_type', '').strip()
    apk_product = request.args.get('apk_product', '').strip()
    query = request.args.get('query', '').strip()
    model = request.args.get('model', '') or container.get_config().get('default_model', 'glm-5.1')

    # 在请求上下文内提前捕获（SSE 生成器执行时已脱离请求上下文）
    _audit_user = session.get('user', {}).get('username', '')
    _audit_ip = request.remote_addr or ''

    if not query:
        def error_gen():
            yield f'data: {json.dumps({"type": "error", "message": "请输入问题描述"}, ensure_ascii=False)}\n\n'
        return Response(error_gen(), mimetype='text/event-stream')

    # 离线模式：跳过缓存，直接走离线分支（<1s 无需缓存）
    if not is_offline_mode():
        # 检查缓存
        cache = container.get_cache_manager()
        cached_result = cache.get(project_name, system_type, apk_product, query)

        if cached_result:
            # 返回缓存结果
            def generate_cached():
                yield f'data: {json.dumps({"type": "start", "message": "正在分析...", "cached": True}, ensure_ascii=False)}\n\n'
                yield f'data: {json.dumps({"type": "matched_cases", "cases": cached_result.get("matched_cases", [])}, ensure_ascii=False)}\n\n'

                # 流式推送缓存内容
                cached_response = cached_result.get("response", "")
                chunk_size = 30
                for i in range(0, len(cached_response), chunk_size):
                    content_chunk = cached_response[i:i + chunk_size]
                    yield f'data: {json.dumps({"type": "chunk", "content": content_chunk}, ensure_ascii=False)}\n\n'
                    time.sleep(0.01)

                yield f'data: {json.dumps({"type": "done", "api_time": 0.5, "cached": True}, ensure_ascii=False)}\n\n'

            return Response(generate_cached(), mimetype='text/event-stream',
                           headers={'Cache-Control': 'no-cache', 'X-Accel-Buffering': 'no'})

    def generate():
        """生成器：流式返回内容"""
        start_time = time.time()

        try:
            # 1. 发送开始标记
            yield f'data: {json.dumps({"type": "start", "message": "正在分析...", "offline": is_offline_mode()}, ensure_ascii=False)}\n\n'

            # 2. 搜索匹配案例
            engine = container.get_search_engine()
            matched_cases_data = engine.search(query, top_k=5, project_filter=project_name if project_name else None)
            matched_cases = format_matched_cases(matched_cases_data)

            # 3. 发送匹配案例
            yield f'data: {json.dumps({"type": "matched_cases", "cases": matched_cases, "offline": is_offline_mode()}, ensure_ascii=False)}\n\n'

            # ============================================================
            # 【离线模式】单帧推送搜索结果后结束（PRD §3.4）
            # ============================================================
            if is_offline_mode():
                result = build_offline_response(matched_cases_data)
                # 单帧推送完整响应文本
                yield f'data: {json.dumps({"type": "chunk", "content": result["response"], "offline": True}, ensure_ascii=False)}\n\n'
                api_time = time.time() - start_time
                yield f'data: {json.dumps({"type": "done", "api_time": round(api_time, 2), "offline": True}, ensure_ascii=False)}\n\n'
                log_audit({
                    'timestamp': datetime.now().isoformat(),
                    'user': _audit_user,
                    'module': 'troubleshoot',
                    'action': 'analyze',
                    'target': query[:50] if query else '',
                    'ip': _audit_ip,
                    'project': project_name,
                    'system_type': system_type,
                    'apk_product': apk_product,
                    'query': query,
                    'matched_count': len(matched_cases),
                    'api_time': round(api_time, 2),
                    'mode': 'offline_stream',
                })
                return

            # 4. 构建 Prompt
            prompt = build_prompt(query, project_name, system_type, apk_product, matched_cases_data)

            # 5. 收集完整响应（用于安全过滤）
            full_response = ""
            for chunk in call_claude_api_stream(prompt, model=model):
                full_response += chunk

            # 6. 安全过滤（包含敏感信息过滤）
            sf = container.get_safety_filter()
            filter_result = sf.filter_output_with_sensitive(full_response, query)
            filtered_text = filter_result['filtered_text']

            # 7. 存入缓存
            cache.set(project_name, system_type, apk_product, query, filtered_text, matched_cases)

            # 8. 流式推送过滤后的内容（分块发送，模拟打字效果）
            chunk_size = 30  # 每次发送的字符数
            for i in range(0, len(filtered_text), chunk_size):
                content_chunk = filtered_text[i:i + chunk_size]
                yield f'data: {json.dumps({"type": "chunk", "content": content_chunk}, ensure_ascii=False)}\n\n'
                time.sleep(0.01)  # 小延迟，模拟打字效果

            # 9. 发送完成标记
            api_time = time.time() - start_time
            yield f'data: {json.dumps({"type": "done", "api_time": round(api_time, 2)}, ensure_ascii=False)}\n\n'

            # 9. 审计日志
            log_audit({
                'timestamp': datetime.now().isoformat(),
                'user': _audit_user,
                'module': 'troubleshoot',
                'action': 'analyze',
                'target': query[:50] if query else '',
                'ip': _audit_ip,
                'project': project_name,
                'system_type': system_type,
                'apk_product': apk_product,
                'query': query,
                'matched_count': len(matched_cases),
                'api_time': round(api_time, 2),
                'removed_lines': len(filter_result.get('removed_lines', [])),
                'mode': 'stream',
            })

        except Exception as e:
            logger.exception("流式分析接口异常")
            yield f'data: {json.dumps({"type": "error", "message": f"分析异常：{str(e)}"}, ensure_ascii=False)}\n\n'

    return Response(
        generate(),
        mimetype='text/event-stream',
        headers={
            'Cache-Control': 'no-cache',
            'X-Accel-Buffering': 'no',  # 禁用 Nginx 缓冲
            'Connection': 'keep-alive',
        }
    )


@bp.route('/api/health', methods=['GET'])
def health_check():
    """
    健康检查接口。

    返回服务状态、版本信息、知识库统计等。
    用于监控系统、负载均衡器健康检查。
    """
    try:
        engine = container.get_search_engine()
        cache = container.get_cache_manager()
        cache_stats = cache.get_stats()
        search_mode_info = engine.get_search_mode()

        # 获取服务监测调度器状态（反映当前运行进程）
        scheduler_status = {"initialized": False}
        try:
            from service_monitor.services import schedule_service
            scheduler_status = schedule_service.get_scheduler_status()
        except Exception as e:
            scheduler_status = {"initialized": False, "error": str(e)}

        return jsonify({
            'status': 'ok',
            'timestamp': datetime.now().isoformat(),
            'version': '1.3.0',
            'offline_mode': is_offline_mode(),
            'knowledge_base': {
                'total_records': len(engine.records),
                'last_update': engine.index.get('last_update', 'unknown'),
            },
            'search': {
                'mode': search_mode_info['mode'],
                'vector_loaded': search_mode_info['vector_loaded'],
                'embedding_model': search_mode_info['embedding_model'],
            },
            'cache': {
                'total_files': cache_stats.get('total_files', 0),
                'total_size_mb': cache_stats.get('total_size_mb', 0),
            },
            'scheduler': scheduler_status,
            'components': {
                'search_engine': 'ok',
                'safety_filter': 'ok',
                'cache_manager': 'ok',
            }
        })
    except Exception as e:
        logger.exception("健康检查接口异常")
        return jsonify({
            'status': 'error',
            'timestamp': datetime.now().isoformat(),
            'error': str(e),
        }), 500


@bp.route('/api/projects', methods=['GET'])
def get_projects():
    """获取项目列表（用于下拉建议）。
    安全：普通用户返回空列表，仅管理员可获取完整项目名（防止项目信息泄露）。
    """
    user = session.get('user') or {}
    role = user.get('role', '')
    engine = container.get_search_engine()

    if role != 'admin':
        # 普通用户：返回空列表，前端 datalist 不展示
        return jsonify({'success': True, 'projects': []})

    return jsonify({
        'success': True,
        'projects': engine.get_projects(),
    })


@bp.route('/api/categories', methods=['GET'])
def get_categories():
    """获取分类列表"""
    engine = container.get_search_engine()
    return jsonify({
        'success': True,
        'categories': engine.get_categories(),
    })
