from fastapi import APIRouter, HTTPException, Query
from pydantic import BaseModel, Field

from app.services.monitor_service import MonitorService
from app.utils.response import success_response

router = APIRouter()
service = MonitorService()


# ── 请求 Schema ───────────────────────────────────────────────────────────────

class MPCParamsSchema(BaseModel):
    P: int = Field(default=20, ge=5, le=100, description='预测时域')
    M: int = Field(default=5, ge=1, le=20, description='控制时域')
    Q: float = Field(default=10.0, gt=0, description='跟踪误差权重')
    R: float = Field(default=0.1, gt=0, description='控制增量权重')
    alpha: float = Field(default=0.8, gt=0, lt=1, description='参考轨迹柔化系数')
    u_min: float = Field(default=0.0, description='电流下限(A)')
    u_max: float = Field(default=10.0, description='电流上限(A)')
    du_min: float = Field(default=-2.0, description='电流增量下限(A/步)')
    du_max: float = Field(default=2.0, description='电流增量上限(A/步)')
    y_min: float = Field(default=-50.0, description='温度约束下限(°C)')
    y_max: float = Field(default=200.0, description='温度约束上限(°C)')
    correction_gain: float = Field(default=0.5, ge=0, le=1, description='反馈校正增益')


class CreateExperimentRequest(BaseModel):
    name: str = Field(min_length=1, max_length=255)
    model_id: int
    input_csv_path: str = Field(min_length=1, description='读取传感器数据的CSV文件路径')
    output_csv_path: str = Field(min_length=1, description='输出曲线数据的CSV文件路径')
    target_temp: float = Field(description='目标温度(°C)')
    sampling_interval: float = Field(default=1.0, gt=0, le=3600, description='采样周期(秒)')
    mpc_params: MPCParamsSchema = Field(default_factory=MPCParamsSchema)


# ── 元数据接口 ────────────────────────────────────────────────────────────────

@router.get('/models')
def list_models():
    return success_response(data=service.list_models())


@router.get('/packages')
def list_packages():
    return success_response(data=service.list_packages())


# ── 试验 CRUD ─────────────────────────────────────────────────────────────────

@router.get('/experiments')
def list_experiments():
    return success_response(data=service.list_experiments())


@router.post('/experiments')
def create_experiment(req: CreateExperimentRequest):
    try:
        exp = service.create_experiment(
            name=req.name.strip(),
            model_id=req.model_id,
            input_csv_path=req.input_csv_path.strip(),
            output_csv_path=req.output_csv_path.strip(),
            target_temp=req.target_temp,
            sampling_interval=req.sampling_interval,
            mpc_params=req.mpc_params.model_dump(),
        )
        return success_response(data=exp, message='试验创建成功')
    except ValueError as exc:
        raise HTTPException(status_code=400, detail=str(exc)) from exc


@router.get('/experiments/{exp_id}')
def get_experiment(exp_id: int):
    try:
        return success_response(data=service.get_experiment(exp_id))
    except ValueError as exc:
        raise HTTPException(status_code=404, detail=str(exc)) from exc


@router.delete('/experiments/{exp_id}')
def delete_experiment(exp_id: int):
    try:
        service.delete_experiment(exp_id)
        return success_response(message='试验已删除')
    except ValueError as exc:
        raise HTTPException(status_code=404, detail=str(exc)) from exc


# ── 控制操作 ──────────────────────────────────────────────────────────────────

@router.post('/experiments/{exp_id}/start')
def start_experiment(exp_id: int):
    try:
        service.start_experiment(exp_id)
        return success_response(message='试验已启动')
    except ValueError as exc:
        raise HTTPException(status_code=400, detail=str(exc)) from exc


@router.post('/experiments/{exp_id}/stop')
def stop_experiment(exp_id: int):
    try:
        service.stop_experiment(exp_id)
        return success_response(message='试验已停止')
    except ValueError as exc:
        raise HTTPException(status_code=400, detail=str(exc)) from exc


# ── 数据 / 报告 / 导出 ────────────────────────────────────────────────────────

@router.get('/experiments/{exp_id}/data')
def get_data_points(exp_id: int, from_step: int = Query(default=0, ge=0)):
    return success_response(data=service.get_data_points(exp_id, from_step))




