import 'package:fis_common/event/event_type.dart';
import 'package:fis_measure/interfaces/process/workspace/application.dart';
import 'package:fis_measure/interfaces/process/workspace/point_info.dart';
import 'package:fis_measure/view/cursor.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';

abstract class IMouseState {
  Offset? get mousePosition;
  set mousePosition(Offset? value);

  Offset? get cursorPosition;

  MeasureCursorType get cursorType;
  set cursorType(MeasureCursorType value);

  double get cursorSize;
  set cursorSize(double value);

  late FEventHandler<Offset?> mousePositionChanged;
  late FEventHandler<MeasureCursorType> cursorTypeChanged;
  late FEventHandler<double> cursorSizeChanged;
}

class MouseState implements IMouseState {
  Offset? _mousePosition;
  double _cursorSize = 16;
  MeasureCursorType _cursorType = MeasureCursorType.cursor01;

  @override
  var mousePositionChanged = FEventHandler<Offset?>();

  @override
  var cursorSizeChanged = FEventHandler<double>();

  @override
  var cursorTypeChanged = FEventHandler<MeasureCursorType>();

  @override
  Offset? get mousePosition => _mousePosition;
  @override
  set mousePosition(Offset? value) {
    if (value != _mousePosition) {
      _mousePosition = value;
      mousePositionChanged.emit(this, value);
    }
  }

  @override
  double get cursorSize => _cursorSize;
  @override
  set cursorSize(double value) {
    if (value != _cursorSize) {
      _cursorSize = value;
      cursorSizeChanged.emit(this, value);
    }
  }

  @override
  MeasureCursorType get cursorType => _cursorType;
  @override
  set cursorType(MeasureCursorType value) {
    if (value != _cursorType) {
      _cursorType = value;
      cursorTypeChanged.emit(this, value);
    }
  }

  @override
  Offset? get cursorPosition {
    if (mousePosition == null) return null;

    double dx = mousePosition!.dx, dy = mousePosition!.dy;
    final offset = cursorSize / 2;
    dx -= offset;
    dy -= offset;
    return Offset(dx, dy);
  }
}

class MeasureMouseGesturePanel extends StatefulWidget {
  const MeasureMouseGesturePanel({Key? key}) : super(key: key);

  @override
  State<StatefulWidget> createState() => _MeasureMouseGesturePanelState();
}

class _MeasureMouseGesturePanelState extends State<MeasureMouseGesturePanel> {
  Offset? mousePosition;
  Offset? cursorPosition;

  final mouseState = Get.put<IMouseState>(MouseState());
  late final application = Get.find<IApplication>();

  @override
  void initState() {
    //
    mouseState.cursorSize = 32;
    super.initState();
  }

  @override
  void dispose() {
    //
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTapDown: (details) {
        application.createPointInfo(
          details.localPosition,
          PointInfoType.mouseDown,
        );
      },
      onPanDown: (details) {
        // application.createPointInfo(
        //   details.localPosition,
        //   PointInfoType.mouseDown,
        // );
      },
      onPanUpdate: (details) {
        mouseState.mousePosition = details.localPosition;
        application.createPointInfo(
          details.localPosition,
          PointInfoType.mouseMove,
        );
      },
      child: MouseRegion(
        cursor: SystemMouseCursors.none,
        onHover: (event) {
          mouseState.mousePosition = event.localPosition;
          application.createPointInfo(
            event.localPosition,
            PointInfoType.mouseMove,
          );
        },
        child: Stack(
          children: [
            _PositionedCursor(),
          ],
        ),
      ),
    );
  }
}

class _PositionedCursor extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => _PositionedCursorState();
}

class _PositionedCursorState extends State<_PositionedCursor> {
  final mouseState = Get.find<IMouseState>();

  @override
  void initState() {
    mouseState.cursorSizeChanged.addListener(onCursorSizeChanged);
    mouseState.cursorTypeChanged.addListener(cursorTypeChanged);
    mouseState.mousePositionChanged.addListener(mousePositionChanged);
    super.initState();
  }

  @override
  void dispose() {
    mouseState.cursorSizeChanged.removeListener(onCursorSizeChanged);
    mouseState.cursorTypeChanged.removeListener(cursorTypeChanged);
    mouseState.mousePositionChanged.removeListener(mousePositionChanged);
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    final position = mouseState.cursorPosition;
    if (position == null) return Container();

    return Positioned(
      left: position.dx,
      top: position.dy,
      child: MeasureCursor(
        type: mouseState.cursorType,
        size: mouseState.cursorSize,
        color: Colors.red,
      ),
    );
  }

  void onCursorSizeChanged(Object sender, dynamic e) {
    onUpdate();
  }

  void cursorTypeChanged(Object sender, dynamic e) {
    onUpdate();
  }

  void mousePositionChanged(Object sender, dynamic e) {
    onUpdate();
  }

  void onUpdate() {
    setState(() {});
  }
}
