import 'dart:math' as math;
import 'dart:ui' as ui;

import 'package:flame/components.dart';
import 'package:flutter/material.dart';

import '../../../../../core/network/card_images.dart';
import '../../../../../core/settings/app_settings.dart';
import '../../../../../core/theme/app_theme.dart';

// رنگ‌های مشترکِ میز (منبعِ واحد در AppColors).
const _gold = AppColors.gold;
const _goldDark = AppColors.goldDark;

/// میز: زمینِ لاجوردیِ نمدی در کلِ صفحه + یک «میزِ» مرکزی با قابِ طلاییِ دولایه.
/// اگر فرشی انتخاب شده باشد، سطحِ میز تصویرِ فرش است (بریده‌شده در شکلِ میز)؛
/// وگرنه سطحِ سرمه‌ایِ ترسیمی. کارت‌ها داخلِ همین ناحیه انداخته می‌شوند.
class Felt extends PositionComponent with HasGameReference {
  /// URL کاملِ تصویرِ فرش (از سرور)؛ خالی یعنی سطحِ ترسیمیِ کلاسیک (بدون تصویر).
  final String carpetUrl;
  Felt({this.carpetUrl = ''});

  Sprite? _carpetSprite;
  Sprite? _bgSprite; // پس‌زمینه‌ی نقاشی‌شده (اختیاری، قابلِ تعویض)

  bool get _hasCarpet => carpetUrl.isNotEmpty;

  @override
  Future<void> onLoad() async {
    if (_hasCarpet) {
      _carpetSprite = await CardImages.carpetByUrl(carpetUrl);
    }
    // پس‌زمینه‌ی سفارشی (تالار/کاخ): فایلِ assets/images/game_bg.jpg را بگذارید.
    // اگر نبود یا حالتِ کم‌مصرف باشد، به گرادیانِ لاجوردیِ پیش‌فرض برمی‌گردد.
    if (!AppSettings.I.lowGraphics.value) {
      try {
        _bgSprite = await Sprite.load('game_bg.jpg');
      } catch (_) {
        _bgSprite = null;
      }
    }
  }

  @override
  void render(Canvas canvas) {
    final w = game.size.x, h = game.size.y;
    final center = Offset(w / 2, h / 2);

    // ۱) پس‌زمینه: تصویرِ سفارشیِ نقاشی‌شده (اگر موجود باشد) یا گرادیانِ لاجوردیِ
    // پیش‌فرض. تصویر با پوششِ کامل (cover) کشیده و کمی تیره می‌شود تا کارت‌ها خوانا
    // بمانند و وینیتِ شعاعی هم رویش می‌آید تا لبه‌ها با تم جور شود.
    final full = Rect.fromLTWH(0, 0, w, h);
    final bg = _bgSprite;
    if (bg != null) {
      _drawCover(canvas, bg, w, h);
      canvas.drawRect(full, Paint()..color = const Color(0x66081428));
      canvas.drawRect(
        full,
        Paint()
          ..shader = RadialGradient(
            center: Alignment.center,
            radius: 1.1,
            colors: const [Color(0x00000000), AppColors.lapisNight],
            stops: const [0.55, 1.0],
          ).createShader(full),
      );
    } else {
      canvas.drawRect(
        full,
        Paint()
          ..shader = RadialGradient(
            center: Alignment.center,
            radius: 1.0,
            colors: const [AppColors.lapisHi, AppColors.lapisNight],
            stops: const [0.5, 1.0],
          ).createShader(full),
      );
    }

    // ۲) میزِ مرکزی با قابِ طلایی.
    final rect = Rect.fromCenter(
        center: center, width: w * 0.72, height: h * 0.46);
    final radius = Radius.circular(h * 0.05);
    final table = RRect.fromRectAndRadius(rect, radius);

    // سایه‌ی نرمِ زیرِ میز (یک‌بار، نه هر-فریمی سنگین).
    canvas.drawRRect(
      table.shift(const Offset(0, 6)),
      Paint()
        ..color = const Color(0x66000000)
        ..maskFilter = const MaskFilter.blur(BlurStyle.normal, 12),
    );

    // قابِ طلاییِ بیرونی.
    canvas.drawRRect(
      RRect.fromRectAndRadius(rect.inflate(w * 0.012), radius),
      Paint()
        ..shader = const LinearGradient(
          begin: Alignment.topCenter,
          end: Alignment.bottomCenter,
          colors: [_gold, _goldDark],
        ).createShader(rect),
    );

    // سطحِ میز: تصویرِ فرش (بریده در شکلِ میز) یا سطحِ سرمه‌ایِ ترسیمی.
    final sprite = _carpetSprite;
    if (_hasCarpet && sprite != null) {
      canvas.save();
      canvas.clipRRect(table);
      // فرش را به‌صورتِ cover داخلِ مستطیلِ میز می‌کشیم.
      sprite.render(
        canvas,
        position: Vector2(rect.left, rect.top),
        size: Vector2(rect.width, rect.height),
      );
      // تیره‌ترِ ملایم برای خوانایی کارت‌ها روی فرش.
      canvas.drawRRect(table, Paint()..color = const Color(0x1A000000));
      canvas.restore();
    } else {
      canvas.drawRRect(
        table,
        Paint()
          ..shader = RadialGradient(
            center: Alignment.center,
            radius: 0.9,
            colors: const [AppColors.lapisLo, AppColors.lapisInk],
            stops: const [0.4, 1.0],
          ).createShader(rect),
      );
    }

    // نورِ نرمِ مرکزی (اسپاتلایت) برای برجسته‌شدنِ کارت‌های وسطِ میز.
    canvas.save();
    canvas.clipRRect(table);
    canvas.drawRect(
      rect,
      Paint()
        ..shader = RadialGradient(
          center: Alignment.center,
          radius: 0.62,
          colors: const [Color(0x1FFFFFFF), Color(0x00FFFFFF)],
          stops: const [0.0, 1.0],
        ).createShader(rect),
    );
    canvas.restore();

    // خطِ طلاییِ نازکِ داخلی (قابِ دولایه).
    canvas.drawRRect(
      RRect.fromRectAndRadius(rect.deflate(w * 0.018), Radius.circular(h * 0.04)),
      Paint()
        ..style = PaintingStyle.stroke
        ..strokeWidth = w * 0.004
        ..color = _gold.withValues(alpha: 0.65),
    );
  }

  // تصویرِ پس‌زمینه را با حفظِ نسبت، پوششِ کاملِ صفحه (cover) و مرکز-برش می‌کشد.
  void _drawCover(Canvas canvas, Sprite sprite, double w, double h) {
    final img = sprite.image;
    final iw = img.width.toDouble(), ih = img.height.toDouble();
    final scale = math.max(w / iw, h / ih);
    final dw = iw * scale, dh = ih * scale;
    sprite.render(
      canvas,
      position: Vector2((w - dw) / 2, (h - dh) / 2),
      size: Vector2(dw, dh),
    );
  }
}

/// ذراتِ طلاییِ معلق (اتمسفرِ سبک). چند نقطه‌ی کم‌رنگ که آرام بالا می‌روند و
/// چشمک می‌زنند؛ عمق می‌دهد بدونِ بارِ گرافیکیِ محسوس (بدونِ blur).
class Motes extends PositionComponent with HasGameReference {
  final int count;
  Motes({this.count = 12}) {
    priority = 1; // بالای Felt، زیرِ کارت‌ها (priority ۵)
  }

  final _rng = math.Random();
  double _t = 0;
  late final List<_Mote> _motes;

  @override
  Future<void> onLoad() async {
    _motes = List.generate(
      count,
      (_) => _Mote(
        x: _rng.nextDouble(),
        y: _rng.nextDouble(),
        r: 1.0 + _rng.nextDouble() * 1.8,
        speed: 0.006 + _rng.nextDouble() * 0.014,
        drift: (_rng.nextDouble() - 0.5) * 0.03,
        phase: _rng.nextDouble() * 6.28,
      ),
    );
  }

  @override
  void update(double dt) => _t += dt;

  @override
  void render(Canvas canvas) {
    final w = game.size.x, h = game.size.y;
    for (final m in _motes) {
      var y = (m.y - m.speed * _t) % 1.0;
      if (y < 0) y += 1;
      final xx = (m.x + m.drift * math.sin(_t * 0.3 + m.phase)) * w;
      final tw = (0.35 + 0.28 * math.sin(_t * 1.4 + m.phase)).clamp(0.0, 1.0);
      canvas.drawCircle(
        Offset(xx, y * h),
        m.r,
        Paint()..color = _gold.withValues(alpha: tw * 0.45),
      );
    }
  }
}

class _Mote {
  final double x, y, r, speed, drift, phase;
  _Mote({
    required this.x,
    required this.y,
    required this.r,
    required this.speed,
    required this.drift,
    required this.phase,
  });
}

/// دیسکِ فلزیِ شمارش (امتیاز تیم) با عددِ وسط؛ از ۰ تا ۷.
class ScorePuck extends PositionComponent {
  final int count;
  ScorePuck(this.count, {required double radius, super.position})
      : super(size: Vector2.all(radius * 2), anchor: Anchor.center);

  @override
  void render(Canvas canvas) {
    final r = size.x / 2;
    final c = Offset(r, r);
    canvas.drawCircle(c, r, Paint()..color = const Color(0xFF14110F));
    canvas.drawCircle(
      c,
      r * 0.92,
      Paint()
        ..style = PaintingStyle.stroke
        ..strokeWidth = r * 0.22
        ..color = _goldDark,
    );
    final tp = TextPainter(
      text: TextSpan(
        text: '$count',
        style: TextStyle(
          fontFamily: 'Dana',
          color: _gold,
          fontSize: r * 1.05,
          fontWeight: FontWeight.bold,
        ),
      ),
      textDirection: TextDirection.ltr,
    )..layout();
    tp.paint(canvas, c - Offset(tp.width / 2, tp.height / 2));
  }
}

/// افکت رعد روی زمین هنگام «بریدن با حکم»؛ پس از مدت کوتاهی خودش حذف می‌شود.
/// افکتِ بریدن با حکم: فلاشِ کوتاهِ صفحه + حلقه‌ی شوک‌ویوِ طلایی + جرقه‌ها.
/// همراهِ Lightning اضافه می‌شود تا بُرِش «قدرتمند» حس شود.
class CutBurst extends PositionComponent with HasGameReference {
  static const _max = 0.5;
  double _life = _max;
  final _rng = math.Random();
  late final List<_Spark> _sparks;

  @override
  Future<void> onLoad() async {
    size = game.size;
    _sparks = List.generate(16, (_) {
      final ang = _rng.nextDouble() * math.pi * 2;
      final spd = 0.10 + _rng.nextDouble() * 0.17;
      return _Spark(ang, spd, 1.5 + _rng.nextDouble() * 2.5);
    });
  }

  @override
  void update(double dt) {
    _life -= dt;
    if (_life <= 0) removeFromParent();
  }

  @override
  void render(Canvas canvas) {
    final t = (1 - _life / _max).clamp(0.0, 1.0); // پیشرفت ۰..۱
    final center = Offset(size.x / 2, size.y / 2);

    // ۱) فلاشِ کوتاهِ صفحه (فقط اوایل).
    final flash = (1 - t * 3).clamp(0.0, 1.0);
    if (flash > 0) {
      canvas.drawRect(
        Rect.fromLTWH(0, 0, size.x, size.y),
        Paint()..color = const Color(0xFFFFF3C4).withValues(alpha: flash * 0.45),
      );
    }

    final fade = (1 - t).clamp(0.0, 1.0);
    // ۲) حلقه‌ی شوک‌ویوِ طلایی که باز می‌شود.
    canvas.drawCircle(
      center,
      t * size.x * 0.55,
      Paint()
        ..style = PaintingStyle.stroke
        ..strokeWidth = size.x * 0.022 * fade
        ..color = _gold.withValues(alpha: fade * 0.8)
        ..maskFilter = const MaskFilter.blur(BlurStyle.normal, 4),
    );

    // ۳) جرقه‌های طلایی که به بیرون می‌پاشند.
    final sp = Paint()..color = const Color(0xFFFFF3C4).withValues(alpha: fade);
    for (final s in _sparks) {
      final d = s.speed * size.x * t;
      final p = center + Offset(math.cos(s.ang), math.sin(s.ang)) * d;
      canvas.drawCircle(p, s.r * fade, sp);
    }
  }
}

class _Spark {
  final double ang, speed, r;
  _Spark(this.ang, this.speed, this.r);
}

/// افکتِ آتش برای «بریدنِ پیاپیِ حکم» (کمبو: چند روبُریدنِ سریع در یک دست).
/// شعله‌هایی که از مرکزِ میز بالا می‌آیند + ذراتِ اخگرِ صعودی. هر چه شدتِ کمبو
/// بیشتر (تعدادِ بریدن) شعله بلندتر و پرحجم‌تر است.
class FireBurst extends PositionComponent with HasGameReference {
  /// شدت (۱..۳+): تعدادِ بریدنِ پیاپی؛ ارتفاع/حجمِ شعله را تعیین می‌کند.
  final int intensity;
  FireBurst({this.intensity = 3});

  static const _max = 1.15;
  double _life = _max;
  double _t = 0;
  final _rng = math.Random();
  late final List<_Ember> _embers;
  late final List<_Flame> _flames;

  double get _scale => (intensity.clamp(3, 6)) / 3.0; // ۱.۰ در ۳ بریدن، بیشتر با کمبو

  @override
  Future<void> onLoad() async {
    size = game.size;
    final n = (18 * _scale).round();
    _embers = List.generate(n, (_) {
      final spread = (_rng.nextDouble() - 0.5) * size.x * 0.34;
      final rise = 0.30 + _rng.nextDouble() * 0.55; // کسری از ارتفاعِ صعود
      final delay = _rng.nextDouble() * 0.35;
      return _Ember(spread, rise, delay, 1.5 + _rng.nextDouble() * 2.8);
    });
    final f = (5 * _scale).round();
    _flames = List.generate(f, (i) {
      final off = (_rng.nextDouble() - 0.5) * size.x * 0.22;
      final w = size.x * (0.07 + _rng.nextDouble() * 0.06);
      final h = size.x * (0.18 + _rng.nextDouble() * 0.12) * _scale;
      final ph = _rng.nextDouble() * math.pi * 2;
      return _Flame(off, w, h, ph);
    });
  }

  @override
  void update(double dt) {
    _t += dt;
    _life -= dt;
    if (_life <= 0) removeFromParent();
  }

  @override
  void render(Canvas canvas) {
    final prog = (1 - _life / _max).clamp(0.0, 1.0);
    // پاکتِ شدت: سریع بالا می‌آید، آرام محو می‌شود.
    final env = prog < 0.2 ? prog / 0.2 : (1 - (prog - 0.2) / 0.8);
    final base = Offset(size.x / 2, size.y * 0.56); // کفِ شعله (نزدیکِ مرکزِ میز)

    // ۱) هاله‌ی نارنجیِ گرم پشتِ شعله.
    canvas.drawCircle(
      base,
      size.x * 0.28 * env * _scale,
      Paint()
        ..color = const Color(0xFFFF7A18).withValues(alpha: 0.22 * env)
        ..maskFilter = MaskFilter.blur(BlurStyle.normal, size.x * 0.05),
    );

    // ۲) زبانه‌های شعله (نارنجی→زرد) با لرزشِ افقی.
    for (final fl in _flames) {
      final sway = math.sin(_t * 9 + fl.phase) * size.x * 0.02;
      final cx = base.dx + fl.off + sway;
      final h = fl.h * env;
      final tip = Offset(cx + sway * 0.6, base.dy - h);
      final path = Path()
        ..moveTo(cx - fl.w / 2, base.dy)
        ..quadraticBezierTo(cx - fl.w * 0.5, base.dy - h * 0.5, tip.dx, tip.dy)
        ..quadraticBezierTo(cx + fl.w * 0.5, base.dy - h * 0.5, cx + fl.w / 2, base.dy)
        ..close();
      canvas.drawPath(
        path,
        Paint()
          ..shader = _flameShader(base.dy, base.dy - h, env)
          ..maskFilter = MaskFilter.blur(BlurStyle.normal, size.x * 0.008),
      );
    }

    // ۳) اخگرهای صعودی.
    for (final e in _embers) {
      final lt = ((prog - e.delay) / (1 - e.delay)).clamp(0.0, 1.0);
      if (lt <= 0) continue;
      final y = base.dy - lt * size.y * 0.42 * e.rise * _scale;
      final x = base.dx + e.spread * lt + math.sin(lt * 8 + e.spread) * 3;
      final a = (1 - lt) * env;
      canvas.drawCircle(
        Offset(x, y),
        e.r * (1 - lt * 0.5),
        Paint()
          ..color = Color.lerp(
            const Color(0xFFFFE082),
            const Color(0xFFFF5722),
            lt,
          )!.withValues(alpha: a),
      );
    }
  }

  // گرادیانِ عمودیِ شعله: کفِ زرد/سفید (y0) → نوکِ نارنجیِ کم‌رنگ (y1).
  Shader _flameShader(double y0, double y1, double env) => ui.Gradient.linear(
        Offset(0, y0),
        Offset(0, y1),
        [
          const Color(0xFFFFF3C4).withValues(alpha: 0.95 * env),
          const Color(0xFFFFB300).withValues(alpha: 0.85 * env),
          const Color(0xFFFF5722).withValues(alpha: 0.15 * env),
        ],
        const [0.0, 0.45, 1.0],
      );
}

class _Ember {
  final double spread, rise, delay, r;
  _Ember(this.spread, this.rise, this.delay, this.r);
}

class _Flame {
  final double off, w, h, phase;
  _Flame(this.off, this.w, this.h, this.phase);
}

class Lightning extends PositionComponent with HasGameReference {
  static const _max = 0.55;
  double _life = _max;
  final _rng = math.Random();
  final List<List<Offset>> _bolts = [];

  @override
  Future<void> onLoad() async {
    size = game.size;
    final center = Offset(size.x / 2, size.y / 2);
    for (var i = 0; i < 3; i++) {
      // هر رعد یک خط شکسته از یک نقطه‌ی تصادفیِ بالا به سمت مرکز.
      final start =
          Offset(_rng.nextDouble() * size.x, _rng.nextDouble() * size.y * 0.4);
      final pts = <Offset>[start];
      const segs = 6;
      for (var s = 1; s <= segs; s++) {
        final t = s / segs;
        final base = Offset.lerp(start, center, t)!;
        final jitter = (1 - t) * size.x * 0.06;
        pts.add(base +
            Offset((_rng.nextDouble() - 0.5) * jitter,
                (_rng.nextDouble() - 0.5) * jitter));
      }
      _bolts.add(pts);
    }
  }

  @override
  void update(double dt) {
    _life -= dt;
    if (_life <= 0) removeFromParent();
  }

  @override
  void render(Canvas canvas) {
    final op = (_life / _max).clamp(0.0, 1.0);
    final glow = Paint()
      ..color = const Color(0xFFFFE082).withValues(alpha: op * 0.5)
      ..style = PaintingStyle.stroke
      ..strokeWidth = size.x * 0.02
      ..maskFilter = const MaskFilter.blur(BlurStyle.normal, 6);
    final core = Paint()
      ..color = const Color(0xFFFFFDE7).withValues(alpha: op)
      ..style = PaintingStyle.stroke
      ..strokeWidth = size.x * 0.006
      ..strokeCap = StrokeCap.round;
    for (final bolt in _bolts) {
      final path = Path()..moveTo(bolt.first.dx, bolt.first.dy);
      for (final p in bolt.skip(1)) {
        path.lineTo(p.dx, p.dy);
      }
      canvas.drawPath(path, glow);
      canvas.drawPath(path, core);
    }
  }
}
