import 'dart:async';
import 'dart:convert';
import 'dart:math';

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:lunchpick/core/constants/app_colors.dart';
import 'package:lunchpick/core/constants/app_typography.dart';
import 'package:lunchpick/core/services/permission_service.dart';
import 'package:lunchpick/domain/entities/restaurant.dart';
import 'package:lunchpick/domain/entities/share_device.dart';
import 'package:lunchpick/presentation/providers/ad_provider.dart';
import 'package:lunchpick/presentation/providers/bluetooth_provider.dart';
import 'package:lunchpick/presentation/providers/debug_share_preview_provider.dart';
import 'package:lunchpick/presentation/providers/restaurant_provider.dart';
import 'package:lunchpick/presentation/providers/settings_provider.dart';
import 'package:lunchpick/presentation/widgets/native_ad_placeholder.dart';
import 'package:uuid/uuid.dart';

class ShareScreen extends ConsumerStatefulWidget {
  const ShareScreen({super.key});

  @override
  ConsumerState<ShareScreen> createState() => _ShareScreenState();
}

class _ShareCard extends StatelessWidget {
  final bool isDark;
  final IconData icon;
  final Color iconColor;
  final Color iconBgColor;
  final String title;
  final String subtitle;
  final Widget child;

  const _ShareCard({
    required this.isDark,
    required this.icon,
    required this.iconColor,
    required this.iconBgColor,
    required this.title,
    required this.subtitle,
    required this.child,
  });

  @override
  Widget build(BuildContext context) {
    return SizedBox(
      width: double.infinity,
      child: Card(
        color: isDark ? AppColors.darkSurface : AppColors.lightSurface,
        elevation: 2,
        shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
        child: Padding(
          padding: const EdgeInsets.all(24),
          child: Column(
            children: [
              Container(
                padding: const EdgeInsets.all(16),
                decoration: BoxDecoration(
                  color: iconBgColor,
                  shape: BoxShape.circle,
                ),
                child: Icon(icon, size: 48, color: iconColor),
              ),
              const SizedBox(height: 16),
              Text(title, style: AppTypography.heading2(isDark)),
              const SizedBox(height: 8),
              Text(
                subtitle,
                style: AppTypography.body2(isDark),
                textAlign: TextAlign.center,
              ),
              const SizedBox(height: 20),
              child,
            ],
          ),
        ),
      ),
    );
  }
}

class _ShareScreenState extends ConsumerState<ShareScreen> {
  String? _shareCode;
  bool _isScanning = false;
  List<ShareDevice>? _nearbyDevices;
  StreamSubscription<String>? _dataSubscription;
  ProviderSubscription<bool>? _debugPreviewSub;
  final _uuid = const Uuid();
  bool _debugPreviewEnabled = false;
  Timer? _debugPreviewTimer;

  @override
  void initState() {
    super.initState();
    final bluetoothService = ref.read(bluetoothServiceProvider);
    _dataSubscription = bluetoothService.onDataReceived.listen((payload) {
      _handleIncomingData(payload);
    });
    _debugPreviewEnabled = ref.read(debugSharePreviewProvider);
    if (_debugPreviewEnabled) {
      WidgetsBinding.instance.addPostFrameCallback((_) {
        _handleDebugToggleChange(true);
      });
    }
    _debugPreviewSub = ref.listenManual<bool>(debugSharePreviewProvider, (
      previous,
      next,
    ) {
      if (previous == next) return;
      _handleDebugToggleChange(next);
    });
  }

  @override
  void dispose() {
    _dataSubscription?.cancel();
    _debugPreviewSub?.close();
    ref.read(bluetoothServiceProvider).stopListening();
    _debugPreviewTimer?.cancel();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    final isDark = Theme.of(context).brightness == Brightness.dark;
    final screenshotModeEnabled = ref
        .watch(screenshotModeEnabledProvider)
        .maybeWhen(data: (value) => value, orElse: () => false);

    return Scaffold(
      backgroundColor: isDark
          ? AppColors.darkBackground
          : AppColors.lightBackground,
      appBar: AppBar(
        title: const Text('리스트 공유'),
        backgroundColor: isDark
            ? AppColors.darkPrimary
            : AppColors.lightPrimary,
        foregroundColor: Colors.white,
        elevation: 0,
      ),
      body: SingleChildScrollView(
        padding: const EdgeInsets.all(16),
        child: Center(
          child: ConstrainedBox(
            constraints: const BoxConstraints(maxWidth: 520),
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              crossAxisAlignment: CrossAxisAlignment.stretch,
              children: [
                _ShareCard(
                  isDark: isDark,
                  icon: Icons.upload_rounded,
                  iconColor: AppColors.lightSecondary,
                  iconBgColor: AppColors.lightSecondary.withOpacity(0.1),
                  title: '내 리스트 공유하기',
                  subtitle: '내 맛집 리스트를 다른 사람과 공유하세요',
                  child: _buildSendSection(isDark),
                ),
                const SizedBox(height: 16),
                NativeAdPlaceholder(
                  height: 220,
                  enabled: !screenshotModeEnabled,
                ),
                const SizedBox(height: 16),
                _ShareCard(
                  isDark: isDark,
                  icon: Icons.download_rounded,
                  iconColor: AppColors.lightPrimary,
                  iconBgColor: AppColors.lightPrimary.withOpacity(0.1),
                  title: '리스트 공유받기',
                  subtitle: '다른 사람의 맛집 리스트를 받아보세요',
                  child: _buildReceiveSection(isDark),
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }

  Widget _buildReceiveSection(bool isDark) {
    return Column(
      children: [
        if (_shareCode != null) ...[
          Container(
            padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16),
            decoration: BoxDecoration(
              color: AppColors.lightPrimary.withOpacity(0.1),
              borderRadius: BorderRadius.circular(12),
              border: Border.all(
                color: AppColors.lightPrimary.withOpacity(0.3),
                width: 2,
              ),
            ),
            child: Text(
              _shareCode!,
              style: const TextStyle(
                fontSize: 36,
                fontWeight: FontWeight.bold,
                letterSpacing: 6,
                color: AppColors.lightPrimary,
              ),
            ),
          ),
          const SizedBox(height: 12),
          Text('이 코드를 상대방에게 알려주세요', style: AppTypography.caption(isDark)),
          const SizedBox(height: 16),
          TextButton.icon(
            onPressed: () {
              setState(() {
                _shareCode = null;
              });
              ref.read(bluetoothServiceProvider).stopListening();
            },
            icon: const Icon(Icons.close),
            label: const Text('취소'),
            style: TextButton.styleFrom(foregroundColor: AppColors.lightError),
          ),
        ] else
          ElevatedButton.icon(
            onPressed: () {
              _generateShareCode();
            },
            icon: const Icon(Icons.bluetooth),
            label: const Text('공유 코드 생성'),
            style: ElevatedButton.styleFrom(
              backgroundColor: AppColors.lightPrimary,
              foregroundColor: Colors.white,
              padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
              shape: RoundedRectangleBorder(
                borderRadius: BorderRadius.circular(8),
              ),
            ),
          ),
      ],
    );
  }

  Widget _buildSendSection(bool isDark) {
    return Column(
      children: [
        if (_isScanning && _nearbyDevices != null) ...[
          Container(
            constraints: const BoxConstraints(maxHeight: 220),
            child: _nearbyDevices!.isEmpty
                ? Column(
                    children: [
                      const CircularProgressIndicator(
                        color: AppColors.lightSecondary,
                      ),
                      const SizedBox(height: 16),
                      Text(
                        '주변 기기를 검색 중...',
                        style: AppTypography.caption(isDark),
                      ),
                    ],
                  )
                : ListView.builder(
                    itemCount: _nearbyDevices!.length,
                    shrinkWrap: true,
                    itemBuilder: (context, index) {
                      final device = _nearbyDevices![index];
                      return Card(
                        margin: const EdgeInsets.only(bottom: 8),
                        child: ListTile(
                          leading: const Icon(
                            Icons.phone_android,
                            color: AppColors.lightSecondary,
                          ),
                          title: Text(
                            device.code,
                            style: AppTypography.body1(
                              isDark,
                            ).copyWith(fontWeight: FontWeight.bold),
                          ),
                          subtitle: Text('기기 ID: ${device.deviceId}'),
                          trailing: const Icon(
                            Icons.send,
                            color: AppColors.lightSecondary,
                          ),
                          onTap: () {
                            _sendList(device.code);
                          },
                        ),
                      );
                    },
                  ),
          ),
          const SizedBox(height: 16),
          TextButton.icon(
            onPressed: () {
              setState(() {
                _isScanning = false;
                _nearbyDevices = null;
              });
            },
            icon: const Icon(Icons.stop),
            label: const Text('스캔 중지'),
            style: TextButton.styleFrom(foregroundColor: AppColors.lightError),
          ),
        ] else
          ElevatedButton.icon(
            onPressed: () {
              _scanDevices();
            },
            icon: const Icon(Icons.radar),
            label: const Text('주변 기기 스캔'),
            style: ElevatedButton.styleFrom(
              backgroundColor: AppColors.lightSecondary,
              foregroundColor: Colors.white,
              padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
              shape: RoundedRectangleBorder(
                borderRadius: BorderRadius.circular(8),
              ),
            ),
          ),
      ],
    );
  }

  Future<void> _generateShareCode() async {
    final adWatched = await ref
        .read(adServiceProvider)
        .showInterstitialAd(context);
    if (!mounted) return;
    if (!adWatched) {
      _showErrorSnackBar('광고를 끝까지 시청해야 공유 코드를 생성할 수 있어요.');
      return;
    }

    if (kDebugMode && _debugPreviewEnabled) {
      setState(() {
        _shareCode = _shareCode ?? _buildDebugShareCode();
      });
      _showSuccessSnackBar('디버그 공유 코드가 준비되었습니다.');
      return;
    }

    final hasPermission =
        await PermissionService.checkAndRequestBluetoothPermission();
    if (!hasPermission) {
      if (!mounted) return;
      _showErrorSnackBar('블루투스 권한을 허용해야 공유 코드를 생성할 수 있어요.');
      return;
    }

    final random = Random();
    final code = List.generate(6, (_) => random.nextInt(10)).join();

    try {
      await ref.read(bluetoothServiceProvider).startListening(code);
      if (!mounted) return;
      setState(() {
        _shareCode = code;
      });
      _showSuccessSnackBar('공유 코드가 생성되었습니다.');
    } catch (_) {
      if (!mounted) return;
      _showErrorSnackBar('코드를 생성하지 못했습니다. 잠시 후 다시 시도해 주세요.');
    }
  }

  Future<void> _scanDevices() async {
    if (kDebugMode && _debugPreviewEnabled) {
      setState(() {
        _isScanning = true;
        _nearbyDevices = _buildDebugDevices();
      });
      _scheduleDebugReceive();
      return;
    }

    final hasPermission =
        await PermissionService.checkAndRequestBluetoothPermission();
    if (!hasPermission) {
      if (!mounted) return;
      _showErrorSnackBar('블루투스 권한이 필요합니다.');
      return;
    }

    setState(() {
      _isScanning = true;
      _nearbyDevices = [];
    });

    try {
      final devices = await ref
          .read(bluetoothServiceProvider)
          .scanNearbyDevices();
      if (!mounted) return;
      setState(() {
        _nearbyDevices = devices;
      });
    } catch (e) {
      if (!mounted) return;
      setState(() {
        _isScanning = false;
      });
      _showErrorSnackBar('스캔 중 오류가 발생했습니다.');
    }
  }

  Future<void> _sendList(String targetCode) async {
    final adWatched = await ref
        .read(adServiceProvider)
        .showInterstitialAd(context);
    if (!mounted) return;
    if (!adWatched) {
      _showErrorSnackBar('광고를 끝까지 시청해야 리스트를 전송할 수 있어요.');
      return;
    }

    if (kDebugMode && _debugPreviewEnabled) {
      _showLoadingDialog('리스트 전송 중...');
      await Future<void>.delayed(const Duration(milliseconds: 700));
      if (!mounted) return;
      Navigator.pop(context);
      _showSuccessSnackBar('디버그 전송 완료! (실제 전송 없음)');
      setState(() {
        _isScanning = false;
        _nearbyDevices = null;
      });
      return;
    }

    final restaurants = await ref.read(restaurantListProvider.future);
    if (!mounted) return;

    _showLoadingDialog('리스트 전송 중...');
    try {
      await ref
          .read(bluetoothServiceProvider)
          .sendRestaurantList(targetCode, restaurants);
      if (!mounted) return;
      Navigator.pop(context);
      _showSuccessSnackBar('리스트 전송 완료!');
      setState(() {
        _isScanning = false;
        _nearbyDevices = null;
      });
    } catch (e) {
      if (!mounted) return;
      Navigator.pop(context);
      _showErrorSnackBar('전송 실패: $e');
    }
  }

  Future<void> _handleIncomingData(
    String payload, {
    bool skipAd = false,
  }) async {
    if (!mounted) return;
    if (!skipAd) {
      final adWatched = await ref
          .read(adServiceProvider)
          .showInterstitialAd(context);
      if (!mounted) return;
      if (!adWatched) {
        _showErrorSnackBar('광고를 시청해야 리스트를 받을 수 있어요.');
        return;
      }
    }

    try {
      final restaurants = _parseReceivedData(payload);
      await _mergeRestaurantList(restaurants);
    } catch (_) {
      _showErrorSnackBar('전송된 데이터를 처리하는 데 실패했습니다.');
    }
  }

  List<Restaurant> _parseReceivedData(String data) {
    final jsonList = jsonDecode(data) as List<dynamic>;
    return jsonList
        .map((item) => _restaurantFromJson(item as Map<String, dynamic>))
        .toList();
  }

  Restaurant _restaurantFromJson(Map<String, dynamic> json) {
    return Restaurant(
      id: json['id'] as String,
      name: json['name'] as String,
      category: json['category'] as String,
      subCategory: json['subCategory'] as String,
      description: json['description'] as String?,
      phoneNumber: json['phoneNumber'] as String?,
      roadAddress: json['roadAddress'] as String,
      jibunAddress: json['jibunAddress'] as String,
      latitude: (json['latitude'] as num).toDouble(),
      longitude: (json['longitude'] as num).toDouble(),
      lastVisitDate: json['lastVisitDate'] != null
          ? DateTime.parse(json['lastVisitDate'] as String)
          : null,
      source: DataSource.values.firstWhere(
        (source) =>
            source.name ==
            (json['source'] as String? ?? DataSource.USER_INPUT.name),
        orElse: () => DataSource.USER_INPUT,
      ),
      createdAt: DateTime.parse(json['createdAt'] as String),
      updatedAt: DateTime.parse(json['updatedAt'] as String),
      naverPlaceId: json['naverPlaceId'] as String?,
      naverUrl: json['naverUrl'] as String?,
      businessHours: json['businessHours'] as String?,
      lastVisited: json['lastVisited'] != null
          ? DateTime.parse(json['lastVisited'] as String)
          : null,
      visitCount: (json['visitCount'] as num?)?.toInt() ?? 0,
    );
  }

  Future<void> _mergeRestaurantList(List<Restaurant> receivedList) async {
    final currentList = await ref.read(restaurantListProvider.future);
    final notifier = ref.read(restaurantNotifierProvider.notifier);

    final newRestaurants = <Restaurant>[];
    for (final restaurant in receivedList) {
      final exists = currentList.any(
        (existing) =>
            existing.name == restaurant.name &&
            existing.roadAddress == restaurant.roadAddress,
      );
      if (!exists) {
        newRestaurants.add(
          restaurant.copyWith(
            id: _uuid.v4(),
            createdAt: DateTime.now(),
            updatedAt: DateTime.now(),
            source: DataSource.USER_INPUT,
          ),
        );
      }
    }

    for (final restaurant in newRestaurants) {
      await notifier.addRestaurantDirect(restaurant);
    }

    if (!mounted) return;
    if (newRestaurants.isEmpty) {
      _showSuccessSnackBar('이미 등록된 맛집과 동일한 항목만 전송되었습니다.');
    } else {
      _showSuccessSnackBar('${newRestaurants.length}개의 새로운 맛집이 추가되었습니다!');
    }

    setState(() {
      _shareCode = null;
    });
    ref.read(bluetoothServiceProvider).stopListening();
  }

  void _showLoadingDialog(String message) {
    final isDark = Theme.of(context).brightness == Brightness.dark;

    showDialog(
      context: context,
      barrierDismissible: false,
      builder: (context) => Dialog(
        backgroundColor: isDark
            ? AppColors.darkSurface
            : AppColors.lightSurface,
        child: Padding(
          padding: const EdgeInsets.all(20),
          child: Row(
            mainAxisSize: MainAxisSize.min,
            children: [
              const CircularProgressIndicator(color: AppColors.lightPrimary),
              const SizedBox(width: 20),
              Flexible(
                child: Text(message, style: AppTypography.body2(isDark)),
              ),
            ],
          ),
        ),
      ),
    );
  }

  void _showSuccessSnackBar(String message) {
    if (!mounted) return;
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(content: Text(message), backgroundColor: AppColors.lightPrimary),
    );
  }

  void _showErrorSnackBar(String message) {
    if (!mounted) return;
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(content: Text(message), backgroundColor: AppColors.lightError),
    );
  }

  Future<void> _handleDebugToggleChange(bool enabled) async {
    if (!mounted) return;
    setState(() {
      _debugPreviewEnabled = enabled;
    });
    if (enabled) {
      await _startDebugPreviewFlow();
    } else {
      _stopDebugPreviewFlow();
    }
  }

  Future<void> _startDebugPreviewFlow() async {
    _debugPreviewTimer?.cancel();
    final code = _buildDebugShareCode();
    setState(() {
      _shareCode = code;
      _isScanning = true;
      _nearbyDevices = _buildDebugDevices();
    });
    _scheduleDebugReceive();
  }

  void _stopDebugPreviewFlow() {
    _debugPreviewTimer?.cancel();
    setState(() {
      _shareCode = null;
      _isScanning = false;
      _nearbyDevices = null;
    });
  }

  void _scheduleDebugReceive() {
    _debugPreviewTimer?.cancel();
    _debugPreviewTimer = Timer(const Duration(seconds: 1), () {
      if (!mounted || !_debugPreviewEnabled) return;
      final payload = _buildDebugPayload();
      _handleIncomingData(payload, skipAd: true);
    });
  }

  String _buildDebugShareCode() => 'DBG${Random().nextInt(900000) + 100000}';

  List<ShareDevice> _buildDebugDevices() {
    final now = DateTime.now();
    return [
      ShareDevice(code: 'DBG-ALPHA', deviceId: 'LP-DEBUG-1', discoveredAt: now),
      ShareDevice(
        code: 'DBG-BETA',
        deviceId: 'LP-DEBUG-2',
        discoveredAt: now.subtract(const Duration(seconds: 10)),
      ),
    ];
  }

  String _buildDebugPayload() {
    final samples = _buildDebugRestaurants();
    final list = samples
        .map(
          (restaurant) => {
            'id': restaurant.id,
            'name': restaurant.name,
            'category': restaurant.category,
            'subCategory': restaurant.subCategory,
            'description': restaurant.description,
            'phoneNumber': restaurant.phoneNumber,
            'roadAddress': restaurant.roadAddress,
            'jibunAddress': restaurant.jibunAddress,
            'latitude': restaurant.latitude,
            'longitude': restaurant.longitude,
            'lastVisitDate': restaurant.lastVisitDate?.toIso8601String(),
            'source': restaurant.source.name,
            'createdAt': restaurant.createdAt.toIso8601String(),
            'updatedAt': restaurant.updatedAt.toIso8601String(),
            'naverPlaceId': restaurant.naverPlaceId,
            'naverUrl': restaurant.naverUrl,
            'businessHours': restaurant.businessHours,
            'lastVisited': restaurant.lastVisited?.toIso8601String(),
            'visitCount': restaurant.visitCount,
          },
        )
        .toList();
    return jsonEncode(list);
  }

  List<Restaurant> _buildDebugRestaurants() {
    final now = DateTime.now();
    return [
      Restaurant(
        id: 'debug-share-ramen',
        name: '디버그 라멘바',
        category: 'Japanese',
        subCategory: 'Ramen',
        description: '테스트용 라멘 바. 실제 전송 없이 미리보기 용도입니다.',
        phoneNumber: '02-111-1111',
        roadAddress: '서울 특별시 테스트로 1',
        jibunAddress: '서울 테스트동 1-1',
        latitude: 37.566,
        longitude: 126.9784,
        lastVisitDate: now.subtract(const Duration(days: 2)),
        source: DataSource.PRESET,
        createdAt: now,
        updatedAt: now,
        naverPlaceId: null,
        naverUrl: null,
        businessHours: '11:00 - 21:00',
        lastVisited: now.subtract(const Duration(days: 2)),
        visitCount: 3,
      ),
      Restaurant(
        id: 'debug-share-burger',
        name: '샘플 버거샵',
        category: 'Fastfood',
        subCategory: 'Burger',
        description: '광고·권한 없이 교환 흐름을 확인하는 샘플 버거 가게.',
        phoneNumber: '02-222-2222',
        roadAddress: '서울 특별시 디버그길 22',
        jibunAddress: '서울 디버그동 22-2',
        latitude: 37.57,
        longitude: 126.982,
        lastVisitDate: now.subtract(const Duration(days: 5)),
        source: DataSource.PRESET,
        createdAt: now,
        updatedAt: now,
        naverPlaceId: null,
        naverUrl: null,
        businessHours: '10:00 - 23:00',
        lastVisited: now.subtract(const Duration(days: 5)),
        visitCount: 1,
      ),
      Restaurant(
        id: 'debug-share-brunch',
        name: '프리뷰 브런치 카페',
        category: 'Cafe',
        subCategory: 'Brunch',
        description: '리스트 공유 수신 UI를 확인하기 위한 브런치 카페 샘플.',
        phoneNumber: '02-333-3333',
        roadAddress: '서울 특별시 미리보기로 33',
        jibunAddress: '서울 미리보기동 33-3',
        latitude: 37.561,
        longitude: 126.99,
        lastVisitDate: now.subtract(const Duration(days: 1)),
        source: DataSource.PRESET,
        createdAt: now,
        updatedAt: now,
        naverPlaceId: null,
        naverUrl: null,
        businessHours: '09:00 - 18:00',
        lastVisited: now.subtract(const Duration(days: 1)),
        visitCount: 4,
      ),
    ];
  }
}
