import 'package:flutter/material.dart';
import 'package:mobile_scanner/mobile_scanner.dart';
import 'package:qrscanner/models/auth_session.dart';
import 'package:qrscanner/models/pass_code.dart';
import 'package:qrscanner/models/scan_response.dart';
import 'package:qrscanner/services/feedback_service.dart';
import 'package:qrscanner/services/pass_code_service.dart';
import 'package:qrscanner/theme/app_theme.dart';

enum _ScanPhase { scanning, processing, success, warning }

const double _scanWindowSize = 260;
const double _scanWindowRadius = 28;
const Alignment _scanWindowAlignment = Alignment(0, -0.12);

class ScannerScreen extends StatefulWidget {
  const ScannerScreen({
    super.key,
    required this.session,
  });

  final AuthSession session;

  @override
  State<ScannerScreen> createState() => _ScannerScreenState();
}

class _ScannerScreenState extends State<ScannerScreen>
    with TickerProviderStateMixin {
  final _scannerController = MobileScannerController(
    detectionSpeed: DetectionSpeed.normal,
    detectionTimeoutMs: 500,
    facing: CameraFacing.back,
    formats: const [BarcodeFormat.qrCode],
    autoZoom: true,
  );
  final _passCodeService = PassCodeService();
  final _feedbackService = FeedbackService();

  _ScanPhase _phase = _ScanPhase.scanning;
  bool _isHandlingDetection = false;
  String? _lastScannedCode;
  String? _message;
  PassCode? _passCode;

  late final AnimationController _scanLineController;
  late final AnimationController _resultController;
  late final Animation<double> _scanLineAnimation;
  late final Animation<double> _scaleAnimation;
  late final Animation<Offset> _arrowSlide;

  @override
  void initState() {
    super.initState();
    _scanLineController = AnimationController(
      vsync: this,
      duration: const Duration(milliseconds: 2400),
    )..repeat();
    _scanLineAnimation = CurvedAnimation(
      parent: _scanLineController,
      curve: Curves.easeInOut,
    );

    _resultController = AnimationController(
      vsync: this,
      duration: const Duration(milliseconds: 700),
    );
    _scaleAnimation = CurvedAnimation(
      parent: _resultController,
      curve: Curves.elasticOut,
    );
    _arrowSlide = Tween<Offset>(
      begin: const Offset(0, -0.35),
      end: Offset.zero,
    ).animate(CurvedAnimation(
      parent: _resultController,
      curve: Curves.easeOutBack,
    ));
  }

  Rect _scanWindowRect(Size size) {
    final center = _scanWindowAlignment.alongSize(size);
    return Rect.fromCenter(
      center: center,
      width: _scanWindowSize,
      height: _scanWindowSize,
    );
  }

  @override
  void dispose() {
    _scanLineController.dispose();
    _resultController.dispose();
    _scannerController.dispose();
    _feedbackService.dispose();
    super.dispose();
  }

  Future<void> _onDetect(BarcodeCapture capture) async {
    if (_phase != _ScanPhase.scanning || _isHandlingDetection) return;

    final rawValue = capture.barcodes.firstOrNull?.rawValue?.trim();
    if (rawValue == null || rawValue.isEmpty) return;

    final code = _extractCode(rawValue);
    if (code.isEmpty || code == _lastScannedCode) return;

    _isHandlingDetection = true;
    setState(() {
      _phase = _ScanPhase.processing;
      _lastScannedCode = code;
      _message = null;
      _passCode = null;
    });

    _scanLineController.stop();
    await _scannerController.stop();
    await _feedbackService.onCodeDetected();

    try {
      final response = await _passCodeService.scan(
        session: widget.session,
        code: code,
      );

      if (!mounted) return;
      await _showResult(response);
    } catch (_) {
      if (!mounted) return;
      await _showResult(
        const ScanResponse(
          success: false,
          message: 'No se pudo validar el código. Revisa la conexión.',
        ),
      );
    } finally {
      _isHandlingDetection = false;
    }
  }

  String _extractCode(String rawValue) {
    final uri = Uri.tryParse(rawValue);
    if (uri != null) {
      final queryCode = uri.queryParameters['code'];
      if (queryCode != null && queryCode.isNotEmpty) return queryCode;

      final segments = uri.pathSegments.where((s) => s.isNotEmpty).toList();
      if (segments.isNotEmpty) return segments.last;
    }
    return rawValue;
  }

  Future<void> _showResult(ScanResponse response) async {
    _resultController.reset();

    setState(() {
      _message = response.message;
      _passCode = response.passCode;
      _phase = response.success ? _ScanPhase.success : _ScanPhase.warning;
    });

    if (response.success) {
      await _feedbackService.onSuccess();
    } else {
      await _feedbackService.onWarning();
    }

    await _resultController.forward();
  }

  Future<void> _scanAgain() async {
    _resultController.reset();
    _isHandlingDetection = false;
    setState(() {
      _phase = _ScanPhase.scanning;
      _lastScannedCode = null;
      _message = null;
      _passCode = null;
    });
    _scanLineController.repeat();
    await _scannerController.start();
  }

  @override
  Widget build(BuildContext context) {
    final isSuccess = _phase == _ScanPhase.success;
    final isWarning = _phase == _ScanPhase.warning;
    final overlayColor = isSuccess
        ? AppTheme.success.withValues(alpha: 0.82)
        : isWarning
            ? AppTheme.warning.withValues(alpha: 0.82)
            : Colors.transparent;

    return Scaffold(
      backgroundColor: Colors.black,
      extendBodyBehindAppBar: true,
      appBar: AppBar(
        backgroundColor: Colors.transparent,
        elevation: 0,
        leading: IconButton(
          icon: const Icon(Icons.arrow_back_rounded),
          onPressed: () => Navigator.of(context).pop(),
        ),
        title: const Text('Escanear pase'),
        centerTitle: true,
      ),
      body: Stack(
        fit: StackFit.expand,
        children: [
          if (_phase == _ScanPhase.scanning || _phase == _ScanPhase.processing)
            LayoutBuilder(
              builder: (context, constraints) {
                final scanRect = _scanWindowRect(constraints.biggest);
                return MobileScanner(
                  controller: _scannerController,
                  onDetect: _onDetect,
                  scanWindow: scanRect,
                  overlayBuilder: (context, constraints) {
                    if (_phase != _ScanPhase.scanning) {
                      return const SizedBox.shrink();
                    }

                    return AnimatedBuilder(
                      animation: _scanLineAnimation,
                      builder: (context, child) {
                        return CustomPaint(
                          size: constraints.biggest,
                          painter: _ScannerOverlayPainter(
                            scanRect: scanRect,
                            scanLineProgress: _scanLineAnimation.value,
                          ),
                        );
                      },
                    );
                  },
                );
              },
            ),
          if (_phase != _ScanPhase.scanning && _phase != _ScanPhase.processing)
            Container(color: AppTheme.backgroundDark),
          AnimatedContainer(
            duration: const Duration(milliseconds: 450),
            curve: Curves.easeOutCubic,
            color: overlayColor,
          ),
          if (_phase == _ScanPhase.processing)
            SafeArea(
              child: Center(child: _buildProcessingCard()),
            ),
          if (_phase == _ScanPhase.success || _phase == _ScanPhase.warning)
            SafeArea(
              child: Center(
                child: SingleChildScrollView(
                  padding: const EdgeInsets.symmetric(vertical: 16),
                  child: _buildResultCard(),
                ),
              ),
            ),
          if (_phase == _ScanPhase.scanning)
            SafeArea(
              child: Align(
                alignment: Alignment.bottomCenter,
                child: Padding(
                  padding: const EdgeInsets.fromLTRB(32, 0, 32, 28),
                  child: _buildHint(),
                ),
              ),
            ),
        ],
      ),
    );
  }

  Widget _buildProcessingCard() {
    return Container(
      margin: const EdgeInsets.symmetric(horizontal: 28),
      padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 28),
      decoration: BoxDecoration(
        color: AppTheme.surfaceDark.withValues(alpha: 0.92),
        borderRadius: BorderRadius.circular(24),
        border: Border.all(color: Colors.white.withValues(alpha: 0.08)),
      ),
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          const SizedBox(
            width: 42,
            height: 42,
            child: CircularProgressIndicator(
              strokeWidth: 3,
              color: AppTheme.primary,
            ),
          ),
          const SizedBox(height: 18),
          Text(
            'Validando código...',
            style: Theme.of(context).textTheme.titleMedium?.copyWith(
                  fontWeight: FontWeight.w600,
                ),
          ),
          if (_lastScannedCode != null) ...[
            const SizedBox(height: 8),
            Text(
              _lastScannedCode!,
              style: TextStyle(
                color: Colors.white.withValues(alpha: 0.45),
                letterSpacing: 1.2,
              ),
            ),
          ],
        ],
      ),
    );
  }

  Widget _buildResultCard() {
    final isSuccess = _phase == _ScanPhase.success;
    final accent = isSuccess ? AppTheme.success : AppTheme.warning;
    final accentDark = isSuccess ? AppTheme.successDark : AppTheme.warningDark;

    return FadeTransition(
      opacity: _scaleAnimation,
      child: ScaleTransition(
        scale: _scaleAnimation,
        child: Container(
          margin: const EdgeInsets.symmetric(horizontal: 24),
          padding: const EdgeInsets.fromLTRB(24, 32, 24, 24),
          decoration: BoxDecoration(
            gradient: LinearGradient(
              begin: Alignment.topLeft,
              end: Alignment.bottomRight,
              colors: [
                accent.withValues(alpha: 0.95),
                accentDark.withValues(alpha: 0.95),
              ],
            ),
            borderRadius: BorderRadius.circular(28),
            boxShadow: [
              BoxShadow(
                color: accent.withValues(alpha: 0.45),
                blurRadius: 32,
                offset: const Offset(0, 12),
              ),
            ],
          ),
          child: Column(
            mainAxisSize: MainAxisSize.min,
            children: [
              SlideTransition(
                position: _arrowSlide,
                child: Container(
                  width: 88,
                  height: 88,
                  decoration: BoxDecoration(
                    color: Colors.white.withValues(alpha: 0.18),
                    shape: BoxShape.circle,
                  ),
                  child: Icon(
                    isSuccess
                        ? Icons.arrow_downward_rounded
                        : Icons.warning_amber_rounded,
                    size: isSuccess ? 52 : 46,
                    color: Colors.white,
                  ),
                ),
              ),
              const SizedBox(height: 20),
              Text(
                isSuccess ? '¡Pase válido!' : 'No se pudo validar',
                style: const TextStyle(
                  fontSize: 24,
                  fontWeight: FontWeight.bold,
                  color: Colors.white,
                ),
              ),
              if (!isSuccess && (_message?.isNotEmpty ?? false)) ...[
                const SizedBox(height: 10),
                Text(
                  _message!,
                  textAlign: TextAlign.center,
                  style: TextStyle(
                    fontSize: 15,
                    height: 1.4,
                    color: Colors.white.withValues(alpha: 0.92),
                  ),
                ),
              ],
              if (isSuccess && _passCode != null) ...[
                const SizedBox(height: 20),
                Container(
                  width: double.infinity,
                  padding: const EdgeInsets.all(16),
                  decoration: BoxDecoration(
                    color: Colors.black.withValues(alpha: 0.18),
                    borderRadius: BorderRadius.circular(16),
                  ),
                  child: Column(
                    children: [
                      _detailRow('Nombre', _passCode!.name),
                      const SizedBox(height: 8),
                      _detailRow('Código', _passCode!.code),
                    ],
                  ),
                ),
              ],
              const SizedBox(height: 24),
              SizedBox(
                width: double.infinity,
                child: FilledButton.icon(
                  onPressed: _scanAgain,
                  icon: const Icon(Icons.qr_code_scanner_rounded),
                  label: const Text('Escanear otro'),
                  style: FilledButton.styleFrom(
                    backgroundColor: Colors.white,
                    foregroundColor: accentDark,
                    padding: const EdgeInsets.symmetric(vertical: 16),
                    shape: RoundedRectangleBorder(
                      borderRadius: BorderRadius.circular(14),
                    ),
                  ),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }

  Widget _detailRow(String label, String value) {
    return Row(
      children: [
        Text(
          '$label: ',
          style: TextStyle(
            color: Colors.white.withValues(alpha: 0.7),
            fontSize: 14,
          ),
        ),
        Expanded(
          child: Text(
            value,
            textAlign: TextAlign.end,
            style: const TextStyle(
              color: Colors.white,
              fontWeight: FontWeight.w600,
              fontSize: 14,
            ),
          ),
        ),
      ],
    );
  }

  Widget _buildHint() {
    return Padding(
      padding: const EdgeInsets.symmetric(horizontal: 32),
      child: Text(
        'Apunta la cámara al código QR del pase',
        textAlign: TextAlign.center,
        style: TextStyle(
          color: Colors.white.withValues(alpha: 0.65),
          fontSize: 14,
        ),
      ),
    );
  }
}

class _ScannerOverlayPainter extends CustomPainter {
  _ScannerOverlayPainter({
    required this.scanRect,
    required this.scanLineProgress,
  });

  final Rect scanRect;
  final double scanLineProgress;

  static const double _cornerLength = 36;
  static const double _cornerStroke = 4;

  @override
  void paint(Canvas canvas, Size size) {
    final cutout = RRect.fromRectAndRadius(
      scanRect,
      const Radius.circular(_scanWindowRadius),
    );

    final background = Path()..addRect(Offset.zero & size);
    final hole = Path()..addRRect(cutout);
    final overlay = Path.combine(PathOperation.difference, background, hole);

    canvas.drawPath(
      overlay,
      Paint()..color = Colors.black.withValues(alpha: 0.55),
    );

    final borderPaint = Paint()
      ..color = AppTheme.primary.withValues(alpha: 0.35)
      ..style = PaintingStyle.stroke
      ..strokeWidth = 1.5;
    canvas.drawRRect(cutout, borderPaint);

    final cornerPaint = Paint()
      ..color = AppTheme.primary
      ..style = PaintingStyle.stroke
      ..strokeWidth = _cornerStroke
      ..strokeCap = StrokeCap.round;

    _drawCorners(canvas, scanRect, cornerPaint);

    final lineY = scanRect.top +
        _scanWindowRadius +
        (scanRect.height - _scanWindowRadius * 2) * scanLineProgress;
    final linePaint = Paint()
      ..shader = LinearGradient(
        colors: [
          AppTheme.primary.withValues(alpha: 0),
          AppTheme.primary.withValues(alpha: 0.85),
          AppTheme.primary.withValues(alpha: 0),
        ],
        stops: const [0, 0.5, 1],
      ).createShader(
        Rect.fromLTWH(scanRect.left + 16, lineY - 1, scanRect.width - 32, 2),
      )
      ..strokeWidth = 2
      ..strokeCap = StrokeCap.round;

    canvas.drawLine(
      Offset(scanRect.left + 16, lineY),
      Offset(scanRect.right - 16, lineY),
      linePaint,
    );
  }

  void _drawCorners(Canvas canvas, Rect rect, Paint paint) {
    const r = _scanWindowRadius;
    const len = _cornerLength;

    canvas.drawLine(
      Offset(rect.left + r, rect.top),
      Offset(rect.left + r + len, rect.top),
      paint,
    );
    canvas.drawLine(
      Offset(rect.left, rect.top + r),
      Offset(rect.left, rect.top + r + len),
      paint,
    );

    canvas.drawLine(
      Offset(rect.right - r - len, rect.top),
      Offset(rect.right - r, rect.top),
      paint,
    );
    canvas.drawLine(
      Offset(rect.right, rect.top + r),
      Offset(rect.right, rect.top + r + len),
      paint,
    );

    canvas.drawLine(
      Offset(rect.left + r, rect.bottom),
      Offset(rect.left + r + len, rect.bottom),
      paint,
    );
    canvas.drawLine(
      Offset(rect.left, rect.bottom - r - len),
      Offset(rect.left, rect.bottom - r),
      paint,
    );

    canvas.drawLine(
      Offset(rect.right - r - len, rect.bottom),
      Offset(rect.right - r, rect.bottom),
      paint,
    );
    canvas.drawLine(
      Offset(rect.right, rect.bottom - r - len),
      Offset(rect.right, rect.bottom - r),
      paint,
    );
  }

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