// ChainDeltaMark — the Ch∆In signature element. A precise triangle
// (∆) drawn from primitives, not a font glyph. Three states:
//
// - idle: static, accent colour, soft glow
// - live: gentle pulse, like a heartbeat
// - busy: rotates slowly, used while a long operation runs
//
// Sized small. Lives in the navigation rail header so it's
// always visible and identifies the brand without screaming.

import 'dart:math';

import 'package:flutter/material.dart';

enum ChainDeltaMode { idle, live, busy }

class ChainDeltaMark extends StatefulWidget {
  final ChainDeltaMode mode;
  final double size;
  final Color color;

  const ChainDeltaMark({
    super.key,
    required this.color,
    this.mode = ChainDeltaMode.idle,
    this.size = 36,
  });

  @override
  State<ChainDeltaMark> createState() => _FaiDeltaMarkState();
}

class _FaiDeltaMarkState extends State<ChainDeltaMark>
    with SingleTickerProviderStateMixin {
  late final AnimationController _ctrl;

  @override
  void initState() {
    super.initState();
    _ctrl = AnimationController(
      vsync: this,
      duration: _durationFor(widget.mode),
    );
    _restart();
  }

  Duration _durationFor(ChainDeltaMode m) {
    switch (m) {
      case ChainDeltaMode.idle:
        return const Duration(seconds: 1);
      case ChainDeltaMode.live:
        return const Duration(milliseconds: 1600);
      case ChainDeltaMode.busy:
        return const Duration(seconds: 4);
    }
  }

  void _restart() {
    _ctrl.duration = _durationFor(widget.mode);
    switch (widget.mode) {
      case ChainDeltaMode.idle:
        _ctrl.stop();
        _ctrl.value = 0;
        break;
      case ChainDeltaMode.live:
        _ctrl.repeat(reverse: true);
        break;
      case ChainDeltaMode.busy:
        _ctrl.repeat();
        break;
    }
  }

  @override
  void didUpdateWidget(covariant ChainDeltaMark old) {
    super.didUpdateWidget(old);
    if (old.mode != widget.mode) _restart();
  }

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

  @override
  Widget build(BuildContext context) {
    return AnimatedBuilder(
      animation: _ctrl,
      builder: (_, _) {
        return CustomPaint(
          size: Size.square(widget.size),
          painter: _DeltaPainter(
            color: widget.color,
            mode: widget.mode,
            t: _ctrl.value,
          ),
        );
      },
    );
  }
}

class _DeltaPainter extends CustomPainter {
  final Color color;
  final ChainDeltaMode mode;
  final double t;

  _DeltaPainter({required this.color, required this.mode, required this.t});

  @override
  void paint(Canvas canvas, Size size) {
    final cx = size.width / 2;
    final cy = size.height / 2;

    // In live mode: scale the whole mark between 0.85 and 1.15
    // so the pulse is visible without staring. Idle stays at 1.0.
    final scale = mode == ChainDeltaMode.live ? 0.85 + 0.30 * t : 1.0;
    final r = size.width * 0.36 * scale;

    canvas.save();
    canvas.translate(cx, cy);
    if (mode == ChainDeltaMode.busy) {
      canvas.rotate(t * 2 * pi);
    }

    // Outer triangle path.
    final path = Path()
      ..moveTo(0, -r)
      ..lineTo(r * cos(pi / 6), r * sin(pi / 6))
      ..lineTo(-r * cos(pi / 6), r * sin(pi / 6))
      ..close();

    // Glow halo. In live mode the glow ring grows with the pulse
    // and the alpha breathes harder.
    if (mode != ChainDeltaMode.idle) {
      final pulseStrength = mode == ChainDeltaMode.live ? t : 1.0;
      final glow = Paint()
        ..color = color.withValues(alpha: 0.30 + 0.40 * pulseStrength)
        ..maskFilter = MaskFilter.blur(BlurStyle.normal, 8 + 14 * pulseStrength)
        ..style = PaintingStyle.fill;
      canvas.drawPath(path, glow);
    }

    // Filled triangle, brighter on the up-beat for live mode.
    final fillAlpha = mode == ChainDeltaMode.live ? 0.15 + 0.20 * t : 0.18;
    final fill = Paint()
      ..color = color.withValues(alpha: fillAlpha)
      ..style = PaintingStyle.fill;
    canvas.drawPath(path, fill);

    // Outline stroke.
    final stroke = Paint()
      ..color = color
      ..strokeWidth = 2.2
      ..style = PaintingStyle.stroke
      ..strokeJoin = StrokeJoin.round;
    canvas.drawPath(path, stroke);

    // Inner accent dot.
    final dotAlpha = mode == ChainDeltaMode.live ? 0.55 + 0.45 * t : 1.0;
    final dot = Paint()
      ..color = color.withValues(alpha: dotAlpha)
      ..style = PaintingStyle.fill;
    canvas.drawCircle(Offset(0, r * 0.18), r * 0.16, dot);

    canvas.restore();
  }

  @override
  bool shouldRepaint(covariant _DeltaPainter old) =>
      old.t != t || old.mode != mode || old.color != color;
}
