# -*- coding: utf-8 -*-
"""
routes.py — 服务监测路由层

页面路由：/service-monitor/*
API 路由：/api/service-monitor/*

权限：
  - 页面/查看类：登录即可（普通用户仅查看）
  - 操作类（目标增删改、触发巡检、取消）：仅管理员

SSE：/api/service-monitor/run/stream 流式推送巡检进度
"""

from __future__ import annotations

import json
import logging

from flask import (
    Blueprint, render_template, session, request, jsonify,
    Response, redirect, url_for, stream_with_context,
)

from .services import target_service, report_service, runner_service

logger = logging.getLogger("service_monitor.routes")

bp = Blueprint('service-monitor', __name__)


# ============================================================
# 内部辅助：权限
# ============================================================

def _current_user():
    return session.get('user', {})


def _role():
    return _current_user().get('role', '')


def _require_login_json():
    if 'user' not in session:
        return jsonify({"success": False, "error": {"code": 401, "message": "未登录"}}), 401
    return None


def _require_admin_json():
    if 'user' not in session:
        return jsonify({"success": False, "error": {"code": 401, "message": "未登录"}}), 401
    if _role() != 'admin':
        return jsonify({"success": False, "error": {"code": 403, "message": "权限不足，仅管理员可操作"}}), 403
    return None


# ============================================================
# 页面路由
# ============================================================

@bp.route('/service-monitor')
def page_index():
    """监测主页：目标概览 + 最近报告。"""
    if 'user' not in session:
        return redirect(url_for('auth.login'))
    user = _current_user()
    targets = target_service.list_targets(role=user.get('role', ''))
    reports = report_service.list_reports(limit=20)
    return render_template(
        'service_monitor/index.html',
        user=user, targets=targets, reports=reports,
        is_admin=(user.get('role') == 'admin'),
    )


@bp.route('/service-monitor/targets')
def page_targets():
    """目标管理页（仅管理员可进入，普通用户重定向回主页）。"""
    if 'user' not in session:
        return redirect(url_for('auth.login'))
    user = _current_user()
    if user.get('role') != 'admin':
        return redirect(url_for('service-monitor.page_index'))
    targets = target_service.list_targets(role='admin')
    return render_template('service_monitor/targets.html', user=user, targets=targets)


@bp.route('/service-monitor/run/<target_id>')
def page_run(target_id):
    """巡检执行页（仅管理员）。"""
    if 'user' not in session:
        return redirect(url_for('auth.login'))
    user = _current_user()
    if user.get('role') != 'admin':
        return redirect(url_for('service-monitor.page_index'))
    target = target_service.get_target_view(target_id, role='admin')
    if not target:
        return redirect(url_for('service-monitor.page_index'))
    suite = request.args.get('suite', 'quick')
    return render_template('service_monitor/run.html',
                           user=user, target=target, suite=suite)


@bp.route('/service-monitor/report/<report_id>')
def page_report(report_id):
    """报告详情页（所有登录用户可看）。"""
    if 'user' not in session:
        return redirect(url_for('auth.login'))
    user = _current_user()
    report = report_service.get_report(report_id)
    if not report:
        return redirect(url_for('service-monitor.page_index'))
    return render_template('service_monitor/report.html', user=user, report=report)


# ============================================================
# API：目标管理（管理员）
# ============================================================

@bp.route('/api/service-monitor/targets', methods=['GET'])
def api_list_targets():
    guard = _require_login_json()
    if guard:
        return guard
    targets = target_service.list_targets(role=_role())
    return jsonify({"success": True, "targets": targets})


@bp.route('/api/service-monitor/targets', methods=['POST'])
def api_create_target():
    guard = _require_admin_json()
    if guard:
        return guard
    try:
        target = target_service.create_target(request.get_json(force=True) or {})
        return jsonify({"success": True, "target": target})
    except ValueError as e:
        return jsonify({"success": False, "error": {"code": 400, "message": str(e)}}), 400


@bp.route('/api/service-monitor/targets/<target_id>', methods=['PUT'])
def api_update_target(target_id):
    guard = _require_admin_json()
    if guard:
        return guard
    try:
        target = target_service.update_target(target_id, request.get_json(force=True) or {})
        return jsonify({"success": True, "target": target})
    except ValueError as e:
        return jsonify({"success": False, "error": {"code": 400, "message": str(e)}}), 400


@bp.route('/api/service-monitor/targets/<target_id>', methods=['DELETE'])
def api_delete_target(target_id):
    guard = _require_admin_json()
    if guard:
        return guard
    try:
        ok = target_service.delete_target(target_id)
        if not ok:
            return jsonify({"success": False, "error": {"code": 404, "message": "目标不存在"}}), 404
        return jsonify({"success": True})
    except ValueError as e:
        return jsonify({"success": False, "error": {"code": 400, "message": str(e)}}), 400


@bp.route('/api/service-monitor/targets/test', methods=['POST'])
def api_test_connection():
    """测试 SSH 连接（管理员）。

    Returns: {
        "success": bool,
        "message": str,
        "detail": str | None,
        "error_code": str | None
    }
    """
    guard = _require_admin_json()
    if guard:
        return guard
    result = target_service.test_connection(request.get_json(force=True) or {})
    return jsonify(result)


# ============================================================
# API：巡检（管理员）
# ============================================================

@bp.route('/api/service-monitor/run/stream', methods=['GET'])
def api_run_stream():
    """SSE 流式巡检。参数：target_id, suite（quick/full）。"""
    guard = _require_admin_json()
    if guard:
        return guard

    target_id = request.args.get('target_id', '')
    suite = request.args.get('suite', 'quick')

    @stream_with_context
    def generate():
        try:
            for evt in runner_service.run_inspection(target_id, suite):
                yield f"data: {json.dumps(evt, ensure_ascii=False)}\n\n"
        except Exception as e:
            logger.error("SSE 流异常: %s", e)
            err = {"event": "error", "message": f"服务端异常: {e}"}
            yield f"data: {json.dumps(err, ensure_ascii=False)}\n\n"

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


@bp.route('/api/service-monitor/run/<run_id>/cancel', methods=['POST'])
def api_cancel_run(run_id):
    guard = _require_admin_json()
    if guard:
        return guard
    ok = runner_service.cancel_run(run_id)
    return jsonify({"success": ok})


# ============================================================
# API：报告（登录即可查看）
# ============================================================

@bp.route('/api/service-monitor/reports', methods=['GET'])
def api_list_reports():
    guard = _require_login_json()
    if guard:
        return guard
    target_id = request.args.get('target_id')
    reports = report_service.list_reports(target_id=target_id, limit=50)
    return jsonify({"success": True, "reports": reports})


@bp.route('/api/service-monitor/reports/<report_id>', methods=['GET'])
def api_get_report(report_id):
    guard = _require_login_json()
    if guard:
        return guard
    report = report_service.get_report(report_id)
    if not report:
        return jsonify({"success": False, "error": {"code": 404, "message": "报告不存在"}}), 404
    return jsonify({"success": True, "report": report})


@bp.route('/api/service-monitor/reports/<report_id>', methods=['DELETE'])
def api_delete_report(report_id):
    guard = _require_admin_json()
    if guard:
        return guard
    ok = report_service.delete_report(report_id)
    return jsonify({"success": ok})


@bp.route('/api/service-monitor/reports/<report_id>/export', methods=['GET'])
def api_export_report(report_id):
    guard = _require_login_json()
    if guard:
        return guard
    fmt = request.args.get('format', 'md')
    if fmt == 'json':
        data = report_service.export_json(report_id)
        if not data:
            return jsonify({"success": False, "error": {"code": 404, "message": "报告不存在"}}), 404
        resp = Response(json.dumps(data, ensure_ascii=False, indent=2),
                        mimetype='application/json')
        resp.headers['Content-Disposition'] = f'attachment; filename=report_{report_id}.json'
        return resp
    else:
        md = report_service.export_markdown(report_id)
        if md is None:
            return jsonify({"success": False, "error": {"code": 404, "message": "报告不存在"}}), 404
        resp = Response(md, mimetype='text/markdown')
        resp.headers['Content-Disposition'] = f'attachment; filename=report_{report_id}.md'
        return resp


# ============================================================
# 修复预留（本期不实现）
# ============================================================

@bp.route('/api/service-monitor/fix', methods=['POST'])
def api_fix():
    """修复能力预留位——本期返回开发中提示。"""
    guard = _require_admin_json()
    if guard:
        return guard
    return jsonify({"success": False, "message": "修复能力开发中，敬请期待"})
