import 'package:flame/components.dart';
import 'package:flame/effects.dart';
import 'package:flame/events.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart' show HapticFeedback;

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

/// یک کارت روی میز؛ اگر تصویر `assets/images/cards/<code>.png` موجود باشد از آن
/// استفاده می‌کند، وگرنه نسخه‌ی برداری می‌کشد. برای پشت کارت `back.jpg`.
/// کارت‌های قابل‌بازی فقط با **کشیدن (drag)** به سمت زمین بازی می‌شوند (نه tap).
class CardComponent extends PositionComponent
    with DragCallbacks, HasGameReference {
  final String code; // مثل "AS"؛ برای پشت کارت خالی
  final String skin; // اسکینِ کارت؛ تصاویر از backend بارگذاری می‌شوند
  bool faceUp; // قابلِ تغییر: برای انیمیشنِ برگرداندنِ کارت هنگام پخش
  VoidCallback? onPlay; // در صورت مجاز بودن، بازیِ این کارت
  bool dimmed; // کارت غیرمجاز/غیرفعال
  Vector2? home; // موقعیت اصلی در دست (برای برگشت پس از کشیدنِ ناقص)
  double homeAngle = 0; // زاویه‌ی بادبزنیِ کارت در دست (برای برگشت پس از کشیدن)
  bool highlight = false; // کارتِ برنده‌ی دست ⇒ درخششِ طلایی پیش از جمع‌شدن
  int restPriority = 0; // ترتیب لایه‌ی اصلی در دست (برای بازگردانی پس از کشیدن)
  Rect? dropZone; // ناحیه‌ی وسط میز؛ رهاکردن کارت در آن یعنی بازی
  Sprite? _front;
  Sprite? _back;
  bool _dragging = false;
  bool _overZone = false; // کارت روی ناحیه‌ی انداختن است (برای هایلایت)

  CardComponent({
    required this.code,
    required this.faceUp,
    this.skin = 'simple',
    this.onPlay,
    this.dimmed = false,
    super.position,
    super.size,
    super.angle,
    super.priority,
    super.anchor = Anchor.center,
  });

  bool get _playable => onPlay != null && !dimmed;

  @override
  Future<void> onLoad() async {
    // اگر تصویر از قبل در حافظه آماده باشد (از کشِ دیسک/preload)، همان لحظه ست می‌شود
    // ⇒ کارت با تصویرِ درست و بدونِ پرش رندر می‌شود. وگرنه بدونِ مسدودکردنِ رندر در
    // پس‌زمینه بارگذاری و به‌محضِ آماده‌شدن جای‌گزین می‌شود (نسخه‌ی برداری تا آن لحظه).
    if (code.isNotEmpty) {
      final cached = CardImages.cachedFront(skin, code);
      if (cached != null) {
        _front = cached;
      } else {
        CardImages.front(skin, code).then((s) {
          if (isMounted) _front = s;
        });
      }
    }
    final cb = CardImages.cachedBack(skin);
    if (cb != null) {
      _back = cb;
    } else {
      CardImages.back(skin).then((s) {
        if (isMounted) _back = s;
      });
    }
  }

  /// برگرداندنِ کارت از پشت به رو با انیمیشن (هنگام پخش‌شدن از روی دسته).
  void flipToFront({double delay = 0}) {
    if (faceUp) return;
    add(ScaleEffect.to(
      Vector2(0.04, scale.y == 0 ? 1 : scale.y),
      EffectController(duration: 0.13, startDelay: delay, curve: Curves.easeIn),
      onComplete: () {
        faceUp = true; // در لبه‌ی نازک، رو می‌شود
        add(ScaleEffect.to(
            Vector2(1, 1), EffectController(duration: 0.13, curve: Curves.easeOut)));
      },
    ));
  }

  // بزرگ‌نماییِ کارتِ انتخاب‌شده هنگام کشیدن (واضح‌تر برای دیدن).
  static const _dragScale = 1.4;

  void _scaleTo(double s) {
    children.whereType<ScaleEffect>().toList().forEach((e) => e.removeFromParent());
    add(ScaleEffect.to(
        Vector2.all(s), EffectController(duration: 0.12, curve: Curves.easeOut)));
  }

  // چرخاندنِ نرمِ کارت به زاویه‌ی مشخص (صاف‌کردن هنگام کشیدن، برگشت هنگام رها).
  void _rotateTo(double a) {
    children.whereType<RotateEffect>().toList().forEach((e) => e.removeFromParent());
    add(RotateEffect.to(
        a, EffectController(duration: 0.12, curve: Curves.easeOut)));
  }

  /// بازنشانیِ فوریِ مقیاس به اندازه‌ی عادی (هنگام بازی روی میز).
  void resetScale() {
    children.whereType<ScaleEffect>().toList().forEach((e) => e.removeFromParent());
    scale = Vector2.all(1);
  }

  /// یک «پاپِ» کوتاه (بزرگ‌نماییِ رفت‌وبرگشتی) برای کارتِ برنده‌ی دست.
  void pulse() {
    children.whereType<ScaleEffect>().toList().forEach((e) => e.removeFromParent());
    add(ScaleEffect.to(
      Vector2.all(1.16),
      EffectController(duration: 0.18, alternate: true, curve: Curves.easeOut),
    ));
  }

  @override
  void onDragStart(DragStartEvent event) {
    super.onDragStart(event);
    if (!_playable) return;
    _dragging = true;
    priority = 1000; // روی همه‌ی کارت‌ها
    _scaleTo(_dragScale); // بزرگ‌نماییِ نرم هنگام انتخاب
    _rotateTo(0); // صاف‌شدن: کارت دیگر با زاویه‌ی بادبزنیِ دست کشیده نمی‌شود
  }

  @override
  void onDragUpdate(DragUpdateEvent event) {
    if (!_dragging) return;
    // canvasDelta (فضای صفحه) نه localDelta: مستقل از چرخش/مقیاسِ خودِ کارت است،
    // پس کارت دقیقاً به‌دنبالِ انگشت می‌آید نه روی مسیرِ منحنیِ قوسِ دست.
    position += event.canvasDelta;
    _overZone = _inDropZone();
  }

  @override
  void onDragEnd(DragEndEvent event) {
    super.onDragEnd(event);
    if (!_dragging) return;
    _dragging = false;
    // فقط اگر داخل ناحیه‌ی وسط میز رها شد ⇒ بازی (اندازه به حالت عادی)؛
    // وگرنه برگشت به جای مرتبِ خود.
    if (_inDropZone()) {
      resetScale();
      HapticFeedback.selectionClick(); // بازخوردِ لمسیِ بازیِ کارت
      onPlay?.call();
    } else {
      _scaleTo(1);
      _returnHome();
    }
    _overZone = false;
  }

  @override
  void onDragCancel(DragCancelEvent event) {
    super.onDragCancel(event);
    if (!_dragging) return;
    _dragging = false;
    _overZone = false;
    _scaleTo(1);
    _returnHome();
  }

  bool _inDropZone() {
    final z = dropZone;
    if (z != null) return z.contains(position.toOffset());
    return position.y < game.size.y * 0.72; // fallback
  }

  void _returnHome() {
    priority = restPriority; // بازگردانی ترتیب لایه تا روی کارت‌های دیگر نیفتد
    _rotateTo(homeAngle); // بازگشت به زاویه‌ی بادبزنیِ دست
    if (home == null) return;
    add(MoveToEffect(home!, EffectController(duration: 0.2, curve: Curves.easeOut)));
  }

  @override
  void render(Canvas canvas) {
    final rect = size.toRect();
    final radius = Radius.circular(size.x * 0.09);
    final rrect = RRect.fromRectAndRadius(rect, radius);

    // سایه‌ی سبک و ارزان (بدون blurِ هر-فریمی) فقط برای کارت‌های رو ⇒ عمق بدون افت کارایی.
    // (drawShadow هر فریم برای ده‌ها کارت بسیار سنگین بود و باعث لگ می‌شد.)
    if (faceUp) {
      final off = _dragging ? size.x * 0.10 : size.x * 0.03;
      canvas.drawRRect(rrect.shift(Offset(off * 0.4, off)),
          Paint()..color = Color(_dragging ? 0x66000000 : 0x44000000));
    }

    final sprite = faceUp ? _front : _back;
    if (sprite != null) {
      canvas.save();
      canvas.clipRRect(rrect);
      sprite.render(canvas, size: size);
      canvas.restore();
    } else if (faceUp) {
      _drawVectorFace(canvas, rrect);
    } else {
      _drawVectorBack(canvas, rrect);
    }

    // براقیتِ ملایم از بالا فقط برای کارت‌های رو.
    if (faceUp) {
      canvas.save();
      canvas.clipRRect(rrect);
      canvas.drawRect(
        Rect.fromLTWH(0, 0, size.x, size.y * 0.5),
        Paint()
          ..shader = const LinearGradient(
            begin: Alignment.topCenter,
            end: Alignment.bottomCenter,
            colors: [Color(0x2BFFFFFF), Color(0x00FFFFFF)],
          ).createShader(Rect.fromLTWH(0, 0, size.x, size.y * 0.5)),
      );
      canvas.restore();
    }

    if (dimmed) {
      canvas.drawRRect(rrect, Paint()..color = const Color(0x73000000));
    }
    canvas.drawRRect(
      rrect,
      Paint()
        ..style = PaintingStyle.stroke
        ..strokeWidth = 1.5
        ..color = AppColors.suitDark,
    );

    // درخششِ طلاییِ کارتِ برنده‌ی دست (فقط یک کارت هم‌زمان ⇒ blur ارزان).
    if (highlight) {
      canvas.drawRRect(
        rrect,
        Paint()
          ..style = PaintingStyle.stroke
          ..strokeWidth = size.x * 0.07
          ..color = AppColors.gold
          ..maskFilter = const MaskFilter.blur(BlurStyle.normal, 6),
      );
    }

    // هایلایت طلایی: هنگام کشیدن همیشه (انتخاب)، و پررنگ‌تر روی ناحیه‌ی انداختن.
    if (_dragging) {
      canvas.drawRRect(
        rrect,
        Paint()
          ..style = PaintingStyle.stroke
          ..strokeWidth = size.x * (_overZone ? 0.06 : 0.035)
          ..color = AppColors.gold
          ..maskFilter = MaskFilter.blur(BlurStyle.normal, _overZone ? 6 : 3),
      );
    }
  }

  void _drawVectorBack(Canvas canvas, RRect rrect) {
    canvas.drawRRect(rrect, Paint()..color = const Color(0xFF1C3A66));
    final inner = rrect.deflate(size.x * 0.08);
    canvas.drawRRect(
      inner,
      Paint()
        ..style = PaintingStyle.stroke
        ..strokeWidth = 2
        ..color = AppColors.gold,
    );
  }

  void _drawVectorFace(Canvas canvas, RRect rrect) {
    canvas.drawRRect(rrect, Paint()..color = Colors.white);
    final rank = code.substring(0, code.length - 1);
    final suit = code.substring(code.length - 1);
    final (symbol, color) = _suit(suit);

    _text(canvas, '$rank$symbol', size.x * 0.26, color,
        Offset(size.x * 0.08, size.y * 0.05));
    // نماد بزرگ وسط
    _text(canvas, symbol, size.x * 0.5, color,
        Offset(size.x * 0.5, size.y * 0.5), center: true);
  }

  (String, Color) _suit(String s) {
    switch (s) {
      case 'H':
        return ('♥', AppColors.suitRed);
      case 'D':
        return ('♦', AppColors.suitRed);
      case 'C':
        return ('♣', AppColors.suitDark);
      default:
        return ('♠', AppColors.suitDark);
    }
  }

  void _text(Canvas canvas, String s, double fontSize, Color color, Offset at,
      {bool center = false}) {
    final tp = TextPainter(
      text: TextSpan(
          text: s, style: TextStyle(color: color, fontSize: fontSize)),
      textDirection: TextDirection.ltr,
    )..layout();
    final offset = center ? at - Offset(tp.width / 2, tp.height / 2) : at;
    tp.paint(canvas, offset);
  }
}
