import 'package:flutter/material.dart';
import 'package:flut/flut/native.dart';
import 'package:flut/flut/runtime.dart';
import 'package:flut/flutter/widgets/framework.dart';

class FlutStatefulWidget extends StatefulWidget {
  final String flutId;
  final String className;
  final FlutNative native;
  final FlutRuntime runtime;

  const FlutStatefulWidget({
    required this.flutId,
    required this.className,
    required this.native,
    required this.runtime,
    super.key,
  });

  @override
  State<FlutStatefulWidget> createState() => _FlutStatefulWidgetState();
}

class _FlutStatefulWidgetState extends State<FlutStatefulWidget>
    implements FlutState {
  late final String _stableFlutId;

  @override
  void initState() {
    super.initState();
    _stableFlutId = widget.flutId;
    widget.native.stateRegistry[_stableFlutId] = this;
  }

  @override
  void didUpdateWidget(FlutStatefulWidget oldWidget) {
    super.didUpdateWidget(oldWidget);
  }

  @override
  void dispose() {
    widget.native.stateRegistry.remove(_stableFlutId);
    // Notify Python to clean up state_registry and widget_registry
    widget.native.invokeNativeNoWaitSync('state_dispose', {
      'id': _stableFlutId,
    });
    super.dispose();
  }

  @override
  void updateFromPython(Map<String, dynamic>? newSubtree) {
    // Just trigger rebuild - build() will fetch fresh data from Python
    setState(() {});
  }

  @override
  Widget build(BuildContext context) {
    final contextWrapper = widget.runtime.wrapObject<FlutBuildContext>(
      context,
      (oid) => FlutBuildContext.wrap(
        runtime: widget.runtime,
        oid: oid,
        target: context,
      ),
    );
    final contextOid = contextWrapper.flutOid;

    try {
      final request = <String, dynamic>{
        'id': _stableFlutId,
        'contextOid': contextOid,
      };
      if (widget.flutId != _stableFlutId) {
        request['newWidgetId'] = widget.flutId;
      }
      final subtree = widget.native.invokeNativeSync('widget_build', request);

      if (subtree == null) {
        debugPrint('widget_build returned null for id ${widget.flutId}');
        return ErrorWidget.withDetails(message: 'widget_build returned null');
      }

      if (subtree['_flut_error'] != null) {
        debugPrint(
          'widget_build returned error for id ${widget.flutId}: ${subtree['_flut_error']}',
        );
        return ErrorWidget.withDetails(
          message: subtree['_flut_error'].toString(),
        );
      }

      // Release dead objects first (safe - they can't be in current tree)
      widget.runtime.releaseOidsFromResponse(subtree);

      return widget.runtime.buildWidgetFromJson(subtree);
    } catch (e) {
      debugPrint('Exception in build for id ${widget.flutId}: $e');
      return ErrorWidget.withDetails(message: e.toString());
    } finally {
      widget.runtime.releaseObject(contextOid);
    }
  }
}

class FlutStatelessWidget extends StatelessWidget {
  final String flutId;
  final String className;
  final FlutNative native;
  final FlutRuntime runtime;

  const FlutStatelessWidget({
    required this.flutId,
    required this.className,
    required this.native,
    required this.runtime,
    super.key,
  });

  @override
  Widget build(BuildContext context) {
    final contextWrapper = runtime.wrapObject<FlutBuildContext>(
      context,
      (oid) =>
          FlutBuildContext.wrap(runtime: runtime, oid: oid, target: context),
    );
    final contextOid = contextWrapper.flutOid;

    try {
      final subtree = native.invokeNativeSync('widget_build', {
        'id': flutId,
        'contextOid': contextOid,
      });

      if (subtree == null) {
        debugPrint('widget_build returned null for id $flutId');
        return ErrorWidget.withDetails(message: 'widget_build returned null');
      }

      if (subtree['_flut_error'] != null) {
        debugPrint(
          'widget_build returned error for id $flutId: ${subtree['_flut_error']}',
        );
        return ErrorWidget.withDetails(
          message: subtree['_flut_error'].toString(),
        );
      }

      // Release dead objects first (safe - they can't be in current tree)
      runtime.releaseOidsFromResponse(subtree);

      return runtime.buildWidgetFromJson(subtree);
    } catch (e) {
      debugPrint('Exception in build for id $flutId: $e');
      return ErrorWidget.withDetails(message: e.toString());
    } finally {
      runtime.releaseObject(contextOid);
    }
  }
}
