import os
import sys
import json
import mimetypes
from datetime import datetime
from flask import Flask, send_from_directory, jsonify
from flask_cors import CORS

# 引入配置
from config import Config
# 引入扩展
from extensions import db, jwt, scheduler
# 引入模型 (确保 create_all 能扫描到)
from models import Device, DeviceHistory, User

# 引入 API 蓝图和工具
try:
    from routes.api import api_bp, calculate_offset
except ImportError:
    api_bp = None
    calculate_offset = None

# 引入爬虫服务
try:
    from services.core import execute_monitor_task
except ImportError:
    execute_monitor_task = None

# 注册 MIME 类型 (防止前端 JS/CSS 加载报 404 或类型错误)
mimetypes.add_type('application/javascript', '.js')
mimetypes.add_type('text/css', '.css')


# --- 定时任务逻辑 (保持不变) ---
def auto_monitor_job(app):
    with app.app_context():
        print(f"⏰ [定时任务] 启动: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")

        if not execute_monitor_task:
            print("❌ 错误: 爬虫模块未加载")
            return

        try:
            task_result = execute_monitor_task()
            if not task_result:
                print("⚠️ 未抓取到数据")
                return

            scraped_list = task_result.get('device_list', [])
            current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
            count = 0

            for item in scraped_list:
                d_name = item.get('name')
                if not d_name: continue

                # 查找或创建设备
                device = Device.query.filter_by(name=d_name).first()
                if not device:
                    device = Device(name=d_name, source=item.get('source'), install_site="")
                    db.session.add(device)
                    db.session.flush()

                # 更新状态
                device.status = item.get('status')
                device.current_value = item.get('value')
                device.latest_time = item.get('target_time')
                device.check_time = current_time
                device.json_data = json.dumps(item.get('raw_json', {}), ensure_ascii=False)

                if calculate_offset:
                    device.offset = calculate_offset(item.get('target_time'))

                # 记录历史
                db.session.add(DeviceHistory(
                    device_id=device.id,
                    status=device.status,
                    result_data=device.current_value,
                    data_time=item.get('target_time'),
                    json_data=device.json_data
                ))
                count += 1

            db.session.commit()
            print(f"✅ [定时任务] 更新了 {count} 台设备")

        except Exception as e:
            db.session.rollback()
            print(f"❌ [定时任务] 异常: {str(e)}")


# --- App 工厂 ---
def create_app():
    app = Flask(__name__, static_folder=Config.STATIC_FOLDER)

    # 1. 加载配置 (包含数据库、JWT、爬虫配置)
    app.config.from_object(Config)

    # 2. 初始化扩展
    db.init_app(app)
    jwt.init_app(app)
    scheduler.init_app(app)

    # 3. 配置 CORS (允许 Authorization 头，解决 401/422 的关键)
    # 允许所有来源，允许凭证，允许关键 Header
    CORS(app,
         resources={r"/*": {"origins": "*"}},
         supports_credentials=True,
         allow_headers=["Content-Type", "Authorization", "X-Requested-With"])

    # 4. 注册蓝图
    if api_bp:
        app.register_blueprint(api_bp)

    # ==========================================
    # 5. JWT 详细错误处理 (调试核心部分)
    # ==========================================

    # A. 没带 Token 或者 Header 格式不对
    @jwt.unauthorized_loader
    def missing_token(error_string):
        print(f"\n🔴 [JWT ERROR] 请求被拒绝: 缺少 Token 或格式错误")
        print(f"   原因详情: {error_string}")
        print(f"   提示: 前端 header 必须是 'Authorization: Bearer <token>'\n")
        return jsonify({
            "code": 401,
            "message": "Missing Authorization Header",
            "detail": error_string
        }), 401

    # B. Token 是坏的 (签名不对，或者被篡改，或者密钥不匹配)
    @jwt.invalid_token_loader
    def invalid_token(error_string):
        print(f"\n🔴 [JWT ERROR] 请求被拒绝: Token 无效 (Invalid)")
        print(f"   原因详情: {error_string}")
        print(f"   排查: 1. 后端密钥可能变了 2. Token 是旧的 3. 复制粘贴错了\n")
        return jsonify({
            "code": 401,
            "message": "Invalid Token",
            "detail": error_string
        }), 401

    # C. Token 过期了
    @jwt.expired_token_loader
    def expired_token(jwt_header, jwt_payload):
        print(f"\n🔴 [JWT ERROR] 请求被拒绝: Token 已过期 (Expired)")
        print(f"   过期 Token 内容: {jwt_payload}")
        print(f"   当前服务器时间: {datetime.now()}")
        print(f"   提示: 请检查 config.py 里的有效期设置，或校准服务器时间\n")
        return jsonify({
            "code": 401,
            "message": "Token has expired",
            "detail": "token_expired"
        }), 401

    # ==========================================

    # 6. 启动定时任务
    if execute_monitor_task:
        # 防止重复添加任务
        if not scheduler.get_job('daily_monitor_task'):
            scheduler.add_job(
                id='daily_monitor_task',
                func=auto_monitor_job,
                args=[app],
                trigger='cron',
                hour=12,
                minute=0
            )
        if not scheduler.running:
            scheduler.start()

    # 7. 静态文件路由
    @app.route('/')
    def serve_index():
        if not os.path.exists(os.path.join(app.static_folder, 'index.html')):
            return "Web files not found. Please build frontend first.", 404
        return send_from_directory(app.static_folder, 'index.html')

    @app.route('/<path:path>')
    def serve_static(path):
        file_path = os.path.join(app.static_folder, path)
        if os.path.exists(file_path):
            return send_from_directory(app.static_folder, path)

        # 如果不是静态文件请求，也不是 api 请求，就返回 index.html (前端路由)
        if path.startswith('api'):
            return jsonify({'code': 404, 'msg': 'API endpoint not found'}), 404

        return send_from_directory(app.static_folder, 'index.html')

    # 8. 初始化数据库和默认管理员
    with app.app_context():
        # db.create_all() 会根据 binds 配置自动创建 users.db 和 devices.db
        db.create_all()
        try:
            # 检查是否有管理员，没有则创建
            if not User.query.filter_by(username='admin').first():
                print("🛠️  正在创建默认管理员账号...")
                admin = User(username='admin', role='admin')
                admin.set_password('licahk')
                db.session.add(admin)
                db.session.commit()
                print("✅ 初始管理员已创建: admin / licahk")
        except Exception as e:
            # 捕获数据库连接错误等
            print(f"⚠️ 初始化数据警告 (可能是首次运行或表结构变更): {e}")

    return app


if __name__ == '__main__':
    # 确保在主程序块中运行
    app = create_app()

    # 判断是否为打包后的环境
    debug_mode = not getattr(sys, 'frozen', False)

    print(f"\n🚀 服务启动中...")
    print(f"   模式: {'Debug (开发)' if debug_mode else 'Production (生产)'}")
    print(f"   端口: 5000")
    print(f"   密钥检查: {app.config.get('JWT_SECRET_KEY')[:5]}*** (请确保重启后这里不变)\n")

    app.run(host='0.0.0.0', port=5000, debug=debug_mode, use_reloader=False)