"""
Flask 服务器 - 智途投送电脑端
提供静态文件服务 + REST API（士兵位置、危险区域）
浏览器通过 roslibjs 直接连接 rosbridge_server，无需 Python 后端处理无人机逻辑
"""

import os
import sqlite3
import secrets
from functools import wraps
from datetime import datetime
from flask import Flask, send_from_directory, request, jsonify
from flask_cors import CORS
from werkzeug.security import generate_password_hash, check_password_hash

# 项目根目录（app.py 所在目录，部署时前端静态文件应放在同级目录）
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
DB_PATH = os.path.join(os.path.dirname(__file__), 'zhitu.db')

app = Flask(__name__, static_folder=BASE_DIR)
CORS(app)  # 允许跨域请求，支持单兵APP访问

# ---- SQLite 数据库 ----
def get_db():
    conn = sqlite3.connect(DB_PATH)
    conn.row_factory = sqlite3.Row
    return conn

def init_db():
    conn = get_db()
    conn.executescript('''
        CREATE TABLE IF NOT EXISTS accounts (
            soldier_id TEXT PRIMARY KEY,
            password_hash TEXT NOT NULL,
            name TEXT NOT NULL,
            unit TEXT,
            role TEXT,
            created_at TEXT
        );
        CREATE TABLE IF NOT EXISTS demands (
            id TEXT PRIMARY KEY,
            soldier_id TEXT,
            soldier_name TEXT,
            type TEXT,
            items TEXT,
            quantity INTEGER,
            unit TEXT,
            urgency TEXT,
            status TEXT DEFAULT '待处理',
            lat REAL,
            lng REAL,
            created_at TEXT
        );
        CREATE TABLE IF NOT EXISTS soldiers (
            soldier_id TEXT PRIMARY KEY,
            name TEXT,
            lat REAL,
            lng REAL,
            updated_at TEXT
        );
        CREATE TABLE IF NOT EXISTS sos_alerts (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            soldier_id TEXT,
            soldier_name TEXT,
            lat REAL,
            lng REAL,
            alert_time TEXT,
            handled INTEGER DEFAULT 0
        );
        CREATE TABLE IF NOT EXISTS danger_zones (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            lat REAL,
            lng REAL,
            radius REAL,
            description TEXT,
            created_at TEXT
        );
        CREATE TABLE IF NOT EXISTS tasks (
            id TEXT PRIMARY KEY,
            soldier_id TEXT,
            soldier_name TEXT,
            type TEXT,
            status TEXT,
            progress INTEGER DEFAULT 0,
            eta TEXT,
            remain_time TEXT,
            start_name TEXT,
            target_name TEXT,
            start_lat REAL,
            start_lng REAL,
            end_lat REAL,
            end_lng REAL,
            safety_score INTEGER,
            created_at TEXT
        );
        CREATE TABLE IF NOT EXISTS tokens (
            token TEXT PRIMARY KEY,
            soldier_id TEXT,
            name TEXT,
            unit TEXT,
            role TEXT,
            created_at TEXT
        );
    ''')
    conn.commit()
    conn.close()

def init_demo_accounts():
    """初始化演示账号到数据库，确保前后端账号统一"""
    conn = get_db()
    demo_accounts = [
        ("soldier_001", "123456", "张三", "第3步兵师/1连", "狙击手"),
        ("soldier_002", "123456", "李四", "第3步兵师/2连", "机枪手"),
        ("soldier_003", "123456", "王五", "第3步兵师/3连", "通讯员"),
    ]
    for sid, pwd, name, unit, role in demo_accounts:
        existing = conn.execute('SELECT 1 FROM accounts WHERE soldier_id=?', (sid,)).fetchone()
        if not existing:
            conn.execute('''
                INSERT INTO accounts (soldier_id, password_hash, name, unit, role, created_at)
                VALUES (?, ?, ?, ?, ?, ?)
            ''', (sid, generate_password_hash(pwd), name, unit, role,
                  datetime.now().strftime("%Y-%m-%d %H:%M:%S")))
    conn.commit()
    conn.close()

init_db()
init_demo_accounts()

# ---- 内存数据（演示数据：投放点、无人机状态重启后恢复默认值）----
_drop_points = [
    {"id": 1, "name": "安全点 #1", "safety_score": 92, "distance": 5, "reason": "深掩体保护，视角盲区", "lat": 30.0050, "lng": 120.0030},
    {"id": 2, "name": "安全点 #2", "safety_score": 85, "distance": 12, "reason": "钢筋混凝土建筑内部", "lat": 30.0055, "lng": 120.0035},
    {"id": 3, "name": "陷阱点 #3", "safety_score": 35, "distance": 20, "reason": "孤立断墙，成瞄准点", "lat": 30.0060, "lng": 120.0040}
]
_drone_status = {
    "drone_id": "无人机-01",
    "task_id": "#001",
    "status": "飞行中",
    "position": "A区街角12号",
    "battery": 85,
    "eta": "12:30",
    "speed": 8.5,
    "altitude": 15,
    "distance": 500,
    "temperature": 38,
    "lat": 30.0040,
    "lng": 120.0025
}
_drone_logs = [
    {"time": "12:25:30", "message": "到达投放点"},
    {"time": "12:20:45", "message": "接收任务指令"},
    {"time": "12:10:00", "message": "任务分配"}
]
# 计数器已从内存变量改为数据库查询，避免服务重启后主键冲突

def require_auth(f):
    """接口认证装饰器：验证 X-Auth-Token（从数据库查询，支持多 worker 共享）"""
    @wraps(f)
    def decorated(*args, **kwargs):
        token = request.headers.get('X-Auth-Token') or request.args.get('token')
        conn = get_db()
        row = conn.execute('SELECT soldier_id, name, unit, role FROM tokens WHERE token=?', (token,)).fetchone()
        conn.close()
        if not row:
            return jsonify({"ok": False, "error": "未登录或token无效"}), 401
        request.current_user = dict(row)
        return f(*args, **kwargs)
    return decorated


# ===== 静态文件路由 =====

@app.route("/")
def index():
    return send_from_directory(BASE_DIR, "index.html")


@app.route("/css/<path:filename>")
def css_files(filename):
    return send_from_directory(os.path.join(BASE_DIR, "css"), filename)


@app.route("/js/<path:filename>")
def js_files(filename):
    return send_from_directory(os.path.join(BASE_DIR, "js"), filename)


# ===== REST API: 士兵位置 =====

@app.route("/api/soldier/location", methods=["POST"])
@require_auth
def update_soldier_location():
    data = request.get_json(force=True)
    sid = data.get("id")
    if not sid:
        return jsonify({"ok": False, "error": "missing id"}), 400

    conn = get_db()
    conn.execute('''
        INSERT INTO soldiers (soldier_id, name, lat, lng, updated_at)
        VALUES (?, ?, ?, ?, ?)
        ON CONFLICT(soldier_id) DO UPDATE SET
            name=excluded.name, lat=excluded.lat, lng=excluded.lng, updated_at=excluded.updated_at
    ''', (sid, data.get("name", sid), float(data.get("lat", 0)), float(data.get("lng", 0)),
          datetime.now().strftime("%Y-%m-%d %H:%M:%S")))
    conn.commit()
    conn.close()
    return jsonify({"ok": True})


@app.route("/api/soldiers", methods=["GET"])
def get_soldiers():
    conn = get_db()
    rows = conn.execute('SELECT * FROM soldiers').fetchall()
    conn.close()
    return jsonify({"soldiers": [dict(r) for r in rows]})


# ===== REST API: 危险区域 =====

@app.route("/api/danger-zones", methods=["GET"])
def get_danger_zones():
    conn = get_db()
    rows = conn.execute('SELECT * FROM danger_zones').fetchall()
    conn.close()
    return jsonify({"danger_zones": [dict(r) for r in rows]})


@app.route("/api/danger-zones", methods=["POST"])
@require_auth
def add_danger_zone():
    data = request.get_json(force=True)
    zone = {
        "lat": float(data.get("lat", 0)),
        "lng": float(data.get("lng", 0)),
        "radius": float(data.get("radius", 50)),
        "description": data.get("description", "危险区域"),
        "created_at": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    }
    conn = get_db()
    cur = conn.execute('''
        INSERT INTO danger_zones (lat, lng, radius, description, created_at)
        VALUES (?, ?, ?, ?, ?)
    ''', (zone["lat"], zone["lng"], zone["radius"], zone["description"], zone["created_at"]))
    zone_id = cur.lastrowid
    conn.commit()
    conn.close()
    return jsonify({"ok": True, "id": zone_id})


# ===== REST API: 物资需求（单兵APP） =====

def _next_demand_id():
    """从数据库查询当前最大需求ID，生成下一个（避免内存计数器重启归零导致主键冲突）"""
    conn = get_db()
    row = conn.execute("SELECT id FROM demands WHERE id LIKE 'REQ-%' ORDER BY id DESC LIMIT 1").fetchone()
    conn.close()
    if row:
        try:
            num = int(row["id"].replace("REQ-", ""))
        except ValueError:
            num = 0
    else:
        num = 0
    return "REQ-" + str(num + 1).zfill(3)


@app.route("/api/demand", methods=["POST"])
@require_auth
def post_demand():
    data = request.get_json(force=True)

    drop_point = data.get("drop_point") or {}
    lat = float(drop_point.get("lat", 0)) if isinstance(drop_point, dict) else 0
    lng = float(drop_point.get("lng", 0)) if isinstance(drop_point, dict) else 0

    soldier_id = data.get("soldier_id", "unknown")
    if lat == 0 and lng == 0:
        conn = get_db()
        row = conn.execute('SELECT lat, lng FROM soldiers WHERE soldier_id=?', (soldier_id,)).fetchone()
        conn.close()
        if row:
            lat, lng = row["lat"], row["lng"]

    qty = int(data.get("quantity", 0))
    unit = data.get("unit", "个")
    item_type = data.get("type", "未知")
    items = f"{item_type} × {qty}{unit}"
    demand_id = _next_demand_id()

    demand = {
        "id": demand_id,
        "soldier_id": soldier_id,
        "soldier_name": data.get("soldier_name", "未知"),
        "type": item_type + "补给",
        "items": items,
        "quantity": qty,
        "unit": unit,
        "urgency": data.get("urgency", "一般"),
        "status": "待处理",
        "lat": lat,
        "lng": lng,
        "created_at": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    }
    conn = get_db()
    conn.execute('''
        INSERT INTO demands (id, soldier_id, soldier_name, type, items, quantity, unit, urgency, status, lat, lng, created_at)
        VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
    ''', (demand["id"], demand["soldier_id"], demand["soldier_name"], demand["type"],
          demand["items"], demand["quantity"], demand["unit"], demand["urgency"],
          demand["status"], demand["lat"], demand["lng"], demand["created_at"]))
    conn.commit()
    conn.close()
    return jsonify({"ok": True, "id": demand["id"]})


@app.route("/api/demands", methods=["GET"])
def get_demands():
    soldier_id = request.args.get("soldier_id")
    conn = get_db()
    if soldier_id:
        rows = conn.execute('SELECT * FROM demands WHERE soldier_id=?', (soldier_id,)).fetchall()
    else:
        rows = conn.execute("SELECT * FROM demands WHERE status='待处理'").fetchall()
    conn.close()
    return jsonify({"demands": [dict(r) for r in rows]})


@app.route("/api/demands/<demand_id>", methods=["GET"])
@require_auth
def get_demand(demand_id):
    conn = get_db()
    row = conn.execute('SELECT * FROM demands WHERE id=?', (demand_id,)).fetchone()
    conn.close()
    if row:
        return jsonify({"demand": dict(row)})
    return jsonify({"ok": False, "error": "not found"}), 404


# ===== REST API: 投放点 =====

@app.route("/api/drop-points", methods=["GET"])
def get_drop_points():
    return jsonify({"drop_points": _drop_points})


@app.route("/api/drop-point", methods=["POST"])
@require_auth
def post_drop_point():
    data = request.get_json(force=True)
    return jsonify({"ok": True})


# ===== REST API: 任务状态 =====

def _next_task_id():
    """从数据库查询当前最大任务ID，生成下一个"""
    conn = get_db()
    row = conn.execute("SELECT id FROM tasks WHERE id LIKE '#%' ORDER BY id DESC LIMIT 1").fetchone()
    conn.close()
    if row:
        try:
            num = int(row["id"].replace("#", ""))
        except ValueError:
            num = 0
    else:
        num = 0
    return "#" + str(num + 1).zfill(3)


@app.route("/api/task/dispatch", methods=["POST"])
@require_auth
def dispatch_task():
    data = request.get_json(force=True)
    soldier_id = data.get("soldier_id", "unknown")

    task = {
        "id": _next_task_id(),
        "soldier_id": soldier_id,
        "soldier_name": data.get("soldier_name", "未知"),
        "type": data.get("type", "未知"),
        "status": "执行中",
        "progress": 0,
        "eta": "计算中...",
        "remain_time": "计算中...",
        "start_name": data.get("start_name", "后方阵地"),
        "target_name": data.get("target_name", "目标位置"),
        "start_lat": float(data.get("start_lat", 30.0)),
        "start_lng": float(data.get("start_lng", 120.0)),
        "end_lat": float(data.get("end_lat", 30.0)),
        "end_lng": float(data.get("end_lng", 120.0)),
        "safety_score": data.get("safety_score", 90),
        "created_at": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    }
    conn = get_db()
    conn.execute('''
        INSERT INTO tasks (id, soldier_id, soldier_name, type, status, progress, eta, remain_time,
            start_name, target_name, start_lat, start_lng, end_lat, end_lng, safety_score, created_at)
        VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
    ''', (task["id"], task["soldier_id"], task["soldier_name"], task["type"], task["status"],
          task["progress"], task["eta"], task["remain_time"], task["start_name"], task["target_name"],
          task["start_lat"], task["start_lng"], task["end_lat"], task["end_lng"],
          task["safety_score"], task["created_at"]))
    conn.commit()
    conn.close()

    # 更新需求状态为"已调度"
    demand_id = data.get("demand_id")
    if demand_id:
        conn = get_db()
        conn.execute("UPDATE demands SET status='已调度' WHERE id=?", (demand_id,))
        conn.commit()
        conn.close()

    return jsonify({"ok": True, "task": task})


@app.route("/api/task/current", methods=["GET"])
@require_auth
def get_current_task():
    soldier_id = request.args.get("soldier_id", "soldier_001")
    conn = get_db()
    row = conn.execute('SELECT * FROM tasks WHERE soldier_id=?', (soldier_id,)).fetchone()
    conn.close()
    if row:
        return jsonify({"task": dict(row)})
    return jsonify({"task": {
        "id": "#--", "status": "无任务", "progress": 0, "eta": "--",
        "remain_time": "--", "start_name": "--", "target_name": "--", "safety_score": 0
    }})


@app.route("/api/task/update", methods=["POST"])
@require_auth
def update_task():
    data = request.get_json(force=True)
    soldier_id = data.get("soldier_id", "unknown")
    conn = get_db()
    row = conn.execute('SELECT * FROM tasks WHERE soldier_id=?', (soldier_id,)).fetchone()
    if not row:
        conn.close()
        return jsonify({"ok": False, "error": "无进行中的任务"}), 404

    updates = []
    params = []
    if "progress" in data:
        updates.append("progress=?")
        params.append(int(data["progress"]))
    if "status" in data:
        updates.append("status=?")
        params.append(data["status"])
    if "eta" in data:
        updates.append("eta=?")
        params.append(data["eta"])
    if "remain_time" in data:
        updates.append("remain_time=?")
        params.append(data["remain_time"])

    if updates:
        params.append(soldier_id)
        conn.execute(f"UPDATE tasks SET {','.join(updates)} WHERE soldier_id=?", params)
        conn.commit()
    conn.close()
    return jsonify({"ok": True})


# ===== REST API: 无人机状态 =====

@app.route("/api/drone/status", methods=["GET"])
def get_drone_status():
    return jsonify({"status": _drone_status})


@app.route("/api/drone/logs", methods=["GET"])
def get_drone_logs():
    return jsonify({"logs": _drone_logs})


# ===== REST API: SOS求救 =====

@app.route("/api/sos", methods=["POST"])
@require_auth
def post_sos():
    data = request.get_json(force=True)
    alert_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    conn = get_db()
    conn.execute('''
        INSERT INTO sos_alerts (soldier_id, soldier_name, lat, lng, alert_time, handled)
        VALUES (?, ?, ?, ?, ?, ?)
    ''', (data.get("soldier_id", "unknown"), data.get("soldier_name", "未知"),
          float(data.get("lat", 0)), float(data.get("lng", 0)), alert_time, 0))
    # 同时标记为危险区域
    conn.execute('''
        INSERT INTO danger_zones (lat, lng, radius, description, created_at)
        VALUES (?, ?, ?, ?, ?)
    ''', (float(data.get("lat", 0)), float(data.get("lng", 0)), 100,
          f"士兵求救: {data.get('soldier_name', '未知')}", alert_time))
    conn.commit()
    conn.close()
    return jsonify({"ok": True})


# ===== REST API: 账号系统（核心改造：持久化 + Token + 密码加密） =====

@app.route("/api/auth/register", methods=["POST"])
def auth_register():
    data = request.get_json(force=True)
    sid = data.get("soldier_id", "").strip()
    pwd = data.get("password", "").strip()
    name = data.get("name", "").strip()
    unit = data.get("unit", "未知单位").strip()
    role = data.get("role", "步兵").strip()

    if not sid or not pwd or not name:
        return jsonify({"ok": False, "error": "士兵编号、密码、姓名不能为空"}), 400

    conn = get_db()
    existing = conn.execute('SELECT 1 FROM accounts WHERE soldier_id=?', (sid,)).fetchone()
    if existing:
        conn.close()
        return jsonify({"ok": False, "error": "该士兵编号已注册"}), 409

    password_hash = generate_password_hash(pwd)
    conn.execute('''
        INSERT INTO accounts (soldier_id, password_hash, name, unit, role, created_at)
        VALUES (?, ?, ?, ?, ?, ?)
    ''', (sid, password_hash, name, unit, role, datetime.now().strftime("%Y-%m-%d %H:%M:%S")))
    conn.commit()
    conn.close()
    return jsonify({"ok": True, "message": "注册成功"})


@app.route("/api/auth/login", methods=["POST"])
def auth_login():
    data = request.get_json(force=True)
    sid = data.get("soldier_id", "").strip()
    pwd = data.get("password", "").strip()

    conn = get_db()
    row = conn.execute('SELECT * FROM accounts WHERE soldier_id=?', (sid,)).fetchone()

    if not row:
        conn.close()
        return jsonify({"ok": False, "error": "士兵编号不存在"}), 404

    if not check_password_hash(row["password_hash"], pwd):
        conn.close()
        return jsonify({"ok": False, "error": "密码错误"}), 401

    token = secrets.token_hex(16)
    conn.execute('''
        INSERT INTO tokens (token, soldier_id, name, unit, role, created_at)
        VALUES (?, ?, ?, ?, ?, ?)
    ''', (token, sid, row["name"], row["unit"], row["role"], datetime.now().strftime("%Y-%m-%d %H:%M:%S")))
    conn.commit()
    conn.close()

    return jsonify({
        "ok": True,
        "token": token,
        "soldier_id": sid,
        "name": row["name"],
        "unit": row["unit"],
        "role": row["role"]
    })


@app.route("/api/auth/accounts", methods=["GET"])
def get_accounts():
    conn = get_db()
    rows = conn.execute('SELECT soldier_id, name, unit, role FROM accounts').fetchall()
    conn.close()
    return jsonify({
        "accounts": [dict(r) for r in rows]
    })


@app.route("/api/auth/me", methods=["GET"])
def auth_me():
    token = request.headers.get('X-Auth-Token') or request.args.get('token')
    conn = get_db()
    row = conn.execute('SELECT soldier_id, name, unit, role FROM tokens WHERE token=?', (token,)).fetchone()
    conn.close()
    if not row:
        return jsonify({"ok": False, "error": "未登录"}), 401
    return jsonify({"ok": True, "user": dict(row)})


@app.route("/api/ping", methods=["GET"])
def ping():
    return jsonify({"ok": True, "message": "智途投送后端运行正常"})


if __name__ == "__main__":
    import sys
    import io
    sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
    print("=" * 50)
    print("  智途投送 - 物流保障系统")
    print("  http://localhost:5000")
    print("  实机 rosbridge: ws://192.168.1.14:9090")
    print("=" * 50)
    app.run(host="0.0.0.0", port=5000, debug=False)
