import 'dart:math';

import 'package:fis_ui/index.dart';
import 'package:flyinsono/pages/main/home/widgets/listener.dart';
import 'package:flyinsono/pages/schedule/calendar/calendar_page/month_calendar/more_schedule_popup.dart';
import 'package:flyinsono/pages/schedule/calendar/calendar_page/month_calendar/consultation_schedule_popup.dart';
import 'package:flyinsono/pages/schedule/calendar/popup_layer/popup_layer_controller.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';

class PopupLayer extends FStatefulWidget {
  const PopupLayer({super.key});

  @override
  FState<PopupLayer> createState() => _PopupLayerState();
}

class _PopupLayerState extends FState<PopupLayer> {
  PopupLayerController popupLayerController = Get.find<PopupLayerController>();
  bool _isShowMoreSchedulePopup = false;
  bool _isNeedCloseMoreSchedulePopup = false;
  bool _isShowScheduleDetailPopup = false;
  bool _isNeedCloseScheduleDetailPopup = false;
  GlobalKey moreSchedulePopupKey = GlobalKey();
  GlobalKey scheduleDetailPopupKey = GlobalKey();
  GlobalKey moreSchedulePopupContainerKey = GlobalKey();

  /// 日程详情弹出框宽度
  static const double _scheduleDetailPopupWidth = 380;

  /// 日程详情弹出框左右边距
  static const double _scheduleDetailPopupHorizontalPadding = 10;

  /// 完成日程列表弹出框最小推荐宽度
  static const double _moreSchedulePopupMinWidth = 220;

  /// 固定的头部高度
  static const double _popupLayerMarginTop = 70;

  /// 固定的左侧宽度
  static const double _popupLayerMarginLeft = 240;

  /// 弹出框装饰器
  static final BoxDecoration _popupBoxDecoration = BoxDecoration(
    color: Colors.white,
    borderRadius: BorderRadius.circular(8),
    border: Border.all(color: Colors.black12, width: 1),
    boxShadow: const [
      BoxShadow(
        color: Colors.black12,
        offset: Offset(3, 3),
        blurRadius: 25,
      ),
    ],
  );
  @override
  void initState() {
    super.initState();
    popupLayerController.onPopupMoreSchedule.addListener(_onPopupMoreSchedule);
    popupLayerController.onGlobalClick.addListener(_onGlobalClick);
    popupLayerController.onPopupScheduleDatail
        .addListener(_onPopupScheduleDatail);
  }

  @override
  void dispose() {
    super.dispose();
    popupLayerController.onPopupMoreSchedule
        .removeListener(_onPopupMoreSchedule);
    popupLayerController.onGlobalClick.removeListener(_onGlobalClick);
    popupLayerController.onPopupScheduleDatail
        .removeListener(_onPopupScheduleDatail);
  }

  /// 收到显示更多日程的事件
  void _onPopupMoreSchedule(e, GlobalKey key) {
    setState(() {
      _isShowMoreSchedulePopup = true;
      moreSchedulePopupKey = key;
    });
  }

  /// 收到显示日程详情的事件
  void _onPopupScheduleDatail(e, GlobalKey key) {
    setState(() {
      _isShowScheduleDetailPopup = true;
      scheduleDetailPopupKey = key;
    });
  }

  /// 收到全局点击事件
  /// 全局按下时设置 _needClosePopup 为 true
  /// 弹层组件收到 onPointerUp 时设置 _needClosePopup 为 false
  /// 全局抬起时判断 _needClosePopup 是否为 true，为 true 则关闭弹层
  void _onGlobalClick(e, PointerEvent event) {
    if (event is PointerDownEvent) {
      _isNeedCloseMoreSchedulePopup = true;
      _isNeedCloseScheduleDetailPopup = true;
    } else if (event is PointerUpEvent) {
      if (_isNeedCloseMoreSchedulePopup) {
        setState(() {
          _isShowMoreSchedulePopup = false;
        });
      }
      if (_isNeedCloseScheduleDetailPopup) {
        setState(() {
          _isShowScheduleDetailPopup = false;
        });
        popupLayerController.onCloseSchedulePopup.emit(this, null);
      }
    }
  }

  @override
  FWidget build(BuildContext context) {
    return FStack(
      key: moreSchedulePopupContainerKey,
      children: [
        FOffstage(
          offstage: !_isShowMoreSchedulePopup,
          child: FListener(
            behavior: HitTestBehavior.deferToChild,
            onPointerUp: (event) {
              _isNeedCloseMoreSchedulePopup = false;
            },
            child: _buildMoreSchedulePopup(moreSchedulePopupKey),
          ),
        ),
        FOffstage(
          offstage: !_isShowScheduleDetailPopup,
          child: FListener(
            behavior: HitTestBehavior.deferToChild,
            onPointerUp: (event) {
              setState(() {
                _isNeedCloseScheduleDetailPopup = false;
              });
            },
            child: _buildScheduleDetailPopup(scheduleDetailPopupKey),
          ),
        ),
      ],
    );
  }

  /// 只做容器而无需负责内容
  /// [trigger] 触发器的 key
  FWidget _buildMoreSchedulePopup(GlobalKey trigger) {
    final Size triggerSize = getWidgetSize(trigger);
    final Offset triggerOffset = getWidgetOffset(trigger);
    return FFlow(
      delegate: AutoAlignFlowDelegate(triggerOffset),
      children: [
        FContainer(
          decoration: _popupBoxDecoration,
          width: max(triggerSize.width, _moreSchedulePopupMinWidth),
          child: MoreSchedulePopup(
            scheduleData: popupLayerController.currMoreScheduleData,
          ),
        ),
      ],
    );
  }

  /// 只做容器而无需负责内容
  /// [trigger] 触发器的 key
  FWidget _buildScheduleDetailPopup(GlobalKey trigger) {
    final Size triggerSize = getWidgetSize(trigger);
    final Offset triggerOffset = getWidgetOffset(trigger);
    return FFlow(
      delegate: ScheduleAutoAlignFlowDelegate(triggerOffset, triggerSize),
      children: [
        FContainer(
          padding: const EdgeInsets.symmetric(
              horizontal: _scheduleDetailPopupHorizontalPadding),
          width: _scheduleDetailPopupWidth,
          child: FContainer(
            decoration: _popupBoxDecoration,
            child: ConsultationSchedulePopup(
              scheduleData: popupLayerController.currScheduleData,
              onClose: () {
                setState(() {
                  _isShowScheduleDetailPopup = false;
                });
                popupLayerController.onCloseSchedulePopup.emit(this, null);
              },
            ),
          ),
        ),
      ],
    );
  }

  /// 通过组件的 key 获取对应的组件的大小信息
  Size getWidgetSize(GlobalKey key) {
    try {
      final RenderBox renderBox =
          key.currentContext?.findRenderObject() as RenderBox;
      return renderBox.size;
    } catch (e) {
      return Size.zero;
    }
  }

  /// 通过组件的 key 获取对应的组件在弹出层的位置
  Offset getWidgetOffset(GlobalKey key) {
    try {
      final RenderBox boxContainer =
          moreSchedulePopupContainerKey.currentContext?.findRenderObject()
              as RenderBox;
      final Offset containerOffset = boxContainer
          .localToGlobal(Offset.zero)
          .translate(-_popupLayerMarginLeft, -_popupLayerMarginTop);
      final RenderBox renderBox =
          key.currentContext?.findRenderObject() as RenderBox;
      return renderBox.localToGlobal(Offset.zero).translate(
          -_popupLayerMarginLeft - containerOffset.dx,
          -_popupLayerMarginTop - containerOffset.dy);
    } catch (e) {
      return Offset.zero;
    }
  }
}

/// 自动对齐委托
class AutoAlignFlowDelegate extends FlowDelegate {
  final Offset triggerOffset;
  AutoAlignFlowDelegate(this.triggerOffset);

  @override
  void paintChildren(FlowPaintingContext context) {
    final Size containerSize = context.size;
    for (int i = 0; i < context.childCount; i++) {
      final Size childSize = context.getChildSize(i) ?? Size.zero;
      double x = triggerOffset.dx;
      double y = triggerOffset.dy;
      if (containerSize.height - y < childSize.height) {
        y = containerSize.height - childSize.height;
      }
      if (containerSize.width - x < childSize.width) {
        x = containerSize.width - childSize.width;
      }
      context.paintChild(i, transform: Matrix4.translationValues(x, y, 0));
    }
  }

  @override
  bool shouldRepaint(AutoAlignFlowDelegate oldDelegate) {
    return oldDelegate != this;
  }
}

/// 日程详情框自动对齐委托
class ScheduleAutoAlignFlowDelegate extends FlowDelegate {
  /// 日程详情弹出框位置不够时需要向下偏移的距离
  static const double _scheduleDetailPopupDownOffset = 10;

  final Offset triggerOffset;
  final Size triggerSize;
  ScheduleAutoAlignFlowDelegate(this.triggerOffset, this.triggerSize);
  @override
  void paintChildren(FlowPaintingContext context) {
    final Size containerSize = context.size;
    for (int i = 0; i < context.childCount; i++) {
      final Size childSize = context.getChildSize(i) ?? Size.zero;
      double x = triggerOffset.dx;
      double y = triggerOffset.dy;
      if (containerSize.height - y < childSize.height) {
        y = containerSize.height - childSize.height;
      }
      if (containerSize.width - x - triggerSize.width < childSize.width) {
        x = x - childSize.width;
        if (x < 0) {
          x = 0;
          y += triggerSize.height + _scheduleDetailPopupDownOffset;
          if (containerSize.height - y < childSize.height) {
            y = containerSize.height - childSize.height;
          }
        }
      } else {
        x = x + triggerSize.width;
      }
      context.paintChild(i, transform: Matrix4.translationValues(x, y, 0));
    }
  }

  @override
  bool shouldRepaint(ScheduleAutoAlignFlowDelegate oldDelegate) {
    return oldDelegate != this;
  }
}
