import 'dart:ui';

import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';

import '../../../common/widgets/floating_menu_button.dart';

class VsyncBenchmarkScreen extends StatelessWidget {
  const VsyncBenchmarkScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return const Scaffold(
      body: Stack(
        children: [
          SizedBox(
            width: double.infinity,
            height: double.infinity,
            child: ShaderHomePage(),
          ),
          FloatingMenuButton(),
        ],
      ),
    );
  }
}

class ShaderHomePage extends StatefulWidget {
  const ShaderHomePage({super.key});

  @override
  State<ShaderHomePage> createState() => _ShaderHomePageState();
}

class _ShaderHomePageState extends State<ShaderHomePage>
    with SingleTickerProviderStateMixin {
  double delta = 0;
  FragmentShader? shader;

  late final Ticker _ticker;

  void loadMyShader() async {
    var program = await FragmentProgram.fromAsset('shaders/vsync.frag');
    shader = program.fragmentShader();
  }

  @override
  void initState() {
    super.initState();
    loadMyShader();
    _ticker = createTicker((elapsed) {
      setState(() {
        delta += 1 / 60;
      });
    });
    _ticker.start();
  }

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

  @override
  Widget build(BuildContext context) {
    if (shader == null) {
      return const Center(child: CircularProgressIndicator());
    } else {
      return Container(
          color: Colors.white,
          child: CustomPaint(painter: ShaderPainter(shader!, delta)));
    }
  }
}

class ShaderPainter extends CustomPainter {
  final FragmentShader shader;
  final double time;

  ShaderPainter(FragmentShader fragmentShader, this.time)
      : shader = fragmentShader;

  @override
  void paint(Canvas canvas, Size size) {
    final paint = Paint();
    shader.setFloat(0, size.width);
    shader.setFloat(1, size.height);
    shader.setFloat(2, time);
    paint.shader = shader;
    canvas.drawRect(Offset.zero & size, paint);
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) => true;
}
