#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
呼叫器设备API模块
提供呼叫器设备相关的API接口
"""

# # from typing import Dict, List, Any, Optional
from fastapi import APIRouter, Body, Query, Path, Request, File, UploadFile, Form, Response
# # from pydantic import BaseModel

from routes.common_api import format_response, error_response
from utils.logger import get_logger
from services.calldevice_service import CallDeviceService
from routes.model.calldevice_model import CallDeviceModel, DeleteDeviceRequest, ExportDevicesRequest
from utils.crypto_utils import CryptoUtils
import time
import random
import json

# 创建路由
router = APIRouter(
    prefix="/api/vwed-calldevice",
    tags=["VWED呼叫器设备"]
)

# 设置日志
logger = get_logger("app.calldevice_api")


@router.post("/add")
async def add_call_device(
    call_device: CallDeviceModel = Body(..., description="呼叫器设备信息"),
    request: Request = Request
):
    """
    新增呼叫器设备
    
    Args:
        call_device: 呼叫器设备信息，包括协议类型、品牌、IP、端口、设备名称、状态及按钮配置
        request: 请求对象
    Returns:
        包含新增结果的响应
    """
    try:
        # 将按钮列表转换为字典列表，映射字段名称
        buttons_dict = []
        api_token = request.headers.get("x-access-token")
        if call_device.buttons:
            for button in call_device.buttons:
                button_dict = {
                    "signal_name": button.signal_name,
                    "signal_type": button.signal_type,
                    "signal_length": button.signal_length,
                    "register_address": button.register_address,
                    "function_code": button.function_code,
                    "remark": button.remark,
                    "vwed_task_id": button.vwed_task_id,
                    "long_vwed_task_id": button.long_vwed_task_id
                }
                buttons_dict.append(button_dict)
        
        result = await CallDeviceService.add_call_device(
            protocol=call_device.protocol,
            brand=call_device.brand,
            ip=call_device.ip,
            port=call_device.port,
            device_name=call_device.device_name,
            status=call_device.status,
            slave_id=call_device.slave_id,
            buttons=buttons_dict,
            api_token=api_token
        )
        
        if not result.get("success", False):
            return error_response(
                message=result.get("message", "新增呼叫器设备失败"), 
                code=400
            )
        
        return format_response(
            data=result.get("data", {}),
            message=result.get("message", "新增呼叫器设备成功")
        )
    except Exception as e:
        logger.error(f"新增呼叫器设备异常: {str(e)}")
        return error_response(message=f"新增呼叫器设备失败: {str(e)}", code=500)

@router.put("/update/{device_id}")
async def update_call_device(
    device_id: str = Path(..., description="设备ID"),
    call_device: CallDeviceModel = Body(..., description="呼叫器设备信息")
):
    """
    更新呼叫器设备
    
    Args:
        device_id: 设备ID
        call_device: 呼叫器设备信息，包括协议类型、品牌、IP、端口、设备名称、状态及按钮配置
        
    Returns:
        包含更新结果的响应
    """
    try:
        # 将按钮列表转换为字典列表，映射字段名称
        buttons_dict = []
        if call_device.buttons:
            for button in call_device.buttons:
                button_dict = {
                    "signal_name": button.signal_name,
                    "signal_type": button.signal_type,
                    "signal_length": button.signal_length,
                    "register_address": button.register_address,
                    "function_code": button.function_code,
                    "remark": button.remark,
                    "vwed_task_id": button.vwed_task_id,
                    "long_vwed_task_id": button.long_vwed_task_id
                }
                buttons_dict.append(button_dict)
        
        result = await CallDeviceService.update_call_device(
            device_id=device_id,
            protocol=call_device.protocol,
            brand=call_device.brand,
            ip=call_device.ip,
            port=call_device.port,
            device_name=call_device.device_name,
            status=call_device.status,
            slave_id=call_device.slave_id,
            buttons=buttons_dict
        )
        
        if not result.get("success", False):
            return error_response(
                message=result.get("message", "更新呼叫器设备失败"), 
                code=400
            )
        
        return format_response(
            data=result.get("data", {}),
            message=result.get("message", "更新呼叫器设备成功")
        )
    except Exception as e:
        logger.error(f"更新呼叫器设备异常: {str(e)}")
        return error_response(message=f"更新呼叫器设备失败: {str(e)}", code=500)


@router.post("/batch-delete")
async def delete_call_device_batch(
    request: DeleteDeviceRequest = Body(..., description="批量删除设备请求")
):
    """
    删除呼叫器设备
    
    Args:
        request: 包含要删除的设备ID列表的请求
        
    Returns:
        包含删除结果的响应
    """
    try:
        if not request.ids:
            return error_response(
                message="设备ID列表不能为空", 
                code=400
            )
        
        result = await CallDeviceService.delete_call_device(device_ids=request.ids)
        
        if not result.get("success", False):
            return error_response(
                message=result.get("message", "批量删除呼叫器设备失败"), 
                code=400
            )
        
        return format_response(
            data=result.get("data", {}),
            message=result.get("message", "批量删除呼叫器设备成功")
        )
    except Exception as e:
        logger.error(f"批量删除呼叫器设备异常: {str(e)}")
        return error_response(message=f"批量删除呼叫器设备失败: {str(e)}", code=500)

@router.get("/list")
async def get_call_device_list(
    page: int = Query(1, description="页码", ge=1),
    page_size: int = Query(10, description="每页数量", ge=1, le=100),
    device_name: str = Query(None, description="设备名称搜索"),
    ip: str = Query(None, description="IP地址搜索"),
    protocol: str = Query(None, description="协议类型搜索"),
    status: int = Query(None, description="状态过滤(0:禁用,1:启用)")
):
    """
    获取呼叫器设备列表
    
    Args:
        page: 页码
        page_size: 每页数量
        device_name: 设备名称搜索
        ip: IP地址搜索
        protocol: 协议类型搜索
        status: 状态过滤(0:禁用,1:启用)
        
    Returns:
        包含设备列表和分页信息的响应
    """
    try:
        result = await CallDeviceService.get_call_device_list(
            page=page,
            page_size=page_size,
            device_name=device_name,
            ip=ip,
            protocol=protocol,
            status=status
        )
        
        if not result.get("success", False):
            return error_response(
                message=result.get("message", "获取呼叫器设备列表失败"), 
                code=400
            )
        
        return format_response(
            data=result.get("data", {}),
            message=result.get("message", "获取呼叫器设备列表成功")
        )
    except Exception as e:
        logger.error(f"获取呼叫器设备列表异常: {str(e)}")
        return error_response(message=f"获取呼叫器设备列表失败: {str(e)}", code=500)

@router.get("/detail/{device_id}")
async def get_call_device_detail(
    device_id: str = Path(..., description="设备ID")
):
    """
    获取呼叫器设备详情
    
    Args:
        device_id: 设备ID
        
    Returns:
        包含设备详情的响应
    """
    try:
        result = await CallDeviceService.get_call_device_detail(device_id=device_id)
        
        if not result.get("success", False):
            return error_response(
                message=result.get("message", "获取呼叫器设备详情失败"), 
                code=400
            )
        
        return format_response(
            data=result.get("data", {}),
            message=result.get("message", "获取呼叫器设备详情成功")
        )
    except Exception as e:
        logger.error(f"获取呼叫器设备详情异常: {str(e)}")
        return error_response(message=f"获取呼叫器设备详情失败: {str(e)}", code=500)

@router.post("/export-batch")
async def export_batch_calldevice(
    export_req: ExportDevicesRequest = Body(..., description="批量导出设备请求")
):
    """
    批量导出呼叫器设备
    
    Args:
        export_req: 导出请求数据，包含要导出的设备ID列表
        
    Returns:
        Response: 包含设备配置的加密专有格式文件
    """
    try:
        result = await CallDeviceService.export_call_devices(device_ids=export_req.ids)
        
        if not result.get("success", False):
            return error_response(
                message=result.get("message", "批量导出呼叫器设备失败"), 
                code=400
            )
        
        # 获取设备数据
        devices_data = result.get("data", [])
        
        # 加密数据并添加文件头、签名和校验和
        encrypted_data = CryptoUtils.encrypt_data(devices_data)
        
        # 使用专有文件扩展名 .vdex (VWED Device Export)
        filename = f"calldevices_export_{len(export_req.ids)}.vdex" if len(export_req.ids) > 1 else f"calldevice_{export_req.ids[0]}.vdex"
        
        # 返回加密的二进制文件
        headers = {
            'Content-Disposition': f'attachment; filename={filename}',
            'Content-Type': 'application/octet-stream',
            'X-Content-Type-Options': 'nosniff',  # 防止浏览器嗅探文件类型
            "Access-Control-Expose-Headers": "Content-Disposition"
        }
        return Response(content=encrypted_data, media_type='application/octet-stream', headers=headers)
    
    except Exception as e:
        logger.error(f"批量导出呼叫器设备异常: {str(e)}")
        return error_response(message=f"批量导出呼叫器设备失败: {str(e)}", code=500)

@router.post("/import")
async def import_calldevice(
    file: UploadFile = File(..., description="呼叫器设备配置文件，加密专有格式")
):
    """
    导入呼叫器设备
    
    Args:
        file: 设备配置文件，加密专有格式
        
    Returns:
        包含导入结果的响应
    """
    try:
        # 读取文件内容
        content = await file.read()
        
        try:
            # 解密并验证数据
            devices_data = CryptoUtils.decrypt_data(content)
            
            # 生成唯一后缀以避免名称冲突
            timestamp = int(time.time())
            rand_num = random.randint(1000, 9999)
            rename_suffix = f"-备份-{timestamp}{rand_num}"
            
            # 导入设备
            result = await CallDeviceService.import_call_devices(
                devices_data=devices_data,
                rename_suffix=rename_suffix
            )
            
            if not result.get("success", False):
                return error_response(
                    message=result.get("message", "导入呼叫器设备失败"), 
                    code=400
                )
            
            return format_response(
                data=result.get("data", {}),
                message=result.get("message", "导入呼叫器设备成功")
            )
            
        except ValueError as e:
            logger.error(f"文件格式无效或已损坏: {str(e)}")
            return error_response(f"无法导入呼叫器设备: {str(e)}", 400)
        
        except Exception as e:
            logger.error(f"解析呼叫器设备数据失败: {str(e)}")
            return error_response(f"解析呼叫器设备数据失败: {str(e)}", 400)
        
    except Exception as e:
        logger.error(f"导入呼叫器设备异常: {str(e)}")
        return error_response(message=f"导入呼叫器设备失败: {str(e)}", code=500)

@router.post("/monitor/start/{device_id}")
async def start_device_monitor(
    device_id: str = Path(..., description="设备ID"),
    request: Request = Request
):
    """
    启动设备监控
    
    开启一个监控线程，持续监控设备按钮状态，当检测到按钮按下时触发对应任务
    
    Args:
        device_id: 设备ID
        
    Returns:
        包含启动结果的响应
    """
    try:
        # 获取token（用于同步到系统任务）
        tf_api_token = request.headers.get("x-access-token")
        result = await CallDeviceService.start_device_monitor(device_id, tf_api_token)
        
        if not result.get("success", False):
            return error_response(
                message=result.get("message", "启动设备监控失败"), 
                code=400
            )
        
        return format_response(
            data=result.get("data", {}),
            message=result.get("message", "启动设备监控成功")
        )
    except Exception as e:
        logger.error(f"启动设备监控异常: {str(e)}")
        return error_response(message=f"启动设备监控失败: {str(e)}", code=500)

@router.post("/monitor/stop/{device_id}")
async def stop_device_monitor(
    device_id: str = Path(..., description="设备ID")
):
    """
    停止设备监控
    
    停止设备的监控线程，不再监控按钮状态
    
    Args:
        device_id: 设备ID
        
    Returns:
        包含停止结果的响应
    """
    try:
        result = await CallDeviceService.stop_device_monitor(device_id)
        
        if not result.get("success", False):
            return error_response(
                message=result.get("message", "停止设备监控失败"), 
                code=400
            )
        
        return format_response(
            data=result.get("data", {}),
            message=result.get("message", "停止设备监控成功")
        )
    except Exception as e:
        logger.error(f"停止设备监控异常: {str(e)}")
        return error_response(message=f"停止设备监控失败: {str(e)}", code=500)

@router.get("/monitor/status/{device_id}")
async def get_device_monitor_status(
    device_id: str = Path(..., description="设备ID")
):
    """
    获取设备监控状态
    
    获取指定设备的监控状态信息
    
    Args:
        device_id: 设备ID
        
    Returns:
        包含设备监控状态的响应
    """
    try:
        result = await CallDeviceService.get_device_monitor_status(device_id)
        
        if not result.get("success", False):
            return error_response(
                message=result.get("message", "获取设备监控状态失败"), 
                code=400
            )
        
        return format_response(
            data=result.get("data", {}),
            message=result.get("message", "获取设备监控状态成功")
        )
    except Exception as e:
        logger.error(f"获取设备监控状态异常: {str(e)}")
        return error_response(message=f"获取设备监控状态失败: {str(e)}", code=500)

