// lib/editor/pdf/spike_app.dart
//
// THROWAWAY M1 spike app shell (plan §10). Wraps [SpikeEditorPane] with an
// on-screen frame-timing HUD (median build & raster ms over the last ~120
// frames) and an ink-load toggle, so MUST #4/#5 are observable on-device when
// launched via `flutter run -t lib/editor/pdf/spike_main.dart` on the tablet.

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

import 'spike_editor_pane.dart';

class SpikeApp extends StatelessWidget {
  const SpikeApp({super.key, required this.pdfPath, this.denseStrokesAsset});

  final String pdfPath;
  final String? denseStrokesAsset;

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'BadNote M1 Spike',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(useMaterial3: true, colorSchemeSeed: Colors.indigo),
      home: SpikeHome(
        pdfPath: pdfPath,
        denseStrokesAsset: denseStrokesAsset,
      ),
    );
  }
}

class SpikeHome extends StatefulWidget {
  const SpikeHome({super.key, required this.pdfPath, this.denseStrokesAsset});

  final String pdfPath;
  final String? denseStrokesAsset;

  @override
  State<SpikeHome> createState() => _SpikeHomeState();
}

class _SpikeHomeState extends State<SpikeHome> {
  final GlobalKey<SpikeEditorPaneState> _paneKey =
      GlobalKey<SpikeEditorPaneState>();
  final PdfViewerController _controller = PdfViewerController();
  bool _inkLoad = false;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Stack(
        children: [
          SpikeEditorPane(
            key: _paneKey,
            controller: _controller,
            pdfPath: widget.pdfPath,
            denseStrokesAsset: widget.denseStrokesAsset,
          ),
          const Positioned(top: 8, left: 8, child: FrameTimingHud()),
        ],
      ),
      floatingActionButton: Column(
        mainAxisSize: MainAxisSize.min,
        crossAxisAlignment: CrossAxisAlignment.end,
        children: [
          FloatingActionButton.extended(
            heroTag: 'inkload',
            onPressed: () async {
              final next = !_inkLoad;
              await _paneKey.currentState?.setInkLoad(next);
              setState(() => _inkLoad = next);
            },
            label: Text(_inkLoad ? 'Ink load: ON' : 'Ink load: OFF'),
            icon: const Icon(Icons.brush),
          ),
        ],
      ),
    );
  }
}

/// On-screen median build/raster frame-time HUD, driven by
/// [SchedulerBinding.addTimingsCallback]. Shows the median of the last
/// [_window] frames for both the build (`buildDuration`) and raster
/// (`rasterDuration`) phases — the two halves of the 16.6ms budget tracked by
/// MUST #4/#5.
class FrameTimingHud extends StatefulWidget {
  const FrameTimingHud({super.key});

  @override
  State<FrameTimingHud> createState() => _FrameTimingHudState();
}

class _FrameTimingHudState extends State<FrameTimingHud> {
  static const int _window = 120;
  final List<double> _build = <double>[];
  final List<double> _raster = <double>[];
  double _medBuild = 0;
  double _medRaster = 0;
  double _p95Build = 0;
  double _p95Raster = 0;

  @override
  void initState() {
    super.initState();
    SchedulerBinding.instance.addTimingsCallback(_onTimings);
  }

  @override
  void dispose() {
    SchedulerBinding.instance.removeTimingsCallback(_onTimings);
    super.dispose();
  }

  void _onTimings(List<FrameTiming> timings) {
    for (final t in timings) {
      _build.add(t.buildDuration.inMicroseconds / 1000.0);
      _raster.add(t.rasterDuration.inMicroseconds / 1000.0);
    }
    while (_build.length > _window) {
      _build.removeAt(0);
    }
    while (_raster.length > _window) {
      _raster.removeAt(0);
    }
    if (!mounted) return;
    setState(() {
      _medBuild = _percentile(_build, 50);
      _medRaster = _percentile(_raster, 50);
      _p95Build = _percentile(_build, 95);
      _p95Raster = _percentile(_raster, 95);
    });
  }

  static double _percentile(List<double> values, int p) {
    if (values.isEmpty) return 0;
    final sorted = List<double>.from(values)..sort();
    final idx = ((p / 100.0) * (sorted.length - 1)).round();
    return sorted[idx.clamp(0, sorted.length - 1)];
  }

  @override
  Widget build(BuildContext context) {
    Color budget(double ms) => ms <= 16.6
        ? Colors.greenAccent
        : (ms <= 22 ? Colors.amberAccent : Colors.redAccent);
    return IgnorePointer(
      child: Container(
        padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6),
        decoration: BoxDecoration(
          color: Colors.black.withValues(alpha: 0.65),
          borderRadius: BorderRadius.circular(8),
        ),
        child: DefaultTextStyle(
          style: const TextStyle(
            fontFamily: 'monospace',
            fontSize: 12,
            color: Colors.white,
          ),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            mainAxisSize: MainAxisSize.min,
            children: [
              Text('frames: ${_build.length}/$_window'),
              Text.rich(TextSpan(children: [
                const TextSpan(text: 'build  med '),
                TextSpan(
                    text: '${_medBuild.toStringAsFixed(1)}ms',
                    style: TextStyle(color: budget(_medBuild))),
                TextSpan(text: '  p95 ${_p95Build.toStringAsFixed(1)}ms'),
              ])),
              Text.rich(TextSpan(children: [
                const TextSpan(text: 'raster med '),
                TextSpan(
                    text: '${_medRaster.toStringAsFixed(1)}ms',
                    style: TextStyle(color: budget(_medRaster))),
                TextSpan(text: '  p95 ${_p95Raster.toStringAsFixed(1)}ms'),
              ])),
            ],
          ),
        ),
      ),
    );
  }
}
