import 'dart:async';
import 'dart:math' as math;

import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:mobile_scanner/mobile_scanner.dart';

class AppQrScannerDialog extends StatefulWidget {
  const AppQrScannerDialog({super.key});

  static Future<String?> show(BuildContext context) {
    return showGeneralDialog<String>(
      context: context,
      barrierDismissible: false,
      barrierLabel: MaterialLocalizations.of(context).modalBarrierDismissLabel,
      barrierColor: Colors.black,
      transitionDuration: const Duration(milliseconds: 180),
      pageBuilder: (dialogContext, animation, secondaryAnimation) {
        return const AppQrScannerDialog();
      },
      transitionBuilder: (context, animation, secondaryAnimation, child) {
        return FadeTransition(opacity: animation, child: child);
      },
    );
  }

  @override
  State<AppQrScannerDialog> createState() => _AppQrScannerDialogState();
}

class _AppQrScannerDialogState extends State<AppQrScannerDialog>
    with SingleTickerProviderStateMixin {
  late final MobileScannerController _controller;
  late final AnimationController _scanLineController;
  bool _hasScanned = false;

  @override
  void initState() {
    super.initState();
    _controller = MobileScannerController(
      detectionSpeed: DetectionSpeed.noDuplicates,
      facing: CameraFacing.back,
      formats: const [BarcodeFormat.qrCode],
      autoZoom: true,
    );
    _scanLineController = AnimationController(
      vsync: this,
      duration: const Duration(milliseconds: 1800),
    )..repeat(reverse: true);
  }

  @override
  void dispose() {
    _scanLineController.dispose();
    unawaited(_controller.dispose());
    super.dispose();
  }

  Future<void> _handleDetect(BarcodeCapture capture) async {
    if (_hasScanned || capture.barcodes.isEmpty) return;

    final value = capture.barcodes.first.rawValue;
    if (value == null || value.isEmpty) return;

    _hasScanned = true;
    final navigator = Navigator.of(context, rootNavigator: true);
    debugPrint('扫码结果: $value');
    if (!mounted) return;
    if (navigator.canPop()) {
      navigator.pop(value);
    }
    unawaited(_stopScanner());
  }

  void _handleDetectError(Object error, StackTrace stackTrace) {
    debugPrint('扫码识别失败: $error');
  }

  Future<void> _stopScanner() async {
    try {
      await _controller.stop();
    } catch (error) {
      debugPrint('停止扫码相机失败: $error');
    }
  }

  void _close() {
    if (!mounted) return;
    final navigator = Navigator.of(context, rootNavigator: true);
    if (navigator.canPop()) {
      navigator.pop();
    }
  }

  Rect _scanWindowFor(Size size) {
    final scanSize = math.min(size.width * 0.72, 300.w);
    final center = Offset(size.width / 2, size.height * 0.46);
    return Rect.fromCenter(center: center, width: scanSize, height: scanSize);
  }

  @override
  Widget build(BuildContext context) {
    return Material(
      color: Colors.black,
      child: LayoutBuilder(
        builder: (context, constraints) {
          final size = constraints.biggest;
          final scanWindow = _scanWindowFor(size);

          return Stack(
            children: [
              Positioned.fill(
                child: MobileScanner(
                  controller: _controller,
                  fit: BoxFit.cover,
                  onDetect: _handleDetect,
                  onDetectError: _handleDetectError,
                  errorBuilder: _buildCameraError,
                  placeholderBuilder: (_) => const ColoredBox(
                    color: Colors.black,
                    child: Center(
                      child: CircularProgressIndicator(color: Colors.white),
                    ),
                  ),
                ),
              ),
              Positioned.fill(
                child: CustomPaint(
                  painter: _ScannerOverlayPainter(scanWindow: scanWindow),
                ),
              ),
              _ScanLine(animation: _scanLineController, scanWindow: scanWindow),
              Positioned(
                left: 0,
                right: 0,
                top: 0,
                child: SafeArea(
                  bottom: false,
                  child: SizedBox(
                    height: 56.h,
                    child: Stack(
                      alignment: Alignment.center,
                      children: [
                        Align(
                          alignment: Alignment.centerLeft,
                          child: IconButton(
                            onPressed: _close,
                            icon: const Icon(Icons.close),
                            color: Colors.white,
                            tooltip: '关闭',
                          ),
                        ),
                        Text(
                          '扫一扫',
                          style: TextStyle(
                            color: Colors.white,
                            fontSize: 18.sp,
                            fontWeight: FontWeight.w600,
                          ),
                        ),
                      ],
                    ),
                  ),
                ),
              ),
              Positioned(
                top: scanWindow.bottom + 28.h,
                left: 24.w,
                right: 24.w,
                child: Text(
                  '将二维码放入框内，即可自动扫描',
                  textAlign: TextAlign.center,
                  style: TextStyle(
                    color: Colors.white.withValues(alpha: 0.86),
                    fontSize: 15.sp,
                    height: 1.4,
                  ),
                ),
              ),
            ],
          );
        },
      ),
    );
  }

  Widget _buildCameraError(BuildContext context, MobileScannerException error) {
    return ColoredBox(
      color: Colors.black,
      child: Center(
        child: Padding(
          padding: EdgeInsets.symmetric(horizontal: 32.w),
          child: Column(
            mainAxisSize: MainAxisSize.min,
            children: [
              Icon(
                Icons.camera_alt_outlined,
                color: Colors.white.withValues(alpha: 0.82),
                size: 44.r,
              ),
              SizedBox(height: 16.h),
              Text(
                '无法启动相机，请检查相机权限后重试',
                textAlign: TextAlign.center,
                style: TextStyle(
                  color: Colors.white,
                  fontSize: 16.sp,
                  height: 1.45,
                ),
              ),
              SizedBox(height: 8.h),
              Text(
                error.errorDetails?.message ?? error.errorCode.message,
                textAlign: TextAlign.center,
                style: TextStyle(
                  color: Colors.white.withValues(alpha: 0.58),
                  fontSize: 12.sp,
                  height: 1.35,
                ),
              ),
              SizedBox(height: 24.h),
              TextButton(
                onPressed: _close,
                style: TextButton.styleFrom(
                  foregroundColor: Colors.white,
                  side: BorderSide(color: Colors.white.withValues(alpha: 0.44)),
                ),
                child: const Text('关闭'),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

class _ScanLine extends StatelessWidget {
  const _ScanLine({required this.animation, required this.scanWindow});

  final Animation<double> animation;
  final Rect scanWindow;

  @override
  Widget build(BuildContext context) {
    return AnimatedBuilder(
      animation: animation,
      builder: (context, child) {
        final inset = 14.r;
        final top =
            scanWindow.top +
            inset +
            (scanWindow.height - inset * 2) * animation.value;

        return Positioned(
          left: scanWindow.left + inset,
          top: top,
          width: scanWindow.width - inset * 2,
          child: child!,
        );
      },
      child: Container(
        height: 2.h,
        decoration: BoxDecoration(
          color: const Color(0xFF1BD760),
          borderRadius: BorderRadius.circular(2.r),
          boxShadow: [
            BoxShadow(
              color: const Color(0xFF1BD760).withValues(alpha: 0.65),
              blurRadius: 12.r,
              spreadRadius: 2.r,
            ),
          ],
        ),
      ),
    );
  }
}

class _ScannerOverlayPainter extends CustomPainter {
  const _ScannerOverlayPainter({required this.scanWindow});

  final Rect scanWindow;

  @override
  void paint(Canvas canvas, Size size) {
    final overlayPaint = Paint()..color = Colors.black.withValues(alpha: 0.58);
    final outerPath = Path()..addRect(Offset.zero & size);
    final innerPath = Path()
      ..addRRect(RRect.fromRectAndRadius(scanWindow, Radius.circular(8.r)));
    final overlayPath = Path.combine(
      PathOperation.difference,
      outerPath,
      innerPath,
    );
    canvas.drawPath(overlayPath, overlayPaint);

    final borderPaint = Paint()
      ..color = Colors.white.withValues(alpha: 0.38)
      ..style = PaintingStyle.stroke
      ..strokeWidth = 1.r;
    canvas.drawRRect(
      RRect.fromRectAndRadius(scanWindow, Radius.circular(8.r)),
      borderPaint,
    );

    final cornerPaint = Paint()
      ..color = const Color(0xFF1BD760)
      ..style = PaintingStyle.stroke
      ..strokeCap = StrokeCap.round
      ..strokeWidth = 4.r;
    final cornerLength = 28.r;

    void drawCorner(Offset start, Offset horizontalEnd, Offset verticalEnd) {
      canvas
        ..drawLine(start, horizontalEnd, cornerPaint)
        ..drawLine(start, verticalEnd, cornerPaint);
    }

    drawCorner(
      scanWindow.topLeft,
      scanWindow.topLeft.translate(cornerLength, 0),
      scanWindow.topLeft.translate(0, cornerLength),
    );
    drawCorner(
      scanWindow.topRight,
      scanWindow.topRight.translate(-cornerLength, 0),
      scanWindow.topRight.translate(0, cornerLength),
    );
    drawCorner(
      scanWindow.bottomLeft,
      scanWindow.bottomLeft.translate(cornerLength, 0),
      scanWindow.bottomLeft.translate(0, -cornerLength),
    );
    drawCorner(
      scanWindow.bottomRight,
      scanWindow.bottomRight.translate(-cornerLength, 0),
      scanWindow.bottomRight.translate(0, -cornerLength),
    );
  }

  @override
  bool shouldRepaint(covariant _ScannerOverlayPainter oldDelegate) {
    return oldDelegate.scanWindow != scanWindow;
  }
}
