#!/usr/bin/env python3
"""
充电桩监控后端 API 服务

提供:
- GET /api/station/<group_id> - 获取充电站数据
- POST /api/subscribe - 订阅空闲提醒
- DELETE /api/subscribe - 取消订阅

数据存储: MySQL
"""

import os
import re
import logging
import time
import hashlib
import json
from datetime import datetime, timedelta
from pathlib import Path

from dotenv import load_dotenv
from flask import Flask, jsonify, request, g, make_response
from flask_cors import CORS

# 加载环境变量
env_path = Path(__file__).parent / ".env"
load_dotenv(env_path)

# ==================== 日志配置 ====================

logger = logging.getLogger('charger.api')
logger.setLevel(logging.INFO)

# 控制台输出
if not logger.handlers:
    handler = logging.StreamHandler()
    handler.setFormatter(logging.Formatter(
        '[%(asctime)s] [%(levelname)s] %(message)s',
        datefmt='%H:%M:%S'
    ))
    logger.addHandler(handler)


# ==================== 数据库延迟初始化 ====================

from db import Database, init_db, StateCacheDB, HistoryDB, SubscriptionDB

db_initialized = False

def ensure_db():
    """确保数据库已初始化"""
    global db_initialized
    if not db_initialized:
        try:
            init_db()
            db_initialized = True
        except Exception as e:
            logger.warning(f"数据库连接失败，使用降级模式: {e}")
    return db_initialized


app = Flask(__name__)

# CORS 配置：前后端同源时无需设置；不同端口/域名时通过环境变量配置
cors_origins = os.environ.get("CORS_ORIGINS", "")
if cors_origins:
    CORS(app, origins=cors_origins.split(","), supports_credentials=True)
elif os.environ.get("FLASK_ENV") == "production":
    logger.error("生产环境未设置 CORS_ORIGINS，拒绝启动")
    raise RuntimeError("生产环境必须设置 CORS_ORIGINS 环境变量")
else:
    # 本地开发默认允许 localhost
    CORS(app, origins=["http://localhost:*", "http://127.0.0.1:*"], supports_credentials=True)

# ==================== 配置 ====================

CONFIG = {
    # NIO Power API 配置
    "authorization": os.environ.get("NIO_AUTHORIZATION", ""),
    "device_id": os.environ.get("NIO_DEVICE_ID", ""),
    "station_id": os.environ.get("STATION_ID", ""),

    # 服务配置
    "port": int(os.environ.get("FLASK_PORT", 5001)),
    "debug": os.environ.get("FLASK_DEBUG", "1") == "1",
}

# NIO API 实例（可选）
nio_api = None


def init_nio_api():
    """初始化 NIO API 实例"""
    global nio_api
    if CONFIG["authorization"] and CONFIG["device_id"]:
        try:
            from nio_power_api import NIOPowerAPI
            nio_api = NIOPowerAPI(
                authorization=CONFIG["authorization"],
                device_id=CONFIG["device_id"]
            )
            logger.info("NIO API 初始化成功")
            return True
        except Exception as e:
            logger.error(f"NIO API 初始化失败: {e}")
    return False


# ==================== 请求日志中间件 ====================

@app.before_request
def before_request():
    """请求前记录"""
    g.start_time = time.time()
    g.request_id = f"{int(time.time() * 1000)}-{id(request)}"


@app.after_request
def after_request(response):
    """请求后记录日志"""
    if request.path.startswith('/api') or request.path == '/health':
        elapsed = (time.time() - g.start_time) * 1000
        status = response.status_code

        # 日志级别根据状态码
        log_level = logging.INFO if status < 400 else logging.WARNING

        logger.log(log_level, f"[{g.request_id}] {request.method} {request.path} {status} [{elapsed:.1f}ms]")

        # 添加请求 ID 到响应头
        response.headers['X-Request-ID'] = g.request_id

    return response


# ==================== 模拟数据 ====================

def get_mock_station_data() -> dict:
    """获取模拟的充电站数据"""
    now = time.time()

    return {
        "group_id": "STATION_PLACEHOLDER",
        "total_ac": 15,
        "free_ac": 3,
        "total_dc": 2,
        "free_dc": 1,
        "fetch_time": datetime.now().strftime("%H:%M:%S"),
        "fetch_timestamp": int(now),
        "connector_count": 17,
        "connectors": [
            # AC 桩 (1-15号)
            {"connector_id": "AC-01", "connector_name": "1号枪", "type": "AC", "power": 7, "state": {"type": "charging", "desc": "充电中"}, "idle_seconds": 0},
            {"connector_id": "AC-02", "connector_name": "2号桩", "type": "AC", "power": 7, "state": {"type": "free", "desc": "空闲"}, "idle_seconds": 300},
            {"connector_id": "AC-03", "connector_name": "3号桩", "type": "AC", "power": 7, "state": {"type": "charging", "desc": "充电中"}, "idle_seconds": 0},
            {"connector_id": "AC-04", "connector_name": "4号桩", "type": "AC", "power": 7, "state": {"type": "occupied", "desc": "占用"}, "idle_seconds": 0},
            {"connector_id": "AC-05", "connector_name": "5号桩", "type": "AC", "power": 7, "state": {"type": "charging", "desc": "充电中"}, "idle_seconds": 0},
            {"connector_id": "AC-06", "connector_name": "6号桩", "type": "AC", "power": 7, "state": {"type": "free", "desc": "空闲"}, "idle_seconds": 120},
            {"connector_id": "AC-07", "connector_name": "7号桩", "type": "AC", "power": 7, "state": {"type": "charging", "desc": "充电中"}, "idle_seconds": 0},
            {"connector_id": "AC-08", "connector_name": "8号桩", "type": "AC", "power": 7, "state": {"type": "charging", "desc": "充电中"}, "idle_seconds": 0},
            {"connector_id": "AC-09", "connector_name": "9号桩", "type": "AC", "power": 7, "state": {"type": "free", "desc": "空闲"}, "idle_seconds": 60},
            {"connector_id": "AC-10", "connector_name": "10号枪", "type": "AC", "power": 7, "state": {"type": "occupied", "desc": "占用"}, "idle_seconds": 0},
            {"connector_id": "AC-11", "connector_name": "11号桩", "type": "AC", "power": 7, "state": {"type": "charging", "desc": "充电中"}, "idle_seconds": 0},
            {"connector_id": "AC-12", "connector_name": "12号桩", "type": "AC", "power": 7, "state": {"type": "charging", "desc": "充电中"}, "idle_seconds": 0},
            {"connector_id": "AC-13", "connector_name": "13号桩", "type": "AC", "power": 7, "state": {"type": "charging", "desc": "充电中"}, "idle_seconds": 0},
            {"connector_id": "AC-14", "connector_name": "14号枪", "type": "AC", "power": 7, "state": {"type": "charging", "desc": "充电中"}, "idle_seconds": 0},
            {"connector_id": "AC-15", "connector_name": "15号枪", "type": "AC", "power": 7, "state": {"type": "charging", "desc": "充电中"}, "idle_seconds": 0},
            # DC 桩 (16-17号)
            {"connector_id": "DC-16", "connector_name": "16号枪", "type": "DC", "power": 20, "state": {"type": "charging", "desc": "充电中"}, "charging_progress": 65.0, "idle_seconds": 0},
            {"connector_id": "DC-17", "connector_name": "17号枪", "type": "DC", "power": 20, "state": {"type": "free", "desc": "空闲"}, "idle_seconds": 180},
        ]
    }


# ==================== API 路由 ====================

def row_to_connector(row: dict) -> dict:
    """把数据库行转换为前端统一 connector 结构。"""
    connector = {
        "connector_id": row["connector_id"],
        "connector_name": row["connector_name"],
        "type": row["connector_type"],
        "vendor": row.get("vendor") or "nio",
        "power": float(row["power"] or 0),
        "state": {
            "type": row["state_type"],
            "desc": row["state_desc"] or ""
        },
        "idle_seconds": row["idle_seconds"] or 0,
        "charging_seconds": row["charging_seconds"] or 0,
        "occupied_seconds": row.get("occupied_seconds") or 0,
    }

    # DC 充电桩特殊字段
    if row["connector_type"] == "DC":
        if row["remaining_minutes"] is not None:
            connector["estimated_charging_ready_time"] = row["remaining_minutes"]
        # 充电进度（从 state_desc 解析）
        if row["state_type"] == "charging" and row["state_desc"]:
            try:
                connector["charging_progress"] = float(row["state_desc"])
            except (ValueError, TypeError):
                pass

    return connector


def build_station_data(group_id: str) -> dict:
    """
    获取充电站数据。

    实时接口优先读取 charger_latest_status，小表缺失时兜底读历史表最新批次。
    """
    rows = HistoryDB.get_latest_snapshot(group_id)

    if rows:
        fetch_time = max(row["fetch_time"] for row in rows)
    else:
        # 兜底：旧库尚未写入最新快照时，从历史表获取最新一批数据
        latest_row = Database.execute(
            "SELECT MAX(fetch_time) as latest_time FROM charger_status_history WHERE station_id = %s",
            (group_id,),
            fetch_one=True
        )

        if not latest_row or not latest_row.get("latest_time"):
            return None

        fetch_time = latest_row["latest_time"]
        rows = Database.execute(
            """SELECT connector_id, connector_name, connector_type, vendor, power,
                      state_type, state_desc, idle_seconds, charging_seconds, occupied_seconds, remaining_minutes, fetch_time
               FROM charger_status_history
               WHERE station_id = %s AND fetch_time = %s
               ORDER BY
                 connector_type DESC,
                 CAST(connector_name AS UNSIGNED) DESC""",
            (group_id, fetch_time),
            fetch_all=True
        ) or []

    connectors = [row_to_connector(row) for row in rows]

    # 统计
    total_ac = sum(1 for c in connectors if c["type"] == "AC")
    total_dc = sum(1 for c in connectors if c["type"] == "DC")
    free_ac = sum(1 for c in connectors if c["type"] == "AC" and c["state"]["type"] == "free")
    free_dc = sum(1 for c in connectors if c["type"] == "DC" and c["state"]["type"] == "free")

    return {
        "group_id": group_id,
        "total_ac": total_ac,
        "free_ac": free_ac,
        "total_dc": total_dc,
        "free_dc": free_dc,
        "connector_count": len(connectors),
        "fetch_time": fetch_time.strftime("%H:%M:%S"),
        "fetch_datetime": fetch_time.strftime("%Y-%m-%d %H:%M:%S"),
        "fetch_timestamp": int(fetch_time.timestamp()),
        "connectors": connectors,
    }


def build_station_etag(data: dict) -> str:
    """构造站点数据 ETag。"""
    payload = json.dumps({
        "fetch_timestamp": data.get("fetch_timestamp"),
        "connector_count": data.get("connector_count"),
        "connectors": [
            {
                "id": c.get("connector_id"),
                "name": c.get("connector_name"),
                "state": c.get("state", {}).get("type"),
                "idle": c.get("idle_seconds", 0),
                "charging": c.get("charging_seconds", 0),
                "occupied": c.get("occupied_seconds", 0),
                "remaining": c.get("estimated_charging_ready_time"),
                "progress": c.get("charging_progress"),
            }
            for c in data.get("connectors", [])
        ],
    }, ensure_ascii=False, sort_keys=True, separators=(",", ":"))
    digest = hashlib.sha1(payload.encode("utf-8")).hexdigest()
    return f'"station-{digest}"'


def make_station_response(data: dict):
    """返回带 ETag 的站点响应；客户端数据未变化时返回 304。"""
    etag = build_station_etag(data)
    if request.headers.get("If-None-Match") == etag:
        response = make_response("", 304)
        response.headers["ETag"] = etag
        response.headers["Cache-Control"] = "private, max-age=0, must-revalidate"
        return response

    response = jsonify({"success": True, "data": data})
    response.headers["ETag"] = etag
    response.headers["Cache-Control"] = "private, max-age=0, must-revalidate"
    return response


def connector_matches_preferences(connector: dict, preferences: dict) -> bool:
    charger_type = preferences.get("charger_type", "all")
    vendor = preferences.get("vendor", "all")
    return (
        charger_type in ("all", connector.get("type"))
        and vendor in ("all", connector.get("vendor", "nio"))
    )


def summarize_connector(connector: dict) -> dict:
    return {
        "connector_id": connector.get("connector_id"),
        "connector_name": connector.get("connector_name"),
        "type": connector.get("type"),
        "vendor": connector.get("vendor", "nio"),
        "power": connector.get("power", 0),
        "state": connector.get("state", {}).get("type"),
    }


def build_recommendation(station: dict, preferences: dict = None) -> dict:
    """基于当前状态给透明的下楼建议。"""
    preferences = preferences or {}
    connectors = [
        c for c in station.get("connectors", [])
        if connector_matches_preferences(c, preferences)
    ]

    free_connectors = [
        c for c in connectors
        if c.get("state", {}).get("type") == "free"
    ]
    if free_connectors:
        free_connectors.sort(key=lambda c: (
            0 if c.get("type") == "DC" else 1,
            -(c.get("idle_seconds") or 0),
        ))
        best = free_connectors[0]
        return {
            "action": "go_now",
            "severity": "success",
            "wait_minutes": 0,
            "title": "现在可以下楼",
            "message": f"{best.get('connector_name')} 当前空闲，建议现在出发。",
            "best_connector": summarize_connector(best),
            "matched_free_count": len(free_connectors),
            "basis": "current_free",
        }

    ready_candidates = []
    for c in connectors:
        remaining = c.get("estimated_charging_ready_time")
        if c.get("type") == "DC" and c.get("state", {}).get("type") == "charging" and remaining is not None:
            try:
                ready_candidates.append((int(remaining), c))
            except (TypeError, ValueError):
                pass

    if ready_candidates:
        wait_minutes, best = sorted(ready_candidates, key=lambda item: item[0])[0]
        return {
            "action": "wait",
            "severity": "warning" if wait_minutes <= 15 else "neutral",
            "wait_minutes": wait_minutes,
            "title": f"约 {wait_minutes} 分钟后再看",
            "message": f"{best.get('connector_name')} 预计约 {wait_minutes} 分钟后可用，可以先别下楼。",
            "best_connector": summarize_connector(best),
            "matched_free_count": 0,
            "basis": "dc_remaining_time",
        }

    return {
        "action": "subscribe",
        "severity": "neutral",
        "wait_minutes": None,
        "title": "暂时不建议下楼",
        "message": "当前偏好范围内没有明确空位，建议订阅提醒，等系统叫你。",
        "best_connector": None,
        "matched_free_count": 0,
        "basis": "no_current_signal",
    }


@app.route("/api/station/<group_id>")
def get_station(group_id):
    """
    获取充电站数据（从数据库读取）

    数据由后台定时任务采集并存储，前端请求不会触发 NIO API 调用
    """
    try:
        if not ensure_db():
            return jsonify({"success": False, "message": "数据库未连接"}), 503

        data = build_station_data(group_id)
        if not data:
            return jsonify({
                "success": False,
                "message": "暂无数据，请确保后台采集任务已启动",
                "hint": "运行 python scheduler.py start 启动采集任务"
            })

        return make_station_response(data)

    except Exception as e:
        logger.error(f"获取充电站数据失败: {e}", exc_info=True)
        return jsonify({"success": False, "message": "服务器内部错误"}), 500


@app.route("/api/recommendation/<group_id>")
def get_recommendation(group_id):
    """获取下楼建议。"""
    try:
        if not ensure_db():
            return jsonify({"success": False, "message": "数据库未连接"}), 503

        station = build_station_data(group_id)
        if not station:
            return jsonify({"success": False, "message": "暂无数据"}), 404

        preferences = {
            "charger_type": request.args.get("charger_type", "all"),
            "vendor": request.args.get("vendor", "all"),
        }
        if preferences["charger_type"] not in ("AC", "DC", "all"):
            return jsonify({"success": False, "message": "充电桩类型无效"}), 400
        if preferences["vendor"] not in ("all", "nio", "gongniu"):
            return jsonify({"success": False, "message": "厂商类型无效"}), 400

        return jsonify({
            "success": True,
            "data": build_recommendation(station, preferences),
            "query": preferences,
        })
    except Exception as e:
        logger.error(f"获取推荐失败: {e}", exc_info=True)
        return jsonify({"success": False, "message": "服务器内部错误"}), 500


@app.route("/api/subscribe", methods=["POST"])
def subscribe():
    """订阅空闲提醒"""
    try:
        data = request.get_json() or {}
        email = data.get("email", "").strip().lower()
        feishu_name = data.get("feishu_name", "").strip()  # 飞书花名
        charger_type = data.get("charger_type", "all")  # AC/DC/all
        vendor = data.get("vendor", "all")  # all/nio/gongniu

        # 更严格的邮箱验证
        if not re.match(r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$", email):
            return jsonify({"success": False, "message": "邮箱格式无效"}), 400

        # 验证飞书花名（必填）
        if not feishu_name:
            return jsonify({"success": False, "message": "请填写飞书花名"}), 400

        # 验证充电桩类型
        if charger_type not in ("AC", "DC", "all"):
            return jsonify({"success": False, "message": "充电桩类型无效"}), 400

        # 验证厂商类型
        if vendor not in ("all", "nio", "gongniu"):
            return jsonify({"success": False, "message": "厂商类型无效"}), 400

        if not ensure_db():
            logger.error("数据库连接失败，无法处理订阅请求")
            return jsonify({"success": False, "message": "服务暂时不可用，请稍后重试"}), 503

        # VIP 优先级配置（从数据库系统配置读取，非硬编码邮箱）
        is_priority = SubscriptionDB.get_is_priority(email)

        # 添加订阅
        result = SubscriptionDB.add(email, feishu_name, charger_type, is_priority, vendor=vendor)

        if not result["success"]:
            return jsonify({"success": False, "message": result["message"]}), 400

        type_text = {"AC": "AC 慢充", "DC": "DC 快充", "all": "任意类型"}.get(charger_type, charger_type)
        vendor_text = {"all": "全部", "nio": "蔚来", "gongniu": "公牛"}.get(vendor, vendor)

        return jsonify({
            "success": True,
            "message": result["message"],
            "data": {
                "email": email,
                "feishu_name": feishu_name,
                "charger_type": charger_type,
                "charger_type_text": type_text,
                "vendor": vendor,
                "vendor_text": vendor_text,
                "queue_position": result["queue_position"],
                "expires": "本周有效"
            }
        })
    except Exception as e:
        logger.error(f"订阅处理失败: {e}", exc_info=True)
        return jsonify({"success": False, "message": "服务器内部错误"}), 500


@app.route("/api/subscribe", methods=["DELETE"])
def unsubscribe():
    """取消订阅"""
    data = request.get_json() or {}
    email = data.get("email", "").strip().lower()
    SubscriptionDB.remove(email)
    return jsonify({"success": True, "message": "已取消订阅"})


@app.route("/api/subscriptions")
def list_subscriptions():
    """查看所有订阅"""
    subscriptions = SubscriptionDB.get_all()
    return jsonify({"success": True, "data": subscriptions, "count": len(subscriptions)})


@app.route("/api/queue/status")
def get_queue_status():
    """获取排队状态"""
    try:
        if not ensure_db():
            logger.error("数据库连接失败，无法获取排队状态")
            return jsonify({"success": False, "message": "服务暂时不可用"}), 503

        queue_count = SubscriptionDB.get_queue_count()
        return jsonify({
            "success": True,
            "data": {
                "queue_count": queue_count,
                "message": f"当前排队人数：{queue_count} 人" if queue_count > 0 else "当前无人排队，订阅后立即生效"
            }
        })
    except Exception as e:
        logger.error(f"获取排队状态失败: {e}", exc_info=True)
        return jsonify({"success": False, "message": "服务器内部错误"}), 500


# ==================== 充电桩留言 API ====================

@app.route("/api/comment", methods=["POST"])
def add_comment():
    """添加留言"""
    try:
        data = request.get_json() or {}
        connector_id = data.get("connector_id", "").strip()
        connector_name = data.get("connector_name", "").strip()
        feishu_name = data.get("feishu_name", "").strip()
        content = data.get("content", "").strip()

        # 参数验证
        if not connector_id:
            return jsonify({"success": False, "message": "缺少充电桩ID"}), 400
        if not feishu_name:
            return jsonify({"success": False, "message": "请填写飞书花名"}), 400
        if not content:
            return jsonify({"success": False, "message": "留言内容不能为空"}), 400

        if not ensure_db():
            return jsonify({"success": False, "message": "服务暂时不可用"}), 503

        from db import CommentDB
        result = CommentDB.add(connector_id, connector_name, feishu_name, content)

        if result["success"]:
            return jsonify({"success": True, "message": result["message"]})
        else:
            return jsonify({"success": False, "message": result["message"]}), 400

    except Exception as e:
        logger.error(f"添加留言失败: {e}", exc_info=True)
        return jsonify({"success": False, "message": "服务器内部错误"}), 500


@app.route("/api/comments/<connector_id>")
def get_comments(connector_id):
    """获取某充电桩的留言列表"""
    try:
        if not ensure_db():
            return jsonify({"success": False, "message": "服务暂时不可用"}), 503

        from db import CommentDB
        comments = CommentDB.get_by_connector(connector_id)

        return jsonify({
            "success": True,
            "data": comments,
            "count": len(comments)
        })

    except Exception as e:
        logger.error(f"获取留言失败: {e}", exc_info=True)
        return jsonify({"success": False, "message": "服务器内部错误"}), 500


@app.route("/api/comments/batch", methods=["POST"])
def get_comments_batch():
    """批量获取多个充电桩的留言数量"""
    try:
        data = request.get_json() or {}
        connector_ids = data.get("connector_ids", [])

        if len(connector_ids) > 50:
            return jsonify({"success": False, "message": "请求的数据量过大，最多支持 50 个"}), 400

        if not connector_ids:
            return jsonify({"success": True, "data": {}, "count": 0})

        if not ensure_db():
            return jsonify({"success": False, "message": "服务暂时不可用"}), 503

        from db import CommentDB
        counts = CommentDB.get_counts(connector_ids)
        latest = CommentDB.get_latest_comments(connector_ids)

        # 合并为 {connector_id: {count, latest}} 结构
        data = {}
        for cid in connector_ids:
            data[cid] = {
                'count': counts.get(cid, 0),
                'latest': latest.get(cid)
            }

        return jsonify({
            "success": True,
            "data": data,
            "count": sum(counts.values())
        })

    except Exception as e:
        logger.error(f"批量获取留言数量失败: {e}", exc_info=True)
        return jsonify({"success": False, "message": "服务器内部错误"}), 500


# ==================== 访问统计 ====================

import re

@app.route("/api/visit", methods=["POST"])
def record_visit():
    """记录访问并返回今日统计"""
    try:
        data = request.get_json() or {}
        device_hash = data.get("device_hash", "")

        if not re.match(r'^[a-f0-9]{16}$', device_hash):
            return jsonify({"success": False, "message": "device_hash 格式错误"}), 400

        if not ensure_db():
            return jsonify({"success": False, "message": "服务暂时不可用"}), 503

        from db import VisitDB
        VisitDB.record(device_hash)
        stats = VisitDB.get_today_stats()

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

    except Exception as e:
        logger.error(f"记录访问失败: {e}", exc_info=True)
        return jsonify({"success": False, "message": "服务器内部错误"}), 500


@app.route("/api/visit/today")
def get_visit_today():
    """获取今日访问统计"""
    try:
        if not ensure_db():
            return jsonify({"success": False, "message": "服务暂时不可用"}), 503

        from db import VisitDB
        stats = VisitDB.get_today_stats()

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

    except Exception as e:
        logger.error(f"获取访问统计失败: {e}", exc_info=True)
        return jsonify({"success": False, "message": "服务器内部错误"}), 500


@app.route("/api/visit/history")
def get_visit_history():
    """获取近 N 天访问统计（PV/UV）"""
    try:
        try:
            days = int(request.args.get("days", 7))
            days = min(max(days, 1), 90)
        except ValueError:
            return jsonify({"success": False, "message": "参数格式错误"}), 400

        if not ensure_db():
            return jsonify({"success": False, "message": "服务暂时不可用"}), 503

        from db import VisitDB
        history = VisitDB.get_visit_history(days)

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

    except Exception as e:
        logger.error(f"获取访问历史失败: {e}", exc_info=True)
        return jsonify({"success": False, "message": "服务器内部错误"}), 500


@app.route("/api/history/<group_id>")
def get_history(group_id):
    """获取历史数据"""
    connector_id = request.args.get("connector_id")

    # 参数验证（异常处理 + 范围限制）
    try:
        days = int(request.args.get("days", 7))
        days = min(max(days, 1), 365)  # 限制 1-365 天
        limit = int(request.args.get("limit", 1000))
        limit = min(max(limit, 1), 10000)  # 限制 1-10000
    except ValueError:
        return jsonify({"success": False, "message": "参数格式错误，days 和 limit 必须为整数"}), 400

    if not ensure_db():
        return jsonify({"success": False, "message": "服务暂时不可用"}), 503

    start_time = datetime.now() - timedelta(days=days)

    history = HistoryDB.get_history(
        station_id=group_id,
        connector_id=connector_id,
        start_time=start_time,
        limit=limit
    )

    return jsonify({
        "success": True,
        "data": history,
        "count": len(history),
        "query": {
            "station_id": group_id,
            "connector_id": connector_id,
            "days": days
        }
    })


@app.route("/api/statistics/<group_id>")
def get_statistics(group_id):
    """获取统计数据"""
    # 参数验证
    try:
        days = int(request.args.get("days", 7))
        days = min(max(days, 1), 365)  # 限制 1-365 天
    except ValueError:
        return jsonify({"success": False, "message": "参数格式错误，days 必须为整数"}), 400

    if not ensure_db():
        return jsonify({"success": False, "message": "服务暂时不可用"}), 503

    stats = HistoryDB.get_statistics(station_id=group_id, days=days)

    return jsonify({
        "success": True,
        "data": stats,
        "query": {
            "station_id": group_id,
            "days": days
        }
    })


@app.route("/health")
def health():
    """健康检查"""
    db_status = "ok"
    try:
        # 检查数据库连接
        with Database.get_connection() as conn:
            with conn.cursor() as cursor:
                cursor.execute("SELECT 1")
    except Exception as e:
        db_status = "degraded"
        logger.warning(f"健康检查数据库连接失败: {e}")

    return jsonify({
        "status": "ok" if db_status == "ok" else "degraded",
        "timestamp": datetime.now().isoformat(),
        "database": db_status,
        "nio_api": "connected" if nio_api else "mock_mode"
    })


# ==================== 数据分析 API ====================

@app.route("/api/analytics/<group_id>/summary")
def get_analytics_summary(group_id):
    """获取汇总统计数据"""
    days = request.args.get("days", 7, type=int)
    try:
        if ensure_db():
            summary = HistoryDB.get_summary(group_id, days)
            if summary.get("total_sessions", 0) > 0:
                return jsonify({"success": True, "data": summary})

        # Mock 数据
        return jsonify({"success": True, "data": {
            "total_sessions": 342,
            "avg_charging_minutes": 45.6,
            "utilization_rate": 62.3,
            "peak_hour": 14,
            "ac_utilization": 58.7,
            "dc_utilization": 71.2,
        }})
    except Exception as e:
        logger.error(f"获取汇总统计失败: {e}", exc_info=True)
        return jsonify({"success": False, "message": "服务器内部错误"}), 500


@app.route("/api/analytics/<group_id>/hourly")
def get_analytics_hourly(group_id):
    """获取每小时使用率矩阵"""
    days_param = request.args.get("days", 7, type=int)
    try:
        if ensure_db():
            hourly = HistoryDB.get_hourly(group_id, days_param)
            if hourly and len(hourly) > 0:
                return jsonify({"success": True, "data": hourly})

        # Mock 数据：数据库无数据时返回模拟数据
        import random
        random.seed(42)
        days_list = ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
        hourly = []
        multiplier = days_param / 7
        for day in days_list:
            for hour in range(24):
                # 工作日高峰 8-18 点使用率高
                if day in ['周一', '周二', '周三', '周四', '周五']:
                    if 8 <= hour <= 18:
                        util = random.randint(40, 90)
                    elif 6 <= hour <= 20:
                        util = random.randint(15, 45)
                    else:
                        util = random.randint(0, 15)
                else:
                    if 10 <= hour <= 16:
                        util = random.randint(20, 50)
                    else:
                        util = random.randint(0, 20)
                # 根据天数调整使用率
                util = min(100, int(util * multiplier))
                hourly.append({"day": day, "hour": hour, "utilization": util})
        return jsonify({"success": True, "data": hourly})
    except Exception as e:
        logger.error(f"获取小时统计失败: {e}", exc_info=True)
        return jsonify({"success": False, "message": "服务器内部错误"}), 500


@app.route("/api/analytics/<group_id>/trend")
def get_analytics_trend(group_id):
    """获取工作日 9:00-10:00 抢桩时刻趋势"""
    days_param = request.args.get("days", 7, type=int)
    try:
        if ensure_db():
            trend = HistoryDB.get_grab_times(group_id, days_param)
            if trend and len(trend) > 0:
                return jsonify({"success": True, "data": trend})

        # Mock 数据：工作日 9:00-10:00 满载时刻
        import random
        random.seed(42)
        day_names = ['周一', '周二', '周三', '周四', '周五']
        trend = []
        for i, day in enumerate(day_names):
            # 随机生成 9:00-9:59 的满载时刻
            minute = random.randint(5, 55)
            trend.append({
                "day": day,
                "minute": minute,
                "time": f"9:{minute:02d}",
                "full": True
            })
        return jsonify({"success": True, "data": trend})
    except Exception as e:
        logger.error(f"获取趋势数据失败: {e}", exc_info=True)
        return jsonify({"success": False, "message": "服务器内部错误"}), 500


@app.route("/api/analytics/<group_id>/rank")
def get_analytics_rank(group_id):
    """获取各充电桩使用率排名"""
    days_param = request.args.get("days", 7, type=int)
    try:
        if ensure_db():
            rank = HistoryDB.get_connector_rank(group_id, days_param)
            if rank and len(rank) > 0:
                return jsonify({"success": True, "data": rank})

        # Mock 数据：数据库无数据时返回模拟数据
        import random
        random.seed(42)
        multiplier = days_param / 7
        connectors = []
        # DC 桩
        for i in [16, 17]:
            connectors.append({
                "connector_id": f"DC-{i}",
                "connector_name": f"{i}号枪",
                "connector_type": "DC",
                "utilization": min(100, round(random.uniform(55, 85) * multiplier, 1)),
            })
        # AC 桩
        for i in range(1, 16):
            connectors.append({
                "connector_id": f"AC-{i:02d}",
                "connector_name": f"{i}号{'枪' if i in [1, 6, 9, 10, 14, 15] else '桩'}",
                "connector_type": "AC",
                "utilization": min(100, round(random.uniform(25, 75) * multiplier, 1)),
            })
        connectors.sort(key=lambda x: x["utilization"], reverse=True)
        return jsonify({"success": True, "data": connectors})
    except Exception as e:
        logger.error(f"获取排名数据失败: {e}", exc_info=True)
        return jsonify({"success": False, "message": "服务器内部错误"}), 500


@app.route("/api/analytics/<group_id>/overview")
def get_analytics_overview(group_id):
    """获取数据概览"""
    days_param = request.args.get("days", 7, type=int)
    try:
        if ensure_db():
            overview = HistoryDB.get_overview(group_id, days_param)
            return jsonify({"success": True, "data": overview})

        # Mock 数据：根据天数调整
        import random
        random.seed(42)
        multiplier = days_param / 7
        return jsonify({
            "success": True,
            "data": {
                "subscription_count": int(12 * multiplier),
                "ac_avg_charging_minutes": round(180 + random.random() * 60, 1),
                "dc_avg_charging_minutes": round(45 + random.random() * 30, 1),
                "grab_hour": "09:15",
                "charging_sessions": int(156 * multiplier),
                "estimated_kwh": round(2847.5 * multiplier, 2),
                "ac_kwh": round(1847.5 * multiplier, 1),
                "dc_kwh": round(1000.0 * multiplier, 1),
            }
        })
    except Exception as e:
        logger.error(f"获取数据概览失败: {e}", exc_info=True)
        return jsonify({"success": False, "message": "服务器内部错误"}), 500


@app.route("/")
def index():
    """API 信息"""
    return jsonify({
        "name": "充电桩监控 API",
        "version": "1.3.0",
        "endpoints": {
            "station": "GET /api/station/<group_id>",
            "subscribe": "POST /api/subscribe",
            "unsubscribe": "DELETE /api/subscribe",
            "history": "GET /api/history/<group_id>?connector_id=&days=7",
            "statistics": "GET /api/statistics/<group_id>?days=7",
            "analytics_summary": "GET /api/analytics/<group_id>/summary?days=7",
            "analytics_hourly": "GET /api/analytics/<group_id>/hourly?days=7",
            "analytics_trend": "GET /api/analytics/<group_id>/trend?days=7",
            "analytics_rank": "GET /api/analytics/<group_id>/rank?days=7",
            "analytics_overview": "GET /api/analytics/<group_id>/overview?days=7",
            "health": "GET /health"
        }
    })


# ==================== 启动 ====================

if __name__ == "__main__":
    print("=" * 50)
    print("充电桩监控 API 服务")
    print("=" * 50)

    # 初始化 NIO API（可选）
    init_nio_api()

    print(f"\nAPI 端点:")
    print(f"  GET  /api/station/<group_id>  获取充电站数据（从数据库读取）")
    print(f"  GET  /api/history/<group_id>  获取历史数据")
    print(f"  GET  /api/statistics/<group_id>  获取统计数据")
    print(f"  POST /api/subscribe           订阅空闲提醒")
    print(f"  DELETE /api/subscribe         取消订阅")
    print(f"  GET  /health                  健康检查")
    print("=" * 50)
    print(f"\n注意: 数据由后台采集任务提供，请确保运行:")
    print(f"  python scheduler.py start")
    print("=" * 50)

    app.run(host="0.0.0.0", port=CONFIG["port"], debug=CONFIG["debug"])
