import 'dart:io' show Platform;
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:http/http.dart' as http;
import 'package:nearle/views/helpers/constants/Font_constant.dart';
import 'package:nearle/views/helpers/constants/Colorconstants.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:nearle/providers/auth/auth_provider.dart';
import 'package:nearle/utils/device.dart';
import 'package:sms_autofill/sms_autofill.dart';
import 'package:nearle/controllers/profile_controller.dart';
// ignore: unused_import
import 'package:nearle/controllers/riderlog.dart';
import 'package:nearle/Models/login/login.dart';
import 'dart:convert';

enum AuthNext { verifyPin, otp, notRegistered, error }

class AuthController extends GetxController {
  final RxBool sendingOtp = false.obs;
  String? currentPhone;
  final AuthProvider _api = AuthProvider();
  AuthNext? lastDecision;
  // Optional callback used by MPIN screen to clear and refocus fields when user taps "Retry"
  VoidCallback? onPinRetry;
  static const String _prefsUserIdKey = 'userid';
  static const String _prefsPendingPinUserIdKey = 'pending_pin_userid';
  static const String _prefsUserNameKey = 'user_name';
  static const String _prefsUserEmailKey = 'user_email';
  static const String _prefsContactNoKey = 'contactno';
  static const String _prefsAddressKey = 'user_address';
  static const String _prefsForceMasterPinKey = 'force_master_pin';
  static const String _masterPinValue = '1234';
  static const String forceMasterPinPrefKey = _prefsForceMasterPinKey;
  static const String masterPinValue = _masterPinValue;
  bool _forceMasterPinFlow = false;
  void _log(String msg) => debugPrint('[AUTH] $msg');
  Future<void> _notifyProfileController() async {
    try {
      if (Get.isRegistered<ProfileController>()) {
        final prefs = await SharedPreferences.getInstance();
        final pc = Get.find<ProfileController>();
        await pc.loadFromPrefs();
        pc.setProfile(
          name: prefs.getString(_prefsUserNameKey),
          email: prefs.getString(_prefsUserEmailKey),
          contact: prefs.getString(_prefsContactNoKey),
          address: prefs.getString(_prefsAddressKey),
        );
      }
    } catch (_) {}
  }

  String _normalizePhone(String input) {
    final digitsOnly = input.replaceAll(RegExp(r'\D'), '');
    if (digitsOnly.length >= 10) {
      return digitsOnly.substring(digitsOnly.length - 10);
    }
    return digitsOnly;
  }

  void _showBottomSheet({required String title, required String message}) {
    Get.bottomSheet(
      SafeArea(
        child: Container(
          padding: const EdgeInsets.all(16),
          decoration: const BoxDecoration(
            color: Colors.white,
            borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
          ),
          child: Column(
            mainAxisSize: MainAxisSize.min,
            crossAxisAlignment: CrossAxisAlignment.center,
            children: [
              const Icon(
                Icons.info_outline,
                color: Color(0xFF662582),
                size: 40,
              ),
              const SizedBox(height: 12),
              Text(
                title,
                textAlign: TextAlign.center,
                style: TextStyle(
                  fontWeight: FontWeight.w700,
                  fontFamily: FontConstants.fontFamily,
                  fontSize: 20,
                ),
              ),
              const SizedBox(height: 8),
              Text(
                message,
                textAlign: TextAlign.center,
                style: const TextStyle(fontSize: 16),
              ),
              const SizedBox(height: 16),
              SizedBox(
                height: 50,
                width: double.infinity,
                child: ElevatedButton(
                  onPressed: () {
                    Get.back();
                    // If MPIN screen has registered a retry callback, run it
                    onPinRetry?.call();
                  },
                  style: ElevatedButton.styleFrom(
                    backgroundColor: const Color(0xFF662582),
                    shape: RoundedRectangleBorder(
                      borderRadius: BorderRadius.circular(10),
                    ),
                  ),
                  child: const Text(
                    'Retry',
                    style: TextStyle(color: Colors.white, fontSize: 20),
                  ),
                ),
              ),
            ],
          ),
        ),
      ),
      isScrollControlled: true,
      backgroundColor: Colors.transparent,
    );
  }

  Future<AuthNext> precheckPhone(String phone) async {
    try {
      final normalized = _normalizePhone(phone);
      final prefs = await SharedPreferences.getInstance();
      _forceMasterPinFlow = false;
      await prefs.remove(_prefsForceMasterPinKey);
      String deviceId;
      try {
        deviceId = await DeviceUtils.ensureDeviceId(prefs);
      } catch (e) {
        _showBottomSheet(
          title: 'Device Error',
          message:
              'Failed to get device ID. Please restart the app and try again.',
        );
        lastDecision = AuthNext.error;
        return lastDecision!;
      }
      final String fcmToken = await DeviceUtils.ensureFcmToken(prefs);
      final bool fcmWasEmpty = fcmToken.isEmpty;
      _log(
        'POST /users/rider/login body=${jsonEncode({'contactno': normalized, 'devicetype': Platform.operatingSystem, 'configid': 6, 'deviceid': deviceId, 'userfcmtoken': fcmToken})}',
      );
      final Login loginRes = await _api.loginParsed(
        contactNo: normalized,
        deviceType: Platform.operatingSystem,
        configId: 6,
        deviceId: deviceId,
        fcmToken: fcmToken,
      );

      debugPrint('RAW LOGIN RESPONSE: $loginRes');
      final String serverMessage = (loginRes.message ?? '').toLowerCase();
      final bool masterPinFlow = (loginRes.authmode ?? 0) == 1;
      final bool requiresPinSetup =
          serverMessage.contains('pin not set') ||
          serverMessage.contains('mpin not set') ||
          serverMessage.contains('please set your pin') ||
          (loginRes.code != null && loginRes.code == 201);
      if (serverMessage.contains('not registered') ||
          serverMessage.contains('register first') ||
          serverMessage.contains('not found') ||
          serverMessage.contains('no user')) {
        currentPhone = null;
        _showBottomSheet(
          title: 'Not Registered',
          message: 'Please contact admin and register first.',
        );
        lastDecision = AuthNext.notRegistered;
        return lastDecision!;
      }
      if (serverMessage.contains('inactive')) {
        currentPhone = null;
        _showBottomSheet(
          title: 'Rider Inactive',
          message: 'Rider is inactive. Please contact admin.',
        );
        lastDecision = AuthNext.notRegistered;
        return lastDecision!;
      }
      final bool messageSaysEnterPin = (loginRes.message ?? '')
          .toLowerCase()
          .contains('enter your pin');

      if (loginRes.status == true) {
        try {
          final SharedPreferences prefsSave =
              await SharedPreferences.getInstance();
          // Persist from model
          if (loginRes.userid != null) {
            await prefsSave.setInt(_prefsUserIdKey, loginRes.userid!);

            final SharedPreferences prefs =
                await SharedPreferences.getInstance();
            await prefs.setString(
              'username',
              loginRes.fullname ?? loginRes.firstname.toString(),
            );
            await prefs.setInt('userid', loginRes.userid ?? 0);
            await prefs.setInt('userId', loginRes.userid ?? 0);
            await prefs.setInt('shiftid', loginRes.shiftid ?? 0);
            await prefs.setInt('shiftId', loginRes.shiftid ?? 0);
            await prefs.setInt('logid', loginRes.logid ?? 0);
            await prefs.setInt('logId', loginRes.logid ?? 0);
            await prefs.setInt('riderid', loginRes.riderid ?? 0);
            await prefs.setInt('partnerid', loginRes.partnerid ?? 0);
            await prefs.setInt('partnerId', loginRes.partnerid ?? 0);
            await prefs.setInt('rconfigid', loginRes.configid ?? 0);
            await prefs.setInt('locationid', loginRes.locationid ?? 0);
            await prefs.setInt('tenantid', loginRes.tenantid ?? 0);
            await prefs.setInt('applocationid', loginRes.applocationid ?? 0);
            if (loginRes.userfcmtoken != null && loginRes.userfcmtoken!.isNotEmpty) {
              await prefs.setString('userfcmtoken', loginRes.userfcmtoken!);
            }

            debugPrint('saved on shared pref :${loginRes.fullname}');
          }

          final String? name = loginRes.fullname ?? loginRes.firstname;
          final String? email = loginRes.email;
          final String contact = (loginRes.contactno ?? normalized).toString();
          final String? address = loginRes.address;
          _log(
            'Saving from model: name=$name, email=$email, contact=$contact, address=$address',
          );
          if (name != null && name.trim().isNotEmpty) {
            await prefsSave.setString(_prefsUserNameKey, name.trim());
          }
          if (email != null && email.trim().isNotEmpty) {
            await prefsSave.setString(_prefsUserEmailKey, email.trim());
          }
          if (contact.isNotEmpty) {
            await prefsSave.setString(
              _prefsContactNoKey,
              _normalizePhone(contact),
            );
          }
          if (address != null && address.trim().isNotEmpty) {
            await prefsSave.setString(_prefsAddressKey, address.trim());
          }
          await _notifyProfileController();
        } catch (_) {}
      }
      // Persist basic user profile details from model even if above branch didn't run
      try {
        final prefs2 = await SharedPreferences.getInstance();
        final String? name = loginRes.fullname ?? loginRes.firstname;
        final String? email = loginRes.email;
        final String contact = (loginRes.contactno ?? normalized).toString();
        final String? address = loginRes.address;
        if (name != null && name.trim().isNotEmpty) {
          await prefs2.setString(_prefsUserNameKey, name.trim());
        }
        if (email != null && email.trim().isNotEmpty) {
          await prefs2.setString(_prefsUserEmailKey, email.trim());
        }
        if (contact.isNotEmpty) {
          final normalizedContact = _normalizePhone(contact);
          await prefs2.setString(_prefsContactNoKey, normalizedContact);
        }
        if (address != null && address.trim().isNotEmpty) {
          await prefs2.setString(_prefsAddressKey, address.trim());
        }
        await _notifyProfileController();
      } catch (_) {}

      if (masterPinFlow) {
        currentPhone = _normalizePhone(phone);
        _forceMasterPinFlow = true;
        await prefs.setBool(_prefsForceMasterPinKey, true);
        await prefs.remove('dbPin');
        if (loginRes.userid != null) {
          await prefs.setInt(_prefsUserIdKey, loginRes.userid!);
        }
        Get.snackbar(
          'Temporary PIN',
          'Use $_masterPinValue as PIN to continue.',
          snackPosition: SnackPosition.BOTTOM,
          duration: const Duration(seconds: 4),
          backgroundColor: ColorConstants.primaryColor,
          colorText: Colors.white,
        );
        lastDecision = AuthNext.verifyPin;
        return lastDecision!;
      }

      if (messageSaysEnterPin) {
        currentPhone = _normalizePhone(phone);
        lastDecision = AuthNext.verifyPin;
        return lastDecision!;
      }

      if (requiresPinSetup && !masterPinFlow) {
        currentPhone = _normalizePhone(phone);
        await prefs.remove('dbPin');
        if (loginRes.userid != null) {
          await prefs.setInt(_prefsPendingPinUserIdKey, loginRes.userid!);
        }
        lastDecision = AuthNext.otp;
        return lastDecision!;
      }

      // Immediately create rider log entry after successful login
      currentPhone = normalized;
      String? dbPin = loginRes.pin?.toString();
      if (dbPin != null && dbPin.isNotEmpty) {
        await prefs.setString('dbPin', dbPin);
        lastDecision = AuthNext.verifyPin;
        return lastDecision!;
      }
      await prefs.remove('dbPin');
      lastDecision = AuthNext.verifyPin;
      // If FCM was empty during the request, try to refresh session once token becomes available
      if (fcmWasEmpty) {
        try {
          final String newToken = await DeviceUtils.ensureFcmToken(prefs);
          if (newToken.isNotEmpty) {
            await refreshSession(phone: normalized);
          }
        } catch (_) {}
      }
      return lastDecision!;
    } catch (e) {
      debugPrint('Precheck phone error: $e');
      lastDecision = AuthNext.error;
      return lastDecision!;
    }
  }

  Future<bool> sendOtp([String? phoneArg]) async {
    if (sendingOtp.value) return false;
    if (phoneArg != null && phoneArg.isNotEmpty) {
      currentPhone = _normalizePhone(phoneArg);
    }
    if (currentPhone == null) {
      Get.snackbar(
        'Error',
        'Phone number not set. Please enter your number again.',
      );
      return false;
    }
    sendingOtp.value = true;
    try {
      final prefs = await SharedPreferences.getInstance();
      final phone = currentPhone!;

      // Get cached SMS provider settings or use defaults
      String templateId =
          prefs.getString('smsTemplateId') ?? '1107173468024541800';
      String smsContent =
          prefs.getString('smsContent') ??
          '<#> Dear customer, use this One Time Password {#var#} to sign-in to Nearle App. This OTP will be valid for the next 5 mins.';

      // Only fetch SMS provider settings if not cached or cache is old (older than 1 hour)
      final lastProviderFetch = prefs.getInt('lastProviderFetch') ?? 0;
      final now = DateTime.now().millisecondsSinceEpoch;
      if (now - lastProviderFetch > 3600000) {
        // 1 hour in milliseconds
        try {
          final providerUri = Uri.parse(
            'https://jupiter.nearle.app/live/api/v1/platform/getsmsprovider?templatetypeid=1',
          );
          final provRes = await http
              .get(providerUri)
              .timeout(const Duration(seconds: 10));
          if (provRes.statusCode == 200) {
            final Map<String, dynamic> prov = json.decode(provRes.body);
            final details = prov['details'] as Map<String, dynamic>?;
            if (details != null) {
              templateId = (details['templateid'] ?? templateId).toString();
              smsContent = (details['content'] ?? smsContent).toString();
              // Cache the settings
              await prefs.setString('smsTemplateId', templateId);
              await prefs.setString('smsContent', smsContent);
              await prefs.setInt('lastProviderFetch', now);
            }
          }
        } catch (_) {}
      }
      // Append app hash for Android SMS Retriever so auto-fill works silently
      String appHash = '';
      try {
        appHash = await SmsAutoFill().getAppSignature;
        if (appHash.isNotEmpty) {
          _log('Using app hash for SMS Retriever: $appHash');
        }
      } catch (_) {}
      // Generate OTP ourselves (like the original implementation)
      String actualOtp = _generateOtp();
      await prefs.setString('lastOtp', actualOtp);
      _log('Generated OTP: $actualOtp');

      // Replace {#var#} with actual OTP before sending to Lion SMS
      final composedSmsBase = smsContent.replaceAll('{#var#}', actualOtp);
      final composedSms = appHash.isNotEmpty
          ? ('$composedSmsBase\n$appHash')
          : composedSmsBase;
      final phoneWithCountry = phone.startsWith('+') ? phone : '+91$phone';
      final encodedSms = Uri.encodeComponent(composedSms);
      final smsUrl = Uri.parse(
        'https://msg.lionsms.com/api/smsapi?key=e57f5c9679af26077be1a7eadabb1b2a&route=7&sender=NEARLE&number=$phoneWithCountry&templateid=$templateId&sms=$encodedSms',
      );
      final smsRes = await http
          .get(smsUrl)
          .timeout(const Duration(seconds: 10));
      if (smsRes.statusCode == 200 &&
          !(smsRes.body.contains('108') ||
              smsRes.body.contains('110') ||
              smsRes.body.toLowerCase().contains('error'))) {
        return true;
      } else {
        Get.snackbar(
          'OTP Send Failed',
          'Provider: ${smsRes.statusCode} ${smsRes.body}',
        );
        return false;
      }
    } catch (e) {
      debugPrint('sendOtp error: $e');
      Get.snackbar('Error', 'An unexpected error occurred while sending OTP.');
      return false;
    } finally {
      sendingOtp.value = false;
    }
  }

  Future<bool> verifyOtp(String code) async {
    try {
      final prefs = await SharedPreferences.getInstance();
      final sentOtp = prefs.getString('lastOtp');
      if (sentOtp != null && code == sentOtp) {
        await prefs.remove('lastOtp');
        _log('OTP verification successful: $code');
        return true;
      }
      _log('OTP verification failed. Expected: $sentOtp, Got: $code');
      return false;
    } catch (e) {
      _log('OTP verification error: $e');
      return false;
    }
  }

  // Generate 6-digit OTP (same as original implementation)
  String _generateOtp() {
    final random = Random();
    final otp = 100000 + random.nextInt(900000); // Generates 100000-999999
    return otp.toString();
  }

  Future<bool> setPin(String newPin) async {
    try {
      final prefs = await SharedPreferences.getInstance();
      int? userId =
          prefs.getInt(_prefsPendingPinUserIdKey) ??
          prefs.getInt(_prefsUserIdKey);
      if (newPin.length != 4 || int.tryParse(newPin) == null) {
        _showBottomSheet(
          title: 'Invalid PIN',
          message: 'Please enter a valid 4-digit PIN.',
        );
        return false;
      }
      if (userId == null) {
        _showBottomSheet(
          title: 'Error',
          message: 'User ID not found. Please try again.',
        );
        return false;
      }
      final int pinNum = int.parse(newPin);
      final res = await _api.updatePin(userId: userId, pin: pinNum);
      if (res.statusCode >= 200 && res.statusCode < 300) {
        await prefs.setString('dbPin', newPin);
        await prefs.remove(_prefsPendingPinUserIdKey);
        return true;
      }
      final bodyPreview = res.body.length > 200
          ? '${res.body.substring(0, 200)}...'
          : res.body;
      _showBottomSheet(
        title: 'Failed (${res.statusCode})',
        message: 'Unable to set PIN. Server said: $bodyPreview',
      );
      return false;
    } catch (e) {
      debugPrint('setPin error: $e');
      _showBottomSheet(
        title: 'Error',
        message: 'Something went wrong while setting the PIN.',
      );
      return false;
    }
  }

  /// Refresh session on backend with latest deviceId/FCM for the current phone.
  Future<bool> refreshSession({String? phone}) async {
    try {
      final prefs = await SharedPreferences.getInstance();
      final String? usePhone = phone ?? currentPhone;
      if (usePhone == null || usePhone.isEmpty) {
        return false;
      }
      final deviceId = await DeviceUtils.ensureDeviceId(prefs);
      final fcmToken = await DeviceUtils.ensureFcmToken(prefs);
      final Login loginRes = await _api.loginParsed(
        contactNo: usePhone,
        deviceType: Platform.operatingSystem,
        configId: 6,
        deviceId: deviceId,
        fcmToken: fcmToken,
      );
      if (loginRes.userid != null) {
        await prefs.setInt(_prefsUserIdKey, loginRes.userid!);
      }
      try {
        final String? name = loginRes.fullname ?? loginRes.firstname;
        final String? email = loginRes.email;
        final String contact = (loginRes.contactno ?? usePhone).toString();
        final String? address = loginRes.address;
        if (name != null && name.trim().isNotEmpty) {
          await prefs.setString(_prefsUserNameKey, name.trim());
        }
        if (email != null && email.trim().isNotEmpty) {
          await prefs.setString(_prefsUserEmailKey, email.trim());
        }
        if (contact.isNotEmpty) {
          final normalizedContact = _normalizePhone(contact);
          await prefs.setString(_prefsContactNoKey, normalizedContact);
        }
        if (address != null && address.trim().isNotEmpty) {
          await prefs.setString(_prefsAddressKey, address.trim());
        }
        await _notifyProfileController();
      } catch (_) {}
      currentPhone = _normalizePhone(usePhone);
      return loginRes.status == true;
    } catch (_) {
      return false;
    }
  }

  Future<bool> verifyPinWithServer(String inputPin) async {
    try {
      if (inputPin.length != 4 || int.tryParse(inputPin) == null) {
        _showBottomSheet(
          title: 'Invalid PIN',
          message: 'Please enter a valid 4-digit PIN.',
        );
        return false;
      }
      final prefs = await SharedPreferences.getInstance();
      final String? phone = currentPhone;
      if (phone == null || phone.isEmpty) {
        _showBottomSheet(
          title: 'Session Expired',
          message: 'Please enter your number again.',
        );
        return false;
      }
      final bool masterPinActive =
          _forceMasterPinFlow ||
          (prefs.getBool(_prefsForceMasterPinKey) ?? false);
      if (masterPinActive) {
        if (inputPin != _masterPinValue) {
          _showBottomSheet(title: 'Invalid PIN', message: 'Please try again.');
          return false;
        }
        _forceMasterPinFlow = false;
        await prefs.remove(_prefsForceMasterPinKey);
        await prefs.setString('dbPin', _masterPinValue);
        await prefs.setBool('logged_out', false);
        
        // Call loginParsed with the master pin to fetch and save all API data
        // This ensures shared_preferences has all the necessary data like regular pins
        String deviceId;
        try {
          deviceId = await DeviceUtils.ensureDeviceId(prefs);
        } catch (e) {
          _showBottomSheet(
            title: 'Device Error',
            message:
                'Failed to get device ID. Please restart the app and try again.',
          );
          return false;
        }
        final String fcmToken = await DeviceUtils.ensureFcmToken(prefs);
        final Login loginRes = await _api.loginParsed(
          contactNo: phone,
          deviceType: Platform.operatingSystem,
          configId: 6,
          deviceId: deviceId,
          fcmToken: fcmToken,
          pin: int.parse(_masterPinValue),
        );
        
        // Save user details from API response
        if (loginRes.userid != null) {
          await prefs.setInt(_prefsUserIdKey, loginRes.userid!);
        }
        final String? name = loginRes.fullname ?? loginRes.firstname;
        final String? email = loginRes.email;
        final String contact = (loginRes.contactno ?? currentPhone ?? '')
            .toString();
        final String? address = loginRes.address;
        if (name != null && name.trim().isNotEmpty) {
          await prefs.setString(_prefsUserNameKey, name.trim());
        }
        if (email != null && email.trim().isNotEmpty) {
          await prefs.setString(_prefsUserEmailKey, email.trim());
        }
        if (contact.isNotEmpty) {
          await prefs.setString(_prefsContactNoKey, _normalizePhone(contact));
        }
        if (address != null && address.trim().isNotEmpty) {
          await prefs.setString(_prefsAddressKey, address.trim());
        }
        try {
          if (currentPhone != null && currentPhone!.isNotEmpty) {
            currentPhone = _normalizePhone(currentPhone!);
          }
          await _notifyProfileController();
        } catch (_) {}
        
        return true;
      }
      String deviceId;
      try {
        deviceId = await DeviceUtils.ensureDeviceId(prefs);
      } catch (e) {
        _showBottomSheet(
          title: 'Device Error',
          message:
              'Failed to get device ID. Please restart the app and try again.',
        );
        return false;
      }
      final String fcmToken = await DeviceUtils.ensureFcmToken(prefs);
      final Login loginRes = await _api.loginParsed(
        contactNo: phone,
        deviceType: Platform.operatingSystem,
        configId: 6,
        deviceId: deviceId,
        fcmToken: fcmToken,
        pin: int.parse(inputPin),
      );
      final String msg = (loginRes.message ?? '').toLowerCase();
      if ((loginRes.code != null && loginRes.code == 401) ||
          msg.contains('invalid pin')) {
        _showBottomSheet(
          title: 'Invalid PIN',
          message: 'Incorrect PIN. Please try again.',
        );
        return false;
      }
      if (loginRes.status == true || msg.contains('success')) {
        await prefs.setString('dbPin', inputPin);
        if (loginRes.userid != null) {
          await prefs.setInt(_prefsUserIdKey, loginRes.userid!);
        }
        await prefs.setBool('logged_out', false);
        final String? name = loginRes.fullname ?? loginRes.firstname;
        final String? email = loginRes.email;
        final String contact = (loginRes.contactno ?? currentPhone ?? '')
            .toString();
        final String? address = loginRes.address;
        if (name != null && name.trim().isNotEmpty) {
          await prefs.setString(_prefsUserNameKey, name.trim());
        }
        if (email != null && email.trim().isNotEmpty) {
          await prefs.setString(_prefsUserEmailKey, email.trim());
        }
        if (contact.isNotEmpty) {
          await prefs.setString(_prefsContactNoKey, _normalizePhone(contact));
        }
        if (address != null && address.trim().isNotEmpty) {
          await prefs.setString(_prefsAddressKey, address.trim());
        }
        try {
          if (currentPhone != null && currentPhone!.isNotEmpty) {
            currentPhone = _normalizePhone(currentPhone!);
          }
          await _notifyProfileController();
        } catch (_) {}
        // Ensure backend session is refreshed on this device with latest FCM/device id
        try {
          await refreshSession(phone: currentPhone);
        } catch (_) {}
        return true;
      }
      _showBottomSheet(
        title: 'Invalid PIN',
        message: 'Incorrect PIN. Please try again.',
      );
      return false;
    } catch (e) {
      debugPrint('verifyPinWithServer error: $e');
      _showBottomSheet(
        title: 'Error',
        message: 'Failed to verify PIN. Try again.',
      );
      return false;
    }
  }
}
