import 'dart:math' as math;
import 'package:flutter/material.dart';

/// Animation state of the robot avatar.
enum RobotState {
  idle,       // blue, gentle breathing
  thinking,   // orange, eyes spin
  executing,  // orange+, faster pulse
  speaking,   // cyan, mouth wave
  alert,      // red, flash
}

/// CustomPainter that draws a cute robot face.
/// All sizes are expressed as fractions of [size] so it scales cleanly.
class RobotPainter extends CustomPainter {
  final RobotState state;

  /// 0..1 — primary animation progress (breathing, spin, wave, flash)
  final double anim;

  /// 0..1 — blink progress (0=open, 1=closed)
  final double blink;

  const RobotPainter({
    required this.state,
    required this.anim,
    required this.blink,
  });

  // ── colour per state ────────────────────────────────────────────────────
  Color get _primary => switch (state) {
        RobotState.idle => const Color(0xFF6366F1),
        RobotState.thinking => const Color(0xFFF59E0B),
        RobotState.executing => const Color(0xFFF97316),
        RobotState.speaking => const Color(0xFF0EA5E9),
        RobotState.alert => const Color(0xFFEF4444),
      };

  Color get _glow => _primary.withOpacity(0.35 + 0.2 * anim);

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

    // ── halo / glow ring ────────────────────────────────────────────────
    final glowRadius = w * 0.46 + w * 0.06 * anim;
    canvas.drawCircle(
      Offset(cx, h * 0.52),
      glowRadius,
      Paint()
        ..color = _glow
        ..maskFilter = const MaskFilter.blur(BlurStyle.normal, 12),
    );

    // ── antenna ─────────────────────────────────────────────────────────
    final antennaBaseX = cx;
    final antennaBaseY = h * 0.22;
    final antennaTipY = h * 0.06;

    // stick
    canvas.drawLine(
      Offset(antennaBaseX, antennaBaseY),
      Offset(antennaBaseX, antennaTipY + w * 0.04),
      Paint()
        ..color = _primary
        ..strokeWidth = w * 0.04
        ..strokeCap = StrokeCap.round,
    );
    // ball at tip
    final ballRadius = w * 0.065;
    final ballGlow = ballRadius * (1.0 + 0.3 * anim);
    canvas.drawCircle(
      Offset(antennaBaseX, antennaTipY),
      ballGlow,
      Paint()
        ..color = _primary.withOpacity(0.35)
        ..maskFilter = const MaskFilter.blur(BlurStyle.normal, 4),
    );
    canvas.drawCircle(
      Offset(antennaBaseX, antennaTipY),
      ballRadius,
      Paint()..color = _primary,
    );

    // ── head ────────────────────────────────────────────────────────────
    final headRect = RRect.fromRectAndRadius(
      Rect.fromCenter(
        center: Offset(cx, h * 0.40),
        width: w * 0.70,
        height: h * 0.34,
      ),
      Radius.circular(w * 0.15),
    );
    canvas.drawRRect(
      headRect,
      Paint()..color = const Color(0xFF1E293B),
    );
    canvas.drawRRect(
      headRect,
      Paint()
        ..color = _primary
        ..style = PaintingStyle.stroke
        ..strokeWidth = w * 0.04,
    );

    // ── eyes ─────────────────────────────────────────────────────────────
    _drawEyes(canvas, size);

    // ── mouth ────────────────────────────────────────────────────────────
    _drawMouth(canvas, size);

    // ── body ─────────────────────────────────────────────────────────────
    final bodyRect = RRect.fromRectAndRadius(
      Rect.fromCenter(
        center: Offset(cx, h * 0.80),
        width: w * 0.62,
        height: h * 0.25,
      ),
      Radius.circular(w * 0.10),
    );
    canvas.drawRRect(
      bodyRect,
      Paint()..color = const Color(0xFF1E293B),
    );
    canvas.drawRRect(
      bodyRect,
      Paint()
        ..color = _primary.withOpacity(0.6)
        ..style = PaintingStyle.stroke
        ..strokeWidth = w * 0.03,
    );

    // little chest dot
    canvas.drawCircle(
      Offset(cx, h * 0.80),
      w * 0.05 * (1.0 + 0.4 * anim),
      Paint()..color = _primary,
    );
  }

  void _drawEyes(Canvas canvas, Size size) {
    final w = size.width;
    final h = size.height;

    final eyeY = h * 0.38;
    final eyeRadius = w * 0.09;
    final leftX = size.width * 0.34;
    final rightX = size.width * 0.66;

    for (final ex in [leftX, rightX]) {
      // eye background
      canvas.drawCircle(
        Offset(ex, eyeY),
        eyeRadius,
        Paint()..color = const Color(0xFF0F172A),
      );

      if (state == RobotState.thinking || state == RobotState.executing) {
        // spinning arc eye
        final sweepAngle = math.pi * 1.5;
        final startAngle = 2 * math.pi * anim;
        canvas.drawArc(
          Rect.fromCircle(center: Offset(ex, eyeY), radius: eyeRadius * 0.65),
          startAngle,
          sweepAngle,
          false,
          Paint()
            ..color = _primary
            ..strokeWidth = w * 0.03
            ..style = PaintingStyle.stroke
            ..strokeCap = StrokeCap.round,
        );
      } else {
        // normal eye with blink
        final openFraction = 1.0 - blink;
        final ey1 = eyeY - eyeRadius * 0.55 * openFraction;
        final ey2 = eyeY + eyeRadius * 0.55 * openFraction;

        if (openFraction < 0.1) {
          // fully closed — horizontal line
          canvas.drawLine(
            Offset(ex - eyeRadius * 0.5, eyeY),
            Offset(ex + eyeRadius * 0.5, eyeY),
            Paint()
              ..color = _primary
              ..strokeWidth = w * 0.025
              ..strokeCap = StrokeCap.round,
          );
        } else {
          // open eye — vertical oval
          canvas.drawOval(
            Rect.fromCenter(
              center: Offset(ex, eyeY),
              width: eyeRadius * 0.9,
              height: (ey2 - ey1).abs().clamp(4.0, eyeRadius * 1.2),
            ),
            Paint()..color = _primary,
          );
          // pupil highlight
          canvas.drawCircle(
            Offset(ex + eyeRadius * 0.2, eyeY - eyeRadius * 0.2),
            eyeRadius * 0.15,
            Paint()..color = Colors.white.withOpacity(0.8),
          );
        }
      }
    }
  }

  void _drawMouth(Canvas canvas, Size size) {
    final w = size.width;
    final h = size.height;
    final mouthY = h * 0.47;
    final mouthLeft = size.width * 0.36;
    final mouthRight = size.width * 0.64;

    if (state == RobotState.speaking) {
      // wave mouth
      final path = Path();
      path.moveTo(mouthLeft, mouthY);
      final segments = 4;
      final segW = (mouthRight - mouthLeft) / segments;
      for (int i = 0; i < segments; i++) {
        final x1 = mouthLeft + segW * i;
        final x2 = mouthLeft + segW * (i + 1);
        final phase = anim * 2 * math.pi + i * math.pi / 2;
        final cy1 = mouthY + math.sin(phase) * h * 0.04;
        final cy2 = mouthY + math.sin(phase + math.pi / 2) * h * 0.04;
        path.cubicTo(
          x1 + segW * 0.33, cy1,
          x2 - segW * 0.33, cy2,
          x2, mouthY,
        );
      }
      canvas.drawPath(
        path,
        Paint()
          ..color = _primary
          ..strokeWidth = w * 0.035
          ..style = PaintingStyle.stroke
          ..strokeCap = StrokeCap.round,
      );
    } else if (state == RobotState.alert) {
      // zigzag / frown
      final flashOpacity = (0.5 + 0.5 * math.sin(anim * 2 * math.pi)).clamp(0.0, 1.0);
      canvas.drawLine(
        Offset(mouthLeft, mouthY),
        Offset(mouthRight, mouthY),
        Paint()
          ..color = _primary.withOpacity(flashOpacity)
          ..strokeWidth = w * 0.035
          ..strokeCap = StrokeCap.round,
      );
    } else {
      // smile / neutral arc
      final smileDepth = state == RobotState.idle ? h * 0.025 : h * 0.01;
      final path = Path();
      path.moveTo(mouthLeft, mouthY);
      path.quadraticBezierTo(
        (mouthLeft + mouthRight) / 2,
        mouthY + smileDepth,
        mouthRight,
        mouthY,
      );
      canvas.drawPath(
        path,
        Paint()
          ..color = _primary.withOpacity(0.8)
          ..strokeWidth = w * 0.035
          ..style = PaintingStyle.stroke
          ..strokeCap = StrokeCap.round,
      );
    }
  }

  @override
  bool shouldRepaint(RobotPainter old) =>
      old.state != state || old.anim != anim || old.blink != blink;
}