import 'dart:convert';
import 'dart:typed_data';

import 'device_log.dart';
import 'device_message.dart';

/// JSON 协议层帧编解码器
///
/// 由于串口为字节流，需要在 JSON 字符串之外增加帧定界。
/// 采用「4 字节大端长度前缀 + UTF-8 JSON + 换行符」的简单可靠方案：
/// ```
/// [LEN(4B BE)] [JSON_UTF8...] ['\n']
/// ```
/// - LEN：JSON 部分的字节数（不含 LEN 自身与换行符）
/// - JSON：完整 `DeviceMessage.toJson()` 序列化结果
/// - 换行符：辅助日志/调试，便于人工嗅探串口
///
/// 解析器按累积缓冲区增量解码，单次返回一条已完整解析的消息。
class JsonProtocolService {
  static const int _lengthPrefixSize = 4;
  static const int _maxFrameBytes = 64 * 1024;

  final MessageIdGenerator _idGenerator = MessageIdGenerator();
  final List<int> _buffer = [];

  /// 生成下一个消息 ID
  String nextId() => _idGenerator.next();

  /// 将消息编码为可下发的字节流
  Uint8List encode(DeviceMessage message) {
    final json = utf8.encode(message.encode());
    if (json.isEmpty) {
      throw ArgumentError('encoded JSON is empty');
    }
    if (json.length > _maxFrameBytes) {
      throw ArgumentError('message too large: ${json.length}B');
    }
    final buf = Uint8List(_lengthPrefixSize + json.length + 1);
    // 大端长度
    final len = json.length;
    buf[0] = (len >> 24) & 0xFF;
    buf[1] = (len >> 16) & 0xFF;
    buf[2] = (len >> 8) & 0xFF;
    buf[3] = len & 0xFF;
    buf.setRange(_lengthPrefixSize, _lengthPrefixSize + json.length, json);
    buf[buf.length - 1] = 0x0A; // '\n'
    return buf;
  }

  /// 尝试从累积缓冲区解析一条完整消息
  ///
  /// 返回 (message, consumedBytes)。consumedBytes 表示已消费字节数，
  /// 调用方应从缓冲区中移除。
  /// 不足一帧时返回 (null, 0)。
  (DeviceMessage?, int) tryDecode(List<int> incoming) {
    if (incoming.isEmpty) return (null, 0);
    _buffer.addAll(incoming);

    // 防止缓冲区无限增长
    if (_buffer.length > _maxFrameBytes * 2) {
      _buffer.removeRange(0, _buffer.length - _maxFrameBytes);
    }

    if (_buffer.length < _lengthPrefixSize) return (null, 0);

    final len = (_buffer[0] << 24) |
        (_buffer[1] << 16) |
        (_buffer[2] << 8) |
        _buffer[3];
    if (len <= 0 || len > _maxFrameBytes) {
      DeviceLog.warn('tryDecode: 异常长度=$len 丢弃首字节 0x${_buffer[0].toRadixString(16).padLeft(2, '0')}');
      _buffer.removeAt(0);
      return (null, 0);
    }

    final totalNeeded = _lengthPrefixSize + len + 1; // +1 换行符
    if (_buffer.length < totalNeeded) return (null, 0);

    final jsonBytes = _buffer.sublist(_lengthPrefixSize, _lengthPrefixSize + len);
    final tail = _buffer[_lengthPrefixSize + len];
    // 换行符不是必需的，缺失也接受；存在则跳过
    final consumed = tail == 0x0A ? totalNeeded : totalNeeded - 1;
    _buffer.removeRange(0, consumed);

    try {
      final json = utf8.decode(jsonBytes);
      final msg = DeviceMessage.decode(json);
      return (msg, consumed);
    } catch (_) {
      return (null, consumed);
    }
  }

  /// 重置内部缓冲区（断线/异常时调用）
  void reset() => _buffer.clear();
}
