import 'dart:convert';

import '../../programs/models/program.dart';
import '../../programs/models/step.dart';
import 'device_message.dart';

/// 下位机启动任务负载
///
/// 将上位机 [Program] + [Step] 列表转换为下位机协议要求的 `create_task` 数据。
/// 协议示例：
/// ```json
/// {
///   "steps": [
///     {"no": 1, "slot": 1, "name": "混合", "mixtime": 60, "pulltime": 30, "volume": 100, "speed": 5}
///   ],
///   "temperature": 50,
///   "airflowtime": 60
/// }
/// ```
class TaskPayload {
  final List<Step> steps;
  final int temperature;
  final int airflowTime;

  const TaskPayload({
    required this.steps,
    required this.temperature,
    required this.airflowTime,
  });

  /// 从程序和步骤列表构造负载
  factory TaskPayload.fromProgram(Program program, List<Step> steps) {
    return TaskPayload(
      steps: List<Step>.from(steps)
        ..sort((a, b) => a.stepNo.compareTo(b.stepNo)),
      temperature: program.temperature,
      airflowTime: program.airflowTime,
    );
  }

  /// 转换为下位机协议 Map
  Map<String, dynamic> toJson() {
    return {
      'steps': steps.map((s) => _stepToJson(s)).toList(),
      'temperature': temperature,
      'airflowtime': airflowTime,
    };
  }

  /// 序列化为 JSON 字符串
  String encode() => jsonEncode(toJson());

  /// 包裹为下位机 [DeviceMessage]
  DeviceMessage toMessage(String messageId, {bool needAck = true}) {
    return DeviceMessage.request(
      messageId: messageId,
      type: DeviceMessageType.createTask,
      data: toJson(),
      needAck: needAck,
    );
  }

  Map<String, dynamic> _stepToJson(Step s) {
    return {
      'no': s.stepNo,
      'slot': _slotFromPosition(s.position),
      'name': s.name,
      'mixtime': s.mixTime,
      'pulltime': s.magnetTime,
      'volume': s.volume,
      'speed': s.speed,
    };
  }

  /// 将孔位（如 "A1"）转换为下位机使用的整数编号
  /// 协议约定：A1=1, A2=2, ..., A6=6, B1=7, ..., D6=24
  static int _slotFromPosition(String position) {
    if (position.length < 2) return 1;
    final row = position.codeUnitAt(0) - 'A'.codeUnitAt(0);
    final col = int.tryParse(position.substring(1)) ?? 1;
    if (row < 0 || row > 3 || col < 1 || col > 6) return 1;
    return row * 6 + col;
  }
}
