import 'package:nearby_service/nearby_service.dart';
import 'package:nearby_service/src/utils/json_decoder.dart';
import 'package:nearby_service/src/utils/unknown.dart';

///
/// A device on a P2P network obtained from the Android platform.
///
final class NearbyAndroidDevice extends NearbyDevice {
  ///
  /// The class representing the Android class
  /// [WifiP2pDevice](https://developer.android.com/reference/android/net/wifi/p2p/WifiP2pDevice).
  ///
  /// Automatically generates the [info] field from the [deviceName]
  /// and [deviceAddress] fields.
  ///
  /// They are used because in a Wifi Direct environment
  /// the MAC address of the device is an identifier on the network.
  ///
  NearbyAndroidDevice({
    required String deviceName,
    required this.deviceAddress,
    this.isGroupOwner = false,
    this.isServiceDiscoveryCapable = false,
    this.primaryDeviceType = kNearbyUnknown,
    this.wpsKeypadSupported = false,
    this.wpsPbcSupported = false,
    this.wpsDisplaySupported = false,
    this.secondaryDeviceType,
    super.status = NearbyDeviceStatus.unavailable,
  }) : super(
          info: NearbyDeviceInfo(
            displayName: deviceName,
            id: deviceAddress,
          ),
        );

  ///
  /// Gets [NearbyAndroidDevice] from [Map]
  ///
  factory NearbyAndroidDevice.fromJson(Map<String, dynamic>? json) {
    return NearbyAndroidDevice(
      deviceName: json?['deviceName'] ?? kNearbyUnknown,
      deviceAddress: json?['deviceAddress'] ?? kNearbyUnknown,
      isGroupOwner: json?['isGroupOwner'] ?? false,
      isServiceDiscoveryCapable: json?['isServiceDiscoveryCapable'] ?? false,
      primaryDeviceType: json?['primaryDeviceType'] ?? kNearbyUnknown,
      secondaryDeviceType: json?['secondaryDeviceType'],
      wpsDisplaySupported: json?['wpsDisplaySupported'] ?? false,
      wpsKeypadSupported: json?['wpsKeypadSupported'] ?? false,
      wpsPbcSupported: json?['wpsPbcSupported'] ?? false,
      status: NearbyDeviceStatus.fromAndroidCode(json?['status']),
    );
  }

  ///
  /// The device MAC address uniquely identifies a Wi-Fi p2p device.
  /// Source [WifiP2pDevice documentation](https://developer.android.com/reference/android/net/wifi/p2p/WifiP2pDevice)
  ///
  final String deviceAddress;

  ///
  /// True if the device is a group owner.
  /// Source [WifiP2pDevice documentation](https://developer.android.com/reference/android/net/wifi/p2p/WifiP2pDevice)
  ///
  final bool isGroupOwner;

  ///
  /// True if the device is capable of service discovery.
  /// Source [WifiP2pDevice documentation](https://developer.android.com/reference/android/net/wifi/p2p/WifiP2pDevice)
  ///
  final bool isServiceDiscoveryCapable;

  ///
  /// Primary device type identifies the type of device.
  /// Source [WifiP2pDevice documentation](https://developer.android.com/reference/android/net/wifi/p2p/WifiP2pDevice)
  ///
  final String primaryDeviceType;

  ///
  /// Secondary device type is an optional attribute.
  /// that can be provided by a device in addition to the primary device type.
  /// Source [WifiP2pDevice documentation](https://developer.android.com/reference/android/net/wifi/p2p/WifiP2pDevice)
  ///
  final String? secondaryDeviceType;

  ///
  /// True if WPS keypad configuration is supported.
  /// Source [WifiP2pDevice documentation](https://developer.android.com/reference/android/net/wifi/p2p/WifiP2pDevice)
  ///
  final bool wpsKeypadSupported;

  ///
  /// True if WPS push button configuration is supported.
  /// Source [WifiP2pDevice documentation](https://developer.android.com/reference/android/net/wifi/p2p/WifiP2pDevice)
  ///
  final bool wpsPbcSupported;

  ///
  /// True if WPS display configuration is supported.
  /// Source [WifiP2pDevice documentation](https://developer.android.com/reference/android/net/wifi/p2p/WifiP2pDevice)
  ///
  final bool wpsDisplaySupported;

  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
      super == other &&
          other is NearbyAndroidDevice &&
          runtimeType == other.runtimeType &&
          deviceAddress == other.deviceAddress &&
          isGroupOwner == other.isGroupOwner &&
          isServiceDiscoveryCapable == other.isServiceDiscoveryCapable &&
          primaryDeviceType == other.primaryDeviceType &&
          secondaryDeviceType == other.secondaryDeviceType &&
          wpsKeypadSupported == other.wpsKeypadSupported &&
          wpsPbcSupported == other.wpsPbcSupported &&
          wpsDisplaySupported == other.wpsDisplaySupported;

  @override
  int get hashCode =>
      super.hashCode ^
      deviceAddress.hashCode ^
      isGroupOwner.hashCode ^
      isServiceDiscoveryCapable.hashCode ^
      primaryDeviceType.hashCode ^
      secondaryDeviceType.hashCode ^
      wpsKeypadSupported.hashCode ^
      wpsPbcSupported.hashCode ^
      wpsDisplaySupported.hashCode;

  @override
  String toString() {
    return 'NearbyAndroidDevice{deviceAddress: $deviceAddress, isGroupOwner: $isGroupOwner, isServiceDiscoveryCapable: $isServiceDiscoveryCapable, primaryDeviceType: $primaryDeviceType, secondaryDeviceType: $secondaryDeviceType, wpsKeypadSupported: $wpsKeypadSupported, wpsPbcSupported: $wpsPbcSupported, wpsDisplaySupported: $wpsDisplaySupported}';
  }
}

///
/// Implementation of [NearbyDeviceMapper] for Android.
///
class NearbyAndroidMapper implements NearbyDeviceMapper {
  @override
  List<NearbyDevice> mapToDeviceList(dynamic value) {
    final decoded = JSONDecoder.decodeList(value);
    return [
      ...?decoded?.map(
        (e) => NearbyAndroidDevice.fromJson(e as Map<String, dynamic>?),
      ),
    ];
  }

  @override
  NearbyDevice? mapToDevice(dynamic value) {
    final decoded = JSONDecoder.decodeMap(value);
    if (decoded == null) return null;

    return NearbyAndroidDevice.fromJson(decoded);
  }
}
