import 'dart:async';
import 'dart:typed_data';

import 'package:usb_serial/usb_serial.dart';

import '../models/serial_config.dart';
import 'device_log.dart';

/// 串口连接状态
enum SerialConnectionState { disconnected, connecting, connected, error }

/// 串口服务
///
/// 封装 [UsbSerial] 库，对外暴露稳定的连接/读写接口，
/// 屏蔽底层 USB 设备的插拔、权限请求、参数配置等细节。
class SerialPortService {
  UsbPort? _port;
  UsbDevice? _device;
  StreamSubscription<Uint8List>? _readSub;
  final _connectionCtrl = StreamController<SerialConnectionState>.broadcast();
  final _dataCtrl = StreamController<Uint8List>.broadcast();
  final _errorCtrl = StreamController<String>.broadcast();
  SerialConnectionState _state = SerialConnectionState.disconnected;
  String? _lastError;

  /// 当前连接状态
  SerialConnectionState get state => _state;

  /// 最后一次错误信息
  String? get lastError => _lastError;

  /// 是否已连接
  bool get isConnected => _state == SerialConnectionState.connected;

  /// 当前连接设备（仅在已连接时可用）
  UsbDevice? get currentDevice => _device;

  /// 连接状态变更流
  Stream<SerialConnectionState> get connectionStateChanges =>
      _connectionCtrl.stream;

  /// 接收到的数据流
  Stream<Uint8List> get onData => _dataCtrl.stream;

  /// 错误信息流
  Stream<String> get onError => _errorCtrl.stream;

  /// 列出当前连接的 USB 串口设备
  Future<List<UsbDevice>> listDevices() async {
    return await UsbSerial.listDevices();
  }

  /// 设备名（vendor/product 拼接）
  static String deviceLabel(UsbDevice d) {
    final v = _hex(d.vid);
    final p = _hex(d.pid);
    final name = d.productName ?? d.manufacturerName ?? 'USB Serial';
    return '$name [$v:$p]';
  }

  static String _hex(int? v) =>
      (v ?? 0).toRadixString(16).padLeft(4, '0').toUpperCase();

  /// 打开指定设备并按 [config] 配置参数
  Future<bool> connect(UsbDevice device, SerialConfig config) async {
    if (_state == SerialConnectionState.connected ||
        _state == SerialConnectionState.connecting) {
      await disconnect();
    }

    DeviceLog.info('连接串口设备: ${deviceLabel(device)}, '
        'baud=${config.baudRate} dataBits=${config.dataBits} '
        'stopBits=${config.stopBits} parity=${config.parity.name}');
    _setState(SerialConnectionState.connecting);
    try {
      // UsbSerial.create 内部会触发 Android USB 权限弹窗
      final port = await device.create();
      if (port == null) {
        _fail('创建设备端口失败（可能未授予 USB 权限）');
        return false;
      }

      final opened = await port.open();
      if (!opened) {
        await port.close();
        _fail('打开端口失败');
        return false;
      }

      await _applyConfig(port, config);

      _port = port;
      _device = device;
      _subscribeStream(port);
      _setState(SerialConnectionState.connected);
      DeviceLog.info('串口已连接: ${deviceLabel(device)}');
      return true;
    } catch (e) {
      _fail('连接异常: $e');
      return false;
    }
  }

  /// 应用串口参数
  Future<void> _applyConfig(UsbPort port, SerialConfig config) async {
    await port.setPortParameters(
      config.baudRate,
      config.dataBits,
      config.stopBits,
      _parityToCode(config.parity),
    );
    await port.setFlowControl(_flowControlToCode(config.flowControl));
  }

  /// 断开当前连接
  Future<void> disconnect() async {
    if (_state == SerialConnectionState.disconnected) return;
    await _readSub?.cancel();
    _readSub = null;
    try {
      await _port?.close();
    } catch (_) {}
    _port = null;
    _device = null;
    _setState(SerialConnectionState.disconnected);
    DeviceLog.info('串口已断开');
  }

  /// 写入数据，返回成功写入的字节数（设备库本身不返回字节数，连接失败时返回 0）
  Future<int> write(Uint8List data) async {
    final port = _port;
    if (port == null || !isConnected) {
      _emitError('串口未连接，写入失败');
      return 0;
    }
    try {
      await port.write(data);
      DeviceLog.info('串口 TX: ${data.length} 字节');
      return data.length;
    } catch (e) {
      _emitError('写入异常: $e', error: e);
      return 0;
    }
  }

  /// 释放资源（应用退出时调用）
  Future<void> dispose() async {
    await disconnect();
    await _connectionCtrl.close();
    await _dataCtrl.close();
    await _errorCtrl.close();
  }

  void _subscribeStream(UsbPort port) {
    _readSub?.cancel();
    final stream = port.inputStream;
    if (stream == null) {
      _emitError('当前端口无输入流');
      return;
    }
    _readSub = stream.listen(
      (data) {
        if (data.isNotEmpty) {
          DeviceLog.info('串口 RX: ${data.length} 字节');
          _dataCtrl.add(data);
        }
      },
      onError: (Object e) {
        _emitError('读取异常: $e', error: e);
      },
      onDone: () {
        DeviceLog.info('串口输入流关闭');
        _setState(SerialConnectionState.disconnected);
      },
      cancelOnError: false,
    );
  }

  void _setState(SerialConnectionState s) {
    _state = s;
    if (s != SerialConnectionState.error) {
      _lastError = null;
    }
    if (!_connectionCtrl.isClosed) {
      _connectionCtrl.add(s);
    }
  }

  void _fail(String message) {
    _lastError = message;
    _setState(SerialConnectionState.error);
    _emitError(message);
  }

  void _emitError(String message, {Object? error}) {
    _lastError = message;
    if (error != null) {
      DeviceLog.severe(message, error: error);
    } else {
      DeviceLog.warn(message);
    }
    if (!_errorCtrl.isClosed) {
      _errorCtrl.add(message);
    }
  }

  static int _parityToCode(SerialParity p) {
    return switch (p) {
      SerialParity.none => UsbPort.PARITY_NONE,
      SerialParity.odd => UsbPort.PARITY_ODD,
      SerialParity.even => UsbPort.PARITY_EVEN,
      SerialParity.mark => UsbPort.PARITY_MARK,
      SerialParity.space => UsbPort.PARITY_SPACE,
    };
  }

  static int _flowControlToCode(SerialFlowControl f) {
    return switch (f) {
      SerialFlowControl.none => UsbPort.FLOW_CONTROL_OFF,
      SerialFlowControl.rtsCts => UsbPort.FLOW_CONTROL_RTS_CTS,
      SerialFlowControl.xonXoff => UsbPort.FLOW_CONTROL_XON_XOFF,
      SerialFlowControl.dtrDsr => UsbPort.FLOW_CONTROL_DSR_DTR,
    };
  }
}
