import 'package:flutter/services.dart';
import 'package:flut/flut/object.dart';
import 'package:flut/flut/runtime.dart';
import 'package:flut/flut/error.dart';
import 'package:flut/dart/core.dart';
import 'package:flut/flutter/services/keyboard_key.dart';

class FlutKeyEvent extends FlutImmutableObject {
  final KeyEvent event;

  FlutKeyEvent(this.event)
    : super(
        event is KeyDownEvent
            ? 'KeyDownEvent'
            : event is KeyUpEvent
            ? 'KeyUpEvent'
            : event is KeyRepeatEvent
            ? 'KeyRepeatEvent'
            : 'KeyEvent',
      );

  @override
  Map<String, dynamic> flutEncode() {
    final result = flutBaseProps();
    result['logicalKey'] = FlutLogicalKeyboardKey(
      event.logicalKey,
    ).flutEncode();
    result['physicalKey'] = FlutPhysicalKeyboardKey(
      event.physicalKey,
    ).flutEncode();
    result['character'] = event.character;
    result['timeStamp'] = FlutDuration(event.timeStamp).flutEncode();
    result['synthesized'] = event.synthesized;
    return result;
  }
}

class FlutHardwareKeyboard extends FlutRealtimeObject<HardwareKeyboard> {
  FlutHardwareKeyboard.wrap({
    required super.runtime,
    required super.oid,
    required super.target,
  }) : super.wrap(type: 'HardwareKeyboard');

  static void registerStatics(FlutRuntime runtime) {
    runtime.registerStatic('HardwareKeyboard.instance', instance);
  }

  static FlutHardwareKeyboard instance(FlutRuntime runtime) {
    final keyboard = HardwareKeyboard.instance;
    return runtime.wrapObject<FlutHardwareKeyboard>(
      keyboard,
      (oid) => FlutHardwareKeyboard.wrap(
        runtime: runtime,
        oid: oid,
        target: keyboard,
      ),
    );
  }

  @override
  dynamic getRawProperty(String property) {
    switch (property) {
      case 'physicalKeysPressed':
        return flutTarget.physicalKeysPressed
            .map((k) => k.usbHidUsage)
            .toList();
      case 'logicalKeysPressed':
        return flutTarget.logicalKeysPressed.map((k) => k.keyId).toList();
      case 'isShiftPressed':
        return flutTarget.isShiftPressed;
      case 'isControlPressed':
        return flutTarget.isControlPressed;
      case 'isAltPressed':
        return flutTarget.isAltPressed;
      case 'isMetaPressed':
        return flutTarget.isMetaPressed;
    }
    throw FlutUnknownPropertyException('HardwareKeyboard', property);
  }

  @override
  bool setProperty(String property, dynamic value) {
    throw FlutUnknownPropertyException('HardwareKeyboard', property);
  }

  @override
  dynamic callMethod(String method, Map<String, dynamic> args) {
    switch (method) {
      case 'isPhysicalKeyPressed':
        return flutTarget.isPhysicalKeyPressed(
          PhysicalKeyboardKey(args['usbHidUsage'] as int),
        );
      case 'isLogicalKeyPressed':
        return flutTarget.isLogicalKeyPressed(
          LogicalKeyboardKey(args['keyId'] as int),
        );
    }
    throw FlutUnknownMethodException(method);
  }
}
