import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:guru_utils/log/log.dart';
import 'package:guru_utils/visual_feast/visual_feast_looper.dart';

/**
 * Created by Haoyi on 2022/7/5.
 */

abstract class Director {
  VisualFeastLooper? _looper;

  bool get isActive => _looper?.isActive == true;

  bool get isResumed => _looper?.isResumed == true;

  bool get isPaused => _looper?.isPaused == true;

  bool get isStarted => _looper?.isStarted == true;

  void _bind(VisualFeastLooper looper) {
    _looper = looper;
  }

  void _unbind() {
    _looper = null;
  }

  @mustCallSuper
  void start() {
    Log.d("looper start!");
    _looper?.start();
  }

  @mustCallSuper
  void pause() {
    _looper?.pause();
  }

  @mustCallSuper
  void resume() {
    _looper?.resume();
  }

  @mustCallSuper
  void stop() {
    _looper?.stop();
  }

  void resize(Size size) {}

  Future prepare() async {}

  void frameUpdate(double delta) {}

  void render(Canvas canvas) {}

  void dispose() {
    stop();
    _unbind();
  }
}

class _VisualFeastRenderBox extends RenderBox with WidgetsBindingObserver {
  final BuildContext context;

  final Director director;
  final bool autoStart;

  _VisualFeastRenderBox(this.context, this.director, {this.autoStart = false}) {
    director._bind(VisualFeastLooper(_looperCallback));
  }

  @override
  bool get sizedByParent => true;

  @override
  Size computeDryLayout(BoxConstraints constraints) => constraints.biggest;

  @override
  void performResize() {
    super.performResize();
    director.resize(constraints.biggest);
  }

  void start() {
    Log.d("looper start!");
    director.start();
  }

  void pause() {
    director.pause();
  }

  void resume() {
    director.resume();
  }

  void stop() {
    director.stop();
  }

  @override
  void attach(PipelineOwner owner) {
    super.attach(owner);
    Log.d("_VisualFeastRenderBox attach $autoStart");
    director.prepare();

    // if (autoStart) {
    //   start();
    // }

    Log.d("####### attach");
    _bindLifecycleListener();
  }

  @override
  void detach() {
    _unbindLifecycleListener();
    director.dispose();
    Log.d("####### detach");
    super.detach();
  }

  void _looperCallback(double dt) {
    if (!attached) {
      return;
    }
    // Log.d("####### frameUpdate");
    director.frameUpdate(dt);
    markNeedsPaint();
  }

  @override
  void paint(PaintingContext context, Offset offset) {
    context.canvas.save();
    context.canvas.translate(offset.dx, offset.dy);
    director.render(context.canvas);
    context.canvas.restore();
  }

  void _bindLifecycleListener() {
    WidgetsBinding.instance?.addObserver(this);
  }

  void _unbindLifecycleListener() {
    WidgetsBinding.instance?.removeObserver(this);
  }

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {}
}

class _VisualFeast extends LeafRenderObjectWidget {
  final Size size;
  final Director director;

  const _VisualFeast({required this.size, required this.director});

  void dispose() {
    director.dispose();
  }

  @override
  RenderBox createRenderObject(BuildContext context) {
    return RenderConstrainedBox(
        child: _VisualFeastRenderBox(context, director),
        additionalConstraints: BoxConstraints.expand(width: size.width, height: size.height));
  }
//
// @override
// void updateRenderObject(BuildContext context, RenderConstrainedBox renderBox) {
//   renderBox
//     ..child = _VisualFeastRenderBox(context, director)
//     ..additionalConstraints = BoxConstraints.expand(width: size.width, height: size.height);
// }
}

class VisualFeastWidget extends StatelessWidget {
  final Director director;

  const VisualFeastWidget({Key? key, required this.director}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(builder: (_, BoxConstraints constraints) {
      director.resize(constraints.biggest);
      return Stack(
        children: [
          _VisualFeast(size: constraints.biggest, director: director),
        ],
      );
    });
  }
}
