import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:mobile_scanner/mobile_scanner.dart';
import '../../../domain/entities/tour.dart';
import '../../blocs/scan/scan_bloc.dart';
import 'scan_result_sheet.dart';

class ScanPage extends StatefulWidget {
  final Tour tour;

  const ScanPage({
    super.key,
    required this.tour,
  });

  @override
  State<ScanPage> createState() => _ScanPageState();
}

class _ScanPageState extends State<ScanPage> with SingleTickerProviderStateMixin {
  late MobileScannerController controller;
  bool isFlashOn = false;
  bool isManualEntry = false;
  final TextEditingController barcodeController = TextEditingController();

  @override
  void initState() {
    super.initState();
    controller = MobileScannerController();
    
    // Initialize scan bloc with tour
    context.read<ScanBloc>().add(InitializeScan(widget.tour));
  }

  @override
  void dispose() {
    controller.dispose();
    barcodeController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    final theme = Theme.of(context);

    return Scaffold(
      backgroundColor: Colors.black,
      appBar: AppBar(
        backgroundColor: Colors.black.withValues(alpha: 128),
        elevation: 0,
        title: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text(
              widget.tour.locationName ?? 'Station',
              style: theme.textTheme.titleMedium?.copyWith(
                color: Colors.white,
                fontWeight: FontWeight.w600,
              ),
            ),
            Text(
              _getTypeLabel(widget.tour.type),
              style: theme.textTheme.bodySmall?.copyWith(
                color: Colors.white70,
              ),
            ),
          ],
        ),
        actions: [
          IconButton(
            onPressed: () {
              setState(() {
                isFlashOn = !isFlashOn;
                controller.toggleTorch();
              });
            },
            icon: Icon(
              isFlashOn
                  ? Icons.flashlight_on
                  : Icons.flashlight_off,
              color: Colors.white,
            ),
          ),
          IconButton(
            onPressed: () {
              controller.switchCamera();
            },
            icon: const Icon(
              Icons.flip_camera_android,
              color: Colors.white,
            ),
          ),
        ],
      ),
      body: BlocListener<ScanBloc, ScanState>(
        listener: (context, state) {
          if (state is ScanObjectDetected) {
            _showScanResult(context, state);
          } else if (state is ScanFehlKassetteDetected) {
            _showFehlKassetteDialog(context, state);
          } else if (state is ScanContainerObjectDetected) {
            _showContainerObjectResult(context, state);
          } else if (state is ScanContainerDetected) {
            _showContainerDetectedSnackBar(context, state);
          } else if (state is ScanContainerCloseDetected) {
            _showContainerCloseDialog(context, state);
          } else if (state is ScanUnknownObject) {
            _showUnknownObjectDialog(context, state);
          } else if (state is ScanPageDetected) {
            _showPageDetectedSnackBar(context, state);
          } else if (state is ScanObjectUpdated) {
            _showSuccessSnackBar(context, state);
          } else if (state is ScanObjectCreated) {
            _showObjectCreatedSnackBar(context, state);
          } else if (state is ScanError) {
            _showErrorSnackBar(context, state.message);
          }
        },
        child: Stack(
          fit: StackFit.expand,
          children: [
            // Camera Preview
            MobileScanner(
              controller: controller,
              onDetect: (capture) {
                final barcodes = capture.barcodes;
                if (barcodes.isNotEmpty && barcodes.first.rawValue != null) {
                  HapticFeedback.mediumImpact();
                  context.read<ScanBloc>().add(
                    ProcessBarcode(barcode: barcodes.first.rawValue!),
                  );
                }
              },
            ),

            // Scan Overlay
            CustomPaint(
              size: Size.infinite,
              painter: ScanOverlayPainter(),
            ),

            // Bottom Controls
            Positioned(
              bottom: 0,
              left: 0,
              right: 0,
              child: Container(
                padding: const EdgeInsets.all(24),
                decoration: BoxDecoration(
                  gradient: LinearGradient(
                    begin: Alignment.bottomCenter,
                    end: Alignment.topCenter,
                    colors: [
                      Colors.black.withValues(alpha: 230),
                      Colors.transparent,
                    ],
                  ),
                ),
                child: Column(
                  mainAxisSize: MainAxisSize.min,
                  children: [
                    Text(
                      'Barcode in den Rahmen halten',
                      style: theme.textTheme.bodyMedium?.copyWith(
                        color: Colors.white70,
                      ),
                    ),
                    const SizedBox(height: 24),
                    Row(
                      mainAxisAlignment: MainAxisAlignment.center,
                      children: [
                        // Manual Entry Button
                        ElevatedButton.icon(
                          onPressed: _showManualEntryDialog,
                          style: ElevatedButton.styleFrom(
                            backgroundColor: Colors.white,
                            foregroundColor: Colors.black,
                            padding: const EdgeInsets.symmetric(
                              horizontal: 24,
                              vertical: 12,
                            ),
                          ),
                          icon: const Icon(Icons.keyboard),
                          label: const Text('Manuelle Eingabe'),
                        ),
                      ],
                    ),
                  ],
                ),
              ),
            ),

            // Loading Overlay
            BlocBuilder<ScanBloc, ScanState>(
              builder: (context, state) {
                if (state is ScanProcessing) {
                  return Container(
                    color: Colors.black54,
                    child: const Center(
                      child: CircularProgressIndicator(color: Colors.white),
                    ),
                  );
                }
                return const SizedBox.shrink();
              },
            ),
          ],
        ),
      ),
    );
  }

  void _showScanResult(BuildContext context, ScanObjectDetected state) {
    showModalBottomSheet(
      context: context,
      isScrollControlled: true,
      backgroundColor: Colors.transparent,
      builder: (context) => ScanResultSheet(
        object: state.object,
        suggestedState: state.suggestedState,
        tour: state.tour,
        onConfirm: () {
          context.read<ScanBloc>().add(UpdateObjectState(
            object: state.object,
            newState: state.suggestedState,
          ));
          Navigator.pop(context);
        },
        onCancel: () {
          Navigator.pop(context);
        },
      ),
    );
  }

  void _showUnknownObjectDialog(BuildContext context, ScanUnknownObject state) {
    showDialog(
      context: context,
      builder: (context) => AlertDialog(
        title: const Text('Unbekanntes Objekt'),
        content: Column(
          mainAxisSize: MainAxisSize.min,
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text('Barcode: ${state.barcode}'),
            const SizedBox(height: 8),
            const Text(
              'Dieses Objekt ist nicht im System vorhanden. '
              'Möchten Sie es neu anlegen?',
            ),
          ],
        ),
        actions: [
          TextButton(
            onPressed: () => Navigator.pop(context),
            child: const Text('Abbrechen'),
          ),
          ElevatedButton(
            onPressed: () {
              Navigator.pop(context);
              // TODO: Navigate to create object page
            },
            child: const Text('Anlegen'),
          ),
        ],
      ),
    );
  }

  void _showPageDetectedSnackBar(BuildContext context, ScanPageDetected state) {
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(
        content: Text('Seite erkannt: ${state.label}'),
        backgroundColor: Colors.green,
        behavior: SnackBarBehavior.floating,
        action: SnackBarAction(
          label: 'OK',
          textColor: Colors.white,
          onPressed: () {},
        ),
      ),
    );
  }

  void _showSuccessSnackBar(BuildContext context, ScanObjectUpdated state) {
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(
        content: Text('Status aktualisiert: ${state.object.code}'),
        backgroundColor: Colors.green,
        behavior: SnackBarBehavior.floating,
        duration: const Duration(seconds: 2),
      ),
    );
  }

  void _showFehlKassetteDialog(BuildContext context, ScanFehlKassetteDetected state) {
    showDialog(
      context: context,
      builder: (context) => AlertDialog(
        title: const Text('Fehlkassette'),
        content: Text(
          'Die Kassette ${state.object.code} wird als Fehlkassette markiert. '
          'Der Status wird auf "Fehler - zur Dienststelle" geändert.',
        ),
        actions: [
          TextButton(
            onPressed: () => Navigator.pop(context),
            child: const Text('Abbrechen'),
          ),
          ElevatedButton(
            onPressed: () {
              context.read<ScanBloc>().add(UpdateObjectState(
                object: state.object,
                newState: state.suggestedState,
              ));
              Navigator.pop(context);
            },
            style: ElevatedButton.styleFrom(
              backgroundColor: Colors.red,
              foregroundColor: Colors.white,
            ),
            child: const Text('Bestätigen'),
          ),
        ],
      ),
    );
  }

  void _showContainerObjectResult(BuildContext context, ScanContainerObjectDetected state) {
    showModalBottomSheet(
      context: context,
      isScrollControlled: true,
      backgroundColor: Colors.transparent,
      builder: (context) => ScanResultSheet(
        object: state.object,
        suggestedState: state.suggestedState,
        tour: state.tour,
        containerInfo: 'Container: ${state.containerId} (${state.containerType == 'a' ? 'Geldinstitut' : 'Dienststelle'})',
        onConfirm: () {
          context.read<ScanBloc>().add(UpdateObjectState(
            object: state.object,
            newState: state.suggestedState,
            containerCode: state.containerId,
          ));
          Navigator.pop(context);
        },
        onCancel: () {
          Navigator.pop(context);
        },
      ),
    );
  }

  void _showContainerDetectedSnackBar(BuildContext context, ScanContainerDetected state) {
    final containerTypeLabel = state.containerType == 'a' ? 'Geldinstitut' : 'Dienststelle';
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(
        content: Text('Container erkannt: ${state.containerId} ($containerTypeLabel)'),
        backgroundColor: Colors.blue,
        behavior: SnackBarBehavior.floating,
        duration: const Duration(seconds: 3),
        action: SnackBarAction(
          label: 'OK',
          textColor: Colors.white,
          onPressed: () {
            context.read<ScanBloc>().add(UpdateObjectState(
              object: state.object,
              newState: state.suggestedState,
            ));
          },
        ),
      ),
    );
  }

  void _showContainerCloseDialog(BuildContext context, ScanContainerCloseDetected state) {
    final containerTypeLabel = state.containerType == 'a' ? 'Geldinstitut' : 'Dienststelle';
    showDialog(
      context: context,
      builder: (context) => AlertDialog(
        title: const Text('Container schließen'),
        content: Text(
          'Container ${state.object.code} ($containerTypeLabel) wird geschlossen. '
          'Alle enthaltenen Objekte werden auf den entsprechenden Status aktualisiert.',
        ),
        actions: [
          TextButton(
            onPressed: () => Navigator.pop(context),
            child: const Text('Abbrechen'),
          ),
          ElevatedButton(
            onPressed: () {
              context.read<ScanBloc>().add(UpdateObjectState(
                object: state.object,
                newState: state.suggestedState,
              ));
              Navigator.pop(context);
            },
            child: const Text('Schließen'),
          ),
        ],
      ),
    );
  }

  void _showObjectCreatedSnackBar(BuildContext context, ScanObjectCreated state) {
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(
        content: Text('Objekt erstellt: ${state.barcode}'),
        backgroundColor: Colors.green,
        behavior: SnackBarBehavior.floating,
        duration: const Duration(seconds: 2),
      ),
    );
  }

  void _showErrorSnackBar(BuildContext context, String message) {
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(
        content: Text(message),
        backgroundColor: Colors.red,
        behavior: SnackBarBehavior.floating,
      ),
    );
  }

  void _showManualEntryDialog() {
    showDialog(
      context: context,
      builder: (context) => AlertDialog(
        title: const Text('Barcode manuell eingeben'),
        content: TextField(
          controller: barcodeController,
          autofocus: true,
          decoration: const InputDecoration(
            hintText: 'Barcode eingeben',
            border: OutlineInputBorder(),
          ),
          textCapitalization: TextCapitalization.characters,
        ),
        actions: [
          TextButton(
            onPressed: () {
              barcodeController.clear();
              Navigator.pop(context);
            },
            child: const Text('Abbrechen'),
          ),
          ElevatedButton(
            onPressed: () {
              if (barcodeController.text.isNotEmpty) {
                context.read<ScanBloc>().add(
                  ProcessBarcode(barcode: barcodeController.text),
                );
                barcodeController.clear();
                Navigator.pop(context);
              }
            },
            child: const Text('Suchen'),
          ),
        ],
      ),
    );
  }

  String _getTypeLabel(String type) {
    switch (type) {
      case 'stock_start':
        return 'Lager - Beladung';
      case 'stock_end':
        return 'Lager - Rückgabe';
      case 'start':
        return 'Dienststelle';
      case 'st':
        return 'Haltestelle';
      case 'hls':
        return 'Hochbahnstation';
      case 'fsa':
        return 'Fahrscheinautomat';
      case 'vs':
        return 'Versorgungsstelle';
      case 'gi':
        return 'Geldinstitut';
      default:
        return type;
    }
  }
}

class ScanOverlayPainter extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    final paint = Paint()
      ..color = Colors.black.withValues(alpha: 128)
      ..style = PaintingStyle.fill;

    final scanAreaSize = size.width * 0.7;
    final scanAreaLeft = (size.width - scanAreaSize) / 2;
    final scanAreaTop = (size.height - scanAreaSize) / 2;

    // Draw dark overlay
    final path = Path()
      ..addRect(Rect.fromLTWH(0, 0, size.width, size.height));

    final cutout = Path()
      ..addRRect(RRect.fromRectAndRadius(
        Rect.fromLTWH(scanAreaLeft, scanAreaTop, scanAreaSize, scanAreaSize),
        const Radius.circular(20),
      ));

    final overlayPath = Path.combine(
      PathOperation.difference,
      path,
      cutout,
    );

    canvas.drawPath(overlayPath, paint);

    // Draw corner markers
    final markerPaint = Paint()
      ..color = Colors.white
      ..style = PaintingStyle.stroke
      ..strokeWidth = 4;

    final cornerLength = scanAreaSize * 0.15;
    const cornerRadius = 20.0;

    // Top-left corner
    _drawCorner(
      canvas,
      Offset(scanAreaLeft, scanAreaTop),
      cornerLength,
      markerPaint,
      true,
      true,
      cornerRadius,
    );

    // Top-right corner
    _drawCorner(
      canvas,
      Offset(scanAreaLeft + scanAreaSize, scanAreaTop),
      cornerLength,
      markerPaint,
      false,
      true,
      cornerRadius,
    );

    // Bottom-left corner
    _drawCorner(
      canvas,
      Offset(scanAreaLeft, scanAreaTop + scanAreaSize),
      cornerLength,
      markerPaint,
      true,
      false,
      cornerRadius,
    );

    // Bottom-right corner
    _drawCorner(
      canvas,
      Offset(scanAreaLeft + scanAreaSize, scanAreaTop + scanAreaSize),
      cornerLength,
      markerPaint,
      false,
      false,
      cornerRadius,
    );
  }

  void _drawCorner(
    Canvas canvas,
    Offset position,
    double length,
    Paint paint,
    bool isLeft,
    bool isTop,
    double radius,
  ) {
    final path = Path();

    if (isLeft && isTop) {
      path.moveTo(position.dx + length, position.dy);
      path.lineTo(position.dx + radius, position.dy);
      path.arcToPoint(
        Offset(position.dx, position.dy + radius),
        radius: Radius.circular(radius),
        clockwise: false,
      );
      path.lineTo(position.dx, position.dy + length);
    } else if (!isLeft && isTop) {
      path.moveTo(position.dx - length, position.dy);
      path.lineTo(position.dx - radius, position.dy);
      path.arcToPoint(
        Offset(position.dx, position.dy + radius),
        radius: Radius.circular(radius),
      );
      path.lineTo(position.dx, position.dy + length);
    } else if (isLeft && !isTop) {
      path.moveTo(position.dx + length, position.dy);
      path.lineTo(position.dx + radius, position.dy);
      path.arcToPoint(
        Offset(position.dx, position.dy - radius),
        radius: Radius.circular(radius),
      );
      path.lineTo(position.dx, position.dy - length);
    } else {
      path.moveTo(position.dx - length, position.dy);
      path.lineTo(position.dx - radius, position.dy);
      path.arcToPoint(
        Offset(position.dx, position.dy - radius),
        radius: Radius.circular(radius),
        clockwise: false,
      );
      path.lineTo(position.dx, position.dy - length);
    }

    canvas.drawPath(path, paint);
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
}
