import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_web/pages/space_management_v2/main_module/models/space_connection_model.dart';
import 'package:syncrow_web/pages/space_management_v2/main_module/painters/spaces_connections_arrow_painter.dart';
import 'package:syncrow_web/pages/space_management_v2/main_module/widgets/space_card_widget.dart';
import 'package:syncrow_web/pages/space_management_v2/main_module/widgets/space_cell.dart';
import 'package:syncrow_web/pages/space_management_v2/modules/communities/domain/models/community_model.dart';
import 'package:syncrow_web/pages/space_management_v2/modules/communities/domain/models/space_model.dart';
import 'package:syncrow_web/pages/space_management_v2/modules/communities/presentation/communities_tree_selection_bloc/communities_tree_selection_bloc.dart';
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/presentation/helpers/space_details_dialog_helper.dart';

class CommunityStructureCanvas extends StatefulWidget {
  const CommunityStructureCanvas({
    required this.community,
    required this.selectedSpace,
    super.key,
  });

  final CommunityModel community;
  final SpaceModel? selectedSpace;

  @override
  State<CommunityStructureCanvas> createState() => _CommunityStructureCanvasState();
}

class _CommunityStructureCanvasState extends State<CommunityStructureCanvas>
    with SingleTickerProviderStateMixin {
  final Map<String, Offset> _positions = {};
  final double _cardWidth = 150.0;
  final double _cardHeight = 90.0;
  final double _horizontalSpacing = 150.0;
  final double _verticalSpacing = 120.0;

  late TransformationController _transformationController;
  late AnimationController _animationController;

  @override
  void initState() {
    _transformationController = TransformationController();
    _animationController = AnimationController(
      vsync: this,
      duration: const Duration(milliseconds: 150),
    );
    super.initState();
  }

  @override
  void didUpdateWidget(covariant CommunityStructureCanvas oldWidget) {
    super.didUpdateWidget(oldWidget);
    if (widget.selectedSpace?.uuid != oldWidget.selectedSpace?.uuid) {
      WidgetsBinding.instance.addPostFrameCallback((_) {
        if (mounted) {
          _animateToSpace(widget.selectedSpace);
        }
      });
    }
  }

  @override
  void dispose() {
    _transformationController.dispose();
    _animationController.dispose();
    super.dispose();
  }

  Set<String> _getAllDescendantUuids(SpaceModel space) {
    final uuids = <String>{};
    for (final child in space.children) {
      uuids.add(child.uuid);
      uuids.addAll(_getAllDescendantUuids(child));
    }
    return uuids;
  }

  void _runAnimation(Matrix4 target) {
    final animation = Matrix4Tween(
      begin: _transformationController.value,
      end: target,
    ).animate(_animationController);

    void listener() {
      _transformationController.value = animation.value;
    }

    animation.addListener(listener);
    _animationController.forward(from: 0).whenCompleteOrCancel(() {
      animation.removeListener(listener);
    });
  }

  void _animateToSpace(SpaceModel? space) {
    if (space == null) {
      _runAnimation(Matrix4.identity());
      return;
    }

    final position = _positions[space.uuid];
    if (position == null) return;

    const scale = 1.5;
    final viewSize = context.size;
    if (viewSize == null) return;

    final x = -position.dx * scale + (viewSize.width / 2) - (_cardWidth * scale / 2);
    final y =
        -position.dy * scale + (viewSize.height / 2) - (_cardHeight * scale / 2);

    final matrix = Matrix4.identity()
      ..translate(x, y)
      ..scale(scale);

    _runAnimation(matrix);
  }

  void _onSpaceTapped(SpaceModel? space) {
    context.read<CommunitiesTreeSelectionBloc>().add(
          SelectSpaceEvent(community: widget.community, space: space),
        );
  }

  void _resetSelectionAndZoom() {
    context.read<CommunitiesTreeSelectionBloc>().add(
          SelectSpaceEvent(
            community: widget.community,
            space: null,
          ),
        );
  }

  void _calculateLayout(
    List<SpaceModel> spaces,
    int depth,
    Map<int, double> levelXOffset,
  ) {
    for (final space in spaces) {
      double childSubtreeWidth = 0;
      if (space.children.isNotEmpty) {
        _calculateLayout(space.children, depth + 1, levelXOffset);
        final firstChildPos = _positions[space.children.first.uuid];
        final lastChildPos = _positions[space.children.last.uuid];
        if (firstChildPos != null && lastChildPos != null) {
          childSubtreeWidth = (lastChildPos.dx + _cardWidth) - firstChildPos.dx;
        }
      }

      final currentX = levelXOffset.putIfAbsent(depth, () => 0.0);
      double? x;

      if (space.children.isNotEmpty) {
        final firstChildPos = _positions[space.children.first.uuid]!;
        x = firstChildPos.dx + (childSubtreeWidth - _cardWidth) / 2;
      } else {
        x = currentX;
      }

      if (x < currentX) {
        final shiftX = currentX - x;
        _shiftSubtree(space, shiftX);
        final keysToShift = levelXOffset.keys.where((d) => d > depth).toList();
        for (final key in keysToShift) {
          levelXOffset[key] = levelXOffset[key]! + shiftX;
        }
        x += shiftX;
      }

      final y = depth * (_verticalSpacing + _cardHeight);
      _positions[space.uuid] = Offset(x, y);
      levelXOffset[depth] = x + _cardWidth + _horizontalSpacing;
    }
  }

  void _shiftSubtree(SpaceModel space, double shiftX) {
    if (_positions.containsKey(space.uuid)) {
      _positions[space.uuid] = _positions[space.uuid]!.translate(shiftX, 0);
    }
    for (final child in space.children) {
      _shiftSubtree(child, shiftX);
    }
  }

  List<Widget> _buildTreeWidgets() {
    _positions.clear();
    final community = widget.community;

    _calculateLayout(community.spaces, 0, {});

    final selectedSpace = widget.selectedSpace;
    final highlightedUuids = <String>{};
    if (selectedSpace != null) {
      highlightedUuids.add(selectedSpace.uuid);
      highlightedUuids.addAll(_getAllDescendantUuids(selectedSpace));
    }

    final widgets = <Widget>[];
    final connections = <SpaceConnectionModel>[];
    _generateWidgets(community.spaces, widgets, connections, highlightedUuids);

    return [
      CustomPaint(
        painter: SpacesConnectionsArrowPainter(
          connections: connections,
          positions: _positions,
          highlightedUuids: highlightedUuids,
        ),
        child: Stack(alignment: AlignmentDirectional.center, children: widgets),
      ),
    ];
  }

  void _generateWidgets(
    List<SpaceModel> spaces,
    List<Widget> widgets,
    List<SpaceConnectionModel> connections,
    Set<String> highlightedUuids,
  ) {
    for (final space in spaces) {
      final position = _positions[space.uuid];
      if (position == null) continue;

      final isHighlighted = highlightedUuids.contains(space.uuid);
      final hasNoSelectedSpace = widget.selectedSpace == null;

      widgets.add(
        Positioned(
          left: position.dx,
          top: position.dy,
          width: _cardWidth,
          height: _cardHeight,
          child: SpaceCardWidget(
            buildSpaceContainer: () {
              return Opacity(
                opacity: hasNoSelectedSpace || isHighlighted ? 1.0 : 0.5,
                child: Tooltip(
                  message: space.spaceName,
                  preferBelow: false,
                  child: SpaceCell(
                    onTap: () => _onSpaceTapped(space),
                    icon: space.icon,
                    name: space.spaceName,
                  ),
                ),
              );
            },
            onTap: () => SpaceDetailsDialogHelper.showCreate(context),
          ),
        ),
      );

      for (final child in space.children) {
        connections.add(
          SpaceConnectionModel(from: space.uuid, to: child.uuid),
        );
      }
      _generateWidgets(space.children, widgets, connections, highlightedUuids);
    }
  }

  @override
  Widget build(BuildContext context) {
    final treeWidgets = _buildTreeWidgets();
    return InteractiveViewer(
      transformationController: _transformationController,
      boundaryMargin: EdgeInsets.symmetric(
        horizontal: MediaQuery.sizeOf(context).width * 0.3,
        vertical: MediaQuery.sizeOf(context).height * 0.3,
      ),
      minScale: 0.5,
      maxScale: 3.0,
      constrained: false,
      child: GestureDetector(
        onTap: _resetSelectionAndZoom,
        child: SizedBox(
          width: MediaQuery.sizeOf(context).width * 5,
          height: MediaQuery.sizeOf(context).height * 5,
          child: Stack(children: treeWidgets),
        ),
      ),
    );
  }
}
