import 'dart:async';

import 'package:flutter/foundation.dart';
import 'package:vnote_device_plugin/consts/status.dart';
import 'package:vnote_device_plugin/events/defines.dart';
import 'package:vnote_device_plugin/events/event_center.dart';
import 'package:vnote_device_plugin/events/event_type.dart';
import 'package:vnote_device_plugin/models/device.dart';
import 'package:vnote_device_plugin/utils/lock.dart';
import 'package:vnote_device_plugin/utils/logger.dart';
import 'package:vnote_device_plugin/vnote_device_plugin_platform_interface.dart';

import 'searcher.dart';

class _WorkSearchProxy {
  static final locker = Locker<Key>();

  final _uniqueKey = UniqueKey();
  final String type;
  bool _busy = false;
  DeviceSearcher? _searcher;

  _WorkSearchProxy(this.type);

  Future<DeviceInfo?> search() async {
    _busy = true;
    // 排队等待锁定
    await locker.lock(_uniqueKey);
    if (_busy == false) {
      // 已取消
      // 完成工作，解锁
      locker.unlock(_uniqueKey);
      return null;
    }

    final result = await _doOnce();
    // 完成工作，解锁
    locker.unlock(_uniqueKey);
    _busy = false;
    return result;
  }

  Future<void> cancel() async {
    await _stopSearch();
    _busy = false;
    locker.unlock(_uniqueKey);
  }

  Future<DeviceInfo?> _doOnce() async {
    final completer = Completer<DeviceInfo?>();

    final searcher = DeviceSearcher(type);
    _searcher = searcher;
    searcher.init();
    searcher.successEvent.addListener((sender, e) {
      _doneOnce(completer, e);
    });
    searcher.failEvent.addListener((sender, e) {
      _doneOnce(completer, null);
    });
    searcher.timeoutEvent.addListener((sender, e) {
      _doneOnce(completer, null);
    });
    await searcher.start();

    return completer.future;
  }

  void _doneOnce(Completer<DeviceInfo?> completer, DeviceInfo? result) async {
    _searcher?.dispose();
    _searcher = null;
    completer.complete(result);
  }

  Future<void> _stopSearch() async {
    try {
      await _searcher?.stop();
      _searcher?.dispose();
      _searcher = null;
    } catch (e) {
      // 不处理
    }
  }
}

/// 设备 虚拟工作线程 基类
abstract class DeviceWorkerBase {
  final _statusHandlers = <int, DeviceEventStatusCallback>{};
  final _setupStatusList = <int>[
    VDeviceEventStatus.BLE_CONNECTING,
    VDeviceEventStatus.BLE_CONNECT_SUCCESS,
    VDeviceEventStatus.BLE_CONNECT_FAIL,
    VDeviceEventStatus.BLE_DISCONNECTED,
    VDeviceEventStatus.BT_BOUNDING,
    VDeviceEventStatus.BT_BOUND_SUCCESS,
    VDeviceEventStatus.BT_BOUND_FAIL,
  ];

  bool _isConnected = false;
  bool _isConnecting = false;
  DeviceEventListener? _listener;
  _WorkSearchProxy? _searchProxy;

  DeviceWorkerBase({
    required this.type,
    required this.model,
    required this.mac,
  }) {
    init();
  }

  /// 设备类型
  final String type;

  /// 设备型号
  final String model;

  /// 设备物理地址
  final String mac;

  /// 是否需要在连接前先搜索设备
  bool needSearchBeforeConnect = false;

  /// 是否已连接
  bool get isConnected => _isConnected;

  /// 设备已连接事件
  final connectedEvent = FEventHandler<void>();

  /// 设备连接失败事件
  final connectErrorEvent = FEventHandler<dynamic>();

  /// 设备断开连接事件
  final disconnectedEvent = FEventHandler<void>();

  /// 设备连接中
  final connectingEvent = FEventHandler<void>();

  /// 设备配对中事件
  final boundingEvent = FEventHandler<void>();

  /// 设备配对成功事件
  final boundSuccessEvent = FEventHandler<void>();

  /// 设备配对失败事件
  final boundFailEvent = FEventHandler<void>();

  /// 初始化
  @protected
  @mustCallSuper
  void init() {
    _searchProxy = _WorkSearchProxy(type);
    _startListener();
  }

  /// 释放
  @mustCallSuper
  void dispose() {
    _removeListener();
    _setupStatusList.clear();
    _statusHandlers.clear();
  }

  /// 注入状态回调
  ///
  /// [status] 事件状态
  ///
  /// [callback] 回调函数
  @protected
  void injectStatusCallback(
    int status,
    DeviceEventStatusCallback callback,
  ) {
    _setupStatusList.add(status);
    _statusHandlers[status] = callback;
  }

  /// 连接设备
  Future<void> connect() async {
    _isConnecting = false;
    if (_isConnecting || _isConnected) return;

    _isConnecting = true;

    await _searchProxy!.search();

    log("Connect");
    await VnoteDevicePluginPlatform.instance.callAction(
      "BLUETOOTH_CONNECT",
      {
        "MODEL": model,
        "MAC": mac,
      },
    );
  }

  /// 端开连接
  Future<void> disconnect() async {
    if (!_isConnected) {
      // TODO：连接的时候会有搜索动作哦，需要手动停止搜索
      // await VnoteDevicePluginPlatform.instance.callAction(
      //   "SEARCH_STOP",
      //   {"TYPE": type},
      // );
      await _searchProxy!.cancel();
      return;
    }

    log("Disconnect");

    await VnoteDevicePluginPlatform.instance.callAction(
      "BLE_DISCONNECT",
      {"MODEL": model},
    );

    _isConnected = false;
  }

  void _startListener() {
    _listener = DeviceEventListener(
      accpetStatusList: _setupStatusList,
      callback: _onEventCallback,
    );
    DeviceEventCenter.instance.addListener(_listener!);
  }

  void _removeListener() {
    if (_listener != null) {
      DeviceEventCenter.instance.removeListener(_listener!);
      _listener = null;
    }
  }

  void _onEventCallback(int status, Map<String, dynamic>? e) {
    if (status < 1000) {
      return _onConnectAboutCallback(status, e);
    }

    if (_statusHandlers.containsKey(status)) {
      final callback = _statusHandlers[status]!;
      callback.call(e);
    }
  }

  void _onConnectAboutCallback(int status, Map<String, dynamic>? e) {
    final isMatch = checkDeviceMatch(e);
    if (!isMatch) {
      // 非当前设备的事件通知，不做处理
      return;
    }
    switch (status) {
      case VDeviceEventStatus.BLE_CONNECT_SUCCESS:
        _onConnectedCallback();
        break;
      case VDeviceEventStatus.BLE_CONNECT_FAIL:
        _onConnectErrorCallback(status, e);
        break;
      case VDeviceEventStatus.BLE_DISCONNECTED:
        _onDisconnectedCallback();
        break;
      case VDeviceEventStatus.BLE_CONNECTING:
        _onConnectingCallback();
        break;
      case VDeviceEventStatus.BT_BOUNDING:
        _onBoundingCallback();
        break;
      case VDeviceEventStatus.BT_BOUND_SUCCESS:
        _onBoundSuccessCallback();
        break;
      case VDeviceEventStatus.BT_BOUND_FAIL:
        _onBoundFailCallback();
        break;
      default:
        break;
    }
  }

  void _onConnectedCallback() {
    log("Connected callback");
    _isConnecting = false;
    _isConnected = true;
    connectedEvent.emit(this, null);
  }

  void _onConnectErrorCallback(int status, Map<String, dynamic>? data) {
    log("Connect error callback");
    _isConnecting = false;
    connectErrorEvent.emit(this, status);
  }

  void _onDisconnectedCallback() {
    log("Disconnecting callback");
    _isConnected = false;
    disconnectedEvent.emit(this, null);
  }

  void _onConnectingCallback() {
    log("Connecting callback");
    connectingEvent.emit(this, null);
  }

  void _onBoundingCallback() {
    log("Bounding callback");
    _isConnecting = false;
    _isConnected = false;
    boundingEvent.emit(this, null);
  }

  void _onBoundSuccessCallback() {
    log("BoundSuccess callback");
    boundSuccessEvent.emit(this, null);
  }

  void _onBoundFailCallback() {
    log("BoundFail callback");
    boundFailEvent.emit(this, null);
  }

  @protected
  bool checkDeviceMatch(Map<String, dynamic>? data) {
    if (data == null) return false;

    final eventType = data["TYPE"];
    final eventModel = data["MODEL"];
    if (type == eventType && model == eventModel) {
      return true;
    }

    return false;
  }

  @protected
  void log(String content) {
    if (kDebugMode) {
      print("[DEBUG_LOG] $content");
    }
    LogUtil.write("DeviceWorker[$type] $content.");
  }
}
