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

class FlutKeyEventResult extends FlutEnumObject<KeyEventResult> {
  const FlutKeyEventResult()
    : super('KeyEventResult', const {
        'handled': KeyEventResult.handled,
        'ignored': KeyEventResult.ignored,
        'skipRemainingHandlers': KeyEventResult.skipRemainingHandlers,
      });
}

class _FlutFocusNode extends FocusNode {
  _FlutFocusNode({required FlutRuntime runtime, String? onKeyEventId}) {
    if (onKeyEventId != null) {
      onKeyEvent = (node, event) {
        if (event is! KeyDownEvent &&
            event is! KeyUpEvent &&
            event is! KeyRepeatEvent) {
          return KeyEventResult.ignored;
        }

        return runtime.callAction<KeyEventResult>(
              onKeyEventId,
              args: [event],
            ) ??
            KeyEventResult.ignored;
      };
    }
  }
}

class FlutFocusNode extends FlutRealtimeObject<FocusNode> {
  FlutFocusNode._({
    required FlutRuntime runtime,
    required Map<String, dynamic> json,
    required FocusNode target,
  }) : super(runtime: runtime, json: json, type: 'FocusNode', target: target);

  static FlutFocusNode flutDecode(
    FlutRuntime runtime,
    Map<String, dynamic> json,
  ) {
    return FlutFocusNode._(
      runtime: runtime,
      json: json,
      target: _FlutFocusNode(
        runtime: runtime,
        onKeyEventId: runtime.unpackOptionalField<String>(json, 'onKeyEventId'),
      ),
    );
  }

  @override
  dynamic getRawProperty(String property) {
    switch (property) {
      case 'hasFocus':
        return flutTarget.hasFocus;
      case 'hasPrimaryFocus':
        return flutTarget.hasPrimaryFocus;
    }
    throw FlutUnknownPropertyException('FocusNode', property);
  }

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

  @override
  dynamic callMethod(String method, Map<String, dynamic> args) {
    switch (method) {
      case 'requestFocus':
        flutTarget.requestFocus();
        return true;
      case 'unfocus':
        flutTarget.unfocus();
        return true;
    }
    throw FlutUnknownMethodException(method);
  }
}
