import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:geolocator/geolocator.dart';
import 'package:permission_handler/permission_handler.dart';

// --- State ---
class ClockInState extends Equatable {
  final bool isLoading;
  final bool isLocationVerified;
  final String? error;
  final Position? currentLocation;
  final double? distanceFromVenue;
  final bool isClockedIn;
  final DateTime? clockInTime;

  const ClockInState({
    this.isLoading = false,
    this.isLocationVerified = false,
    this.error,
    this.currentLocation,
    this.distanceFromVenue,
    this.isClockedIn = false,
    this.clockInTime,
  });

  ClockInState copyWith({
    bool? isLoading,
    bool? isLocationVerified,
    String? error,
    Position? currentLocation,
    double? distanceFromVenue,
    bool? isClockedIn,
    DateTime? clockInTime,
  }) {
    return ClockInState(
      isLoading: isLoading ?? this.isLoading,
      isLocationVerified: isLocationVerified ?? this.isLocationVerified,
      error: error, // Clear error if not provided
      currentLocation: currentLocation ?? this.currentLocation,
      distanceFromVenue: distanceFromVenue ?? this.distanceFromVenue,
      isClockedIn: isClockedIn ?? this.isClockedIn,
      clockInTime: clockInTime ?? this.clockInTime,
    );
  }

  @override
  List<Object?> get props => [
        isLoading,
        isLocationVerified,
        error,
        currentLocation,
        distanceFromVenue,
        isClockedIn,
        clockInTime,
      ];
}

// --- Cubit ---
class ClockInCubit extends Cubit<ClockInState> {
  // Mock Venue Location (e.g., Grand Hotel, NYC)
  static const double venueLat = 40.7128;
  static const double venueLng = -74.0060;
  static const double allowedRadiusMeters = 500; // 500m radius

  ClockInCubit() : super(const ClockInState());

  Future<void> checkLocationPermission() async {
    emit(state.copyWith(isLoading: true, error: null));
    try {
      LocationPermission permission = await Geolocator.checkPermission();
      if (permission == LocationPermission.denied) {
        permission = await Geolocator.requestPermission();
        if (permission == LocationPermission.denied) {
          emit(state.copyWith(
            isLoading: false,
            error: 'Location permissions are denied',
          ));
          return;
        }
      }

      if (permission == LocationPermission.deniedForever) {
        emit(state.copyWith(
          isLoading: false,
          error: 'Location permissions are permanently denied, we cannot request permissions.',
        ));
        return;
      }

      _getCurrentLocation();
    } catch (e) {
      emit(state.copyWith(isLoading: false, error: e.toString()));
    }
  }

  Future<void> _getCurrentLocation() async {
    try {
      final position = await Geolocator.getCurrentPosition(
        desiredAccuracy: LocationAccuracy.high,
      );

      final distance = Geolocator.distanceBetween(
        position.latitude,
        position.longitude,
        venueLat,
        venueLng,
      );

      final isWithinRadius = distance <= allowedRadiusMeters;

      emit(state.copyWith(
        isLoading: false,
        currentLocation: position,
        distanceFromVenue: distance,
        isLocationVerified: isWithinRadius,
        error: isWithinRadius ? null : 'You are ${distance.toStringAsFixed(0)}m away. You must be within ${allowedRadiusMeters}m.',
      ));
    } catch (e) {
      emit(state.copyWith(isLoading: false, error: 'Failed to get location: $e'));
    }
  }

  Future<void> clockIn() async {
    if (state.currentLocation == null) {
      await checkLocationPermission();
      if (state.currentLocation == null) return;
    }

    emit(state.copyWith(isLoading: true));
    
    await Future.delayed(const Duration(seconds: 2));

    emit(state.copyWith(
      isLoading: false,
      isClockedIn: true,
      clockInTime: DateTime.now(),
    ));
  }

  Future<void> clockOut() async {
     if (state.currentLocation == null) {
      await checkLocationPermission();
      if (state.currentLocation == null) return;
    }
    
    emit(state.copyWith(isLoading: true));

    await Future.delayed(const Duration(seconds: 2));

    emit(state.copyWith(
      isLoading: false,
      isClockedIn: false,
      clockInTime: null,
    ));
  }
}
