import 'package:flutter_riverpod/flutter_riverpod.dart';

import '../models/device_state.dart';
import '../services/device_log.dart';
import '../services/device_message.dart';
import '../services/device_message_service.dart';
import 'serial_provider.dart';

/// 设备信息通知器
///
/// 订阅 [DeviceMessageService] 中的 `device_info` 上行消息，
/// 维护门状态 / 灯状态 / 任务状态，供 UI 直接读取。
class DeviceInfoNotifier extends StateNotifier<DeviceState> {
  final DeviceMessageService _msgService;
  void Function()? _cancelSub;

  DeviceInfoNotifier(this._msgService) : super(const DeviceState()) {
    _cancelSub = _msgService.subscribe(
      DeviceMessageType.deviceInfo,
      _onDeviceInfo,
    );
    // 串口断开时无需主动清空 lastInfoAt —— infoStale 会根据
    // 当前时间与 lastInfoAt 的差值自动判断为「通讯异常」。
  }

  void _onDeviceInfo(DeviceMessage msg) {
    final data = msg.data;
    final light = _parseLight(data['light_status']);
    final door = _parseDoor(data['door_status']);
    final task = _parseTask(data['task_status']);
    final prev = state;
    final changed = prev.lightStatus != light ||
        prev.doorStatus != door ||
        prev.taskStatus != task;
    state = state.copyWith(
      lightStatus: light,
      doorStatus: door,
      taskStatus: task,
      lastInfoAt: DateTime.now(),
    );
    if (changed) {
      DeviceLog.info(
        'device_info updated: light=${light.name} door=${door.name} task=${task.name}',
      );
    }
  }

  /// 主动查询设备信息（发送 need_ack=true 的 create_task 之外的 device_info 请求，
  /// 具体取决于下位机协议约定；目前仅作占位）。
  Future<void> queryDeviceInfo() async {
    if (!_msgService.canSend) {
      DeviceLog.warn('queryDeviceInfo skipped: serial disconnected');
      return;
    }
    final id = _msgService.nextId();
    await _msgService.send(DeviceMessage.request(
      messageId: id,
      type: DeviceMessageType.deviceInfo,
      data: const <String, dynamic>{},
      needAck: true,
    ));
  }

  /// 发送灯光控制消息
  ///
  /// 主动切换后，下位机通常会通过 device_info 上报新的 light_status
  /// 覆盖本地状态。
  Future<bool> toggleLight() async {
    if (!_msgService.canSend) {
      DeviceLog.warn('toggleLight skipped: serial disconnected');
      return false;
    }
    final next = state.lightStatus == DeviceLightStatus.on ? 'off' : 'on';
    final id = _msgService.nextId();
    final ok = await _msgService.send(DeviceMessage.request(
      messageId: id,
      type: DeviceMessageType.lightControl,
      data: {'status': next},
      needAck: true,
    ));
    if (ok) {
      // 乐观更新；下位机的 device_info 上报会作为最终一致来源
      state = state.copyWith(
        lightStatus: next == 'on' ? DeviceLightStatus.on : DeviceLightStatus.off,
      );
      DeviceLog.info('toggleLight optimistic: -> $next');
    }
    return ok;
  }

  /// 显式设定灯光
  Future<bool> setLight(bool on) async {
    if (!_msgService.canSend) {
      DeviceLog.warn('setLight skipped: serial disconnected');
      return false;
    }
    if (on && state.lightStatus == DeviceLightStatus.on) return true;
    if (!on && state.lightStatus == DeviceLightStatus.off) return true;
    final id = _msgService.nextId();
    final ok = await _msgService.send(DeviceMessage.request(
      messageId: id,
      type: DeviceMessageType.lightControl,
      data: {'status': on ? 'on' : 'off'},
      needAck: true,
    ));
    if (ok) {
      state = state.copyWith(
        lightStatus: on ? DeviceLightStatus.on : DeviceLightStatus.off,
      );
      DeviceLog.info('setLight optimistic: -> ${on ? "on" : "off"}');
    }
    return ok;
  }

  @override
  void dispose() {
    _cancelSub?.call();
    _cancelSub = null;
    super.dispose();
  }

  // -- 解析 -------------------------------------------------------------

  static DeviceLightStatus _parseLight(dynamic v) =>
      v == 'on' ? DeviceLightStatus.on : DeviceLightStatus.off;

  static DeviceDoorStatus _parseDoor(dynamic v) =>
      v == 'open' ? DeviceDoorStatus.open : DeviceDoorStatus.close;

  static DeviceTaskStatus _parseTask(dynamic v) {
    return switch (v) {
      'running' => DeviceTaskStatus.running,
      'pause' => DeviceTaskStatus.pause,
      _ => DeviceTaskStatus.idle,
    };
  }
}

/// 设备信息 Provider
final deviceInfoProvider =
    StateNotifierProvider<DeviceInfoNotifier, DeviceState>((ref) {
  final service = ref.watch(deviceMessageServiceProvider);
  return DeviceInfoNotifier(service);
});
