import 'account_runtime_client.dart';
import 'runtime_controllers_settings.dart';
import 'runtime_models.dart';

Future<void> loginAccountSettingsInternal(
  SettingsController controller, {
  required String baseUrl,
  required String identifier,
  required String password,
}) async {
  final normalizedBaseUrl = normalizeAccountBaseUrlSettingsInternal(
    baseUrl,
    fallback: controller.snapshotInternal.accountBaseUrl,
  );
  if (normalizedBaseUrl.isEmpty) {
    controller.accountStatusInternal = 'Account base URL is required';
    controller.notifyListeners();
    return;
  }
  if (identifier.trim().isEmpty || password.isEmpty) {
    controller.accountStatusInternal = 'Email and password are required';
    controller.notifyListeners();
    return;
  }

  controller.accountBusyInternal = true;
  controller.accountStatusInternal = 'Signing in...';
  controller.pendingAccountMfaTicketInternal = '';
  controller.pendingAccountBaseUrlInternal = '';
  controller.notifyListeners();

  try {
    final client = controller.buildAccountClient(normalizedBaseUrl);
    final payload = await client.login(
      identifier: identifier.trim(),
      password: password,
    );
    final requiresMfa =
        payload['mfaRequired'] == true || payload['mfa_required'] == true;
    if (requiresMfa) {
      controller.pendingAccountMfaTicketInternal =
          _stringValue(payload['mfaToken']).isNotEmpty
          ? _stringValue(payload['mfaToken'])
          : _stringValue(payload['mfaTicket']);
      controller.pendingAccountBaseUrlInternal = normalizedBaseUrl;
      controller.accountStatusInternal = 'MFA required';
      return;
    }

    await completeAccountSignInSettingsInternal(
      controller,
      baseUrl: normalizedBaseUrl,
      payload: payload,
      identifier: identifier.trim(),
    );
  } on AccountRuntimeException catch (error) {
    controller.accountStatusInternal = error.message;
  } finally {
    controller.accountBusyInternal = false;
    controller.notifyListeners();
  }
}

Future<void> verifyAccountMfaSettingsInternal(
  SettingsController controller, {
  required String baseUrl,
  required String code,
}) async {
  final normalizedBaseUrl = normalizeAccountBaseUrlSettingsInternal(
    baseUrl,
    fallback: controller.pendingAccountBaseUrlInternal.isNotEmpty
        ? controller.pendingAccountBaseUrlInternal
        : controller.snapshotInternal.accountBaseUrl,
  );
  if (normalizedBaseUrl.isEmpty) {
    controller.accountStatusInternal = 'Account base URL is required';
    controller.notifyListeners();
    return;
  }
  if (controller.pendingAccountMfaTicketInternal.trim().isEmpty) {
    controller.accountStatusInternal = 'MFA ticket is missing';
    controller.notifyListeners();
    return;
  }
  if (code.trim().isEmpty) {
    controller.accountStatusInternal = 'MFA code is required';
    controller.notifyListeners();
    return;
  }

  controller.accountBusyInternal = true;
  controller.accountStatusInternal = 'Verifying MFA...';
  controller.notifyListeners();

  try {
    final client = controller.buildAccountClient(normalizedBaseUrl);
    final payload = await client.verifyMfa(
      mfaToken: controller.pendingAccountMfaTicketInternal,
      code: code.trim(),
    );
    final identifier =
        (await controller.storeInternal.loadAccountSessionIdentifier())
            ?.trim() ??
        controller.snapshotInternal.accountUsername.trim();
    controller.pendingAccountMfaTicketInternal = '';
    controller.pendingAccountBaseUrlInternal = '';
    await completeAccountSignInSettingsInternal(
      controller,
      baseUrl: normalizedBaseUrl,
      payload: payload,
      identifier: identifier,
    );
  } on AccountRuntimeException catch (error) {
    controller.accountStatusInternal = error.message;
  } finally {
    controller.accountBusyInternal = false;
    controller.notifyListeners();
  }
}

Future<void> completeAccountSignInSettingsInternal(
  SettingsController controller, {
  required String baseUrl,
  required Map<String, dynamic> payload,
  required String identifier,
}) async {
  final token = _stringValue(payload['token']).isNotEmpty
      ? _stringValue(payload['token'])
      : _stringValue(payload['access_token']);
  if (token.isEmpty) {
    controller.accountStatusInternal = 'Account session token is missing';
    return;
  }
  final user = _asMap(payload['user']);
  final sessionSummary = _accountSessionSummaryFromUserPayload(user);
  controller.accountSessionTokenInternal = token;
  controller.accountSessionInternal = sessionSummary;
  await controller.storeInternal.saveAccountSessionToken(token);
  await controller.storeInternal.saveAccountSessionExpiresAtMs(
    _parseExpiresAtMs(payload['expiresAt']),
  );
  await controller.storeInternal.saveAccountSessionUserId(
    sessionSummary.userId,
  );
  await controller.storeInternal.saveAccountSessionIdentifier(identifier);
  await controller.storeInternal.saveAccountSessionSummary(sessionSummary);
  await syncAccountSettingsInternal(
    controller,
    baseUrl: baseUrl,
    profilePayloadOverride: payload,
    quiet: true,
  );
  await controller.reloadDerivedStateInternal();
  final email = controller.accountSessionInternal?.email.trim() ?? '';
  controller.accountStatusInternal = email.isEmpty
      ? 'Signed in'
      : 'Signed in as $email';
}

Future<void> restoreAccountSessionSettingsInternal(
  SettingsController controller, {
  String baseUrl = '',
  bool quiet = false,
}) async {
  final normalizedBaseUrl = normalizeAccountBaseUrlSettingsInternal(
    baseUrl,
    fallback: controller.snapshotInternal.accountBaseUrl,
  );
  final token =
      (await controller.storeInternal.loadAccountSessionToken())?.trim() ?? '';
  if (normalizedBaseUrl.isEmpty || token.isEmpty) {
    return;
  }

  if (!quiet) {
    controller.accountBusyInternal = true;
    controller.accountStatusInternal = 'Restoring account session...';
    controller.notifyListeners();
  }

  try {
    final client = controller.buildAccountClient(normalizedBaseUrl);
    final payload = await client.loadProfile(token: token);
    final session = _accountSessionSummaryFromUserPayload(
      _asMap(payload['user']),
    );
    await controller.storeInternal.saveAccountSessionSummary(session);
    if (session.userId.trim().isNotEmpty) {
      await controller.storeInternal.saveAccountSessionUserId(session.userId);
    }
    final identifier = session.email.trim().isNotEmpty
        ? session.email.trim()
        : (await controller.storeInternal.loadAccountSessionIdentifier())
                  ?.trim() ??
              '';
    if (identifier.isNotEmpty) {
      await controller.storeInternal.saveAccountSessionIdentifier(identifier);
    }
    controller.accountStatusInternal = session.email.trim().isEmpty
        ? 'Signed in'
        : 'Signed in as ${session.email.trim()}';
    await syncAccountSettingsInternal(
      controller,
      baseUrl: normalizedBaseUrl,
      profilePayloadOverride: payload,
      quiet: true,
    );
  } on AccountRuntimeException catch (error) {
    if (error.statusCode == 401) {
      await logoutAccountSettingsInternal(
        controller,
        statusMessage: 'Session expired',
        quiet: true,
      );
    } else {
      controller.accountStatusInternal =
          'Session restore failed: ${error.message}';
    }
  } finally {
    if (!quiet) {
      controller.accountBusyInternal = false;
      controller.notifyListeners();
    }
  }
}

Future<AccountSyncResult> syncAccountSettingsInternal(
  SettingsController controller, {
  String baseUrl = '',
  bool quiet = false,
  Map<String, dynamic> profilePayloadOverride = const <String, dynamic>{},
}) async {
  final normalizedBaseUrl = normalizeAccountBaseUrlSettingsInternal(
    baseUrl,
    fallback: controller.snapshotInternal.accountBaseUrl,
  );
  final sessionToken =
      (await controller.storeInternal.loadAccountSessionToken())?.trim() ?? '';
  if (sessionToken.isEmpty) {
    return _persistAccountSyncFailureInternal(
      controller,
      state: 'blocked',
      message: 'Account session is unavailable',
      quiet: quiet,
    );
  }

  if (!quiet) {
    controller.accountBusyInternal = true;
    controller.accountStatusInternal = 'Syncing bridge access...';
    controller.notifyListeners();
  }

  try {
    if (normalizedBaseUrl.isEmpty) {
      return _persistAccountSyncContractFailureInternal(
        controller,
        message: 'Account base URL is required',
        quiet: quiet,
      );
    }

    final client = controller.buildAccountClient(normalizedBaseUrl);
    Map<String, dynamic> profilePayload = profilePayloadOverride;
    if (profilePayload.isEmpty) {
      profilePayload = await client.loadProfile(token: sessionToken);
    }
    await _persistAccountSessionSummaryFromProfilePayloadInternal(
      controller,
      profilePayload,
    );

    final syncPayload = await client.loadXWorkmateProfileSync(
      token: sessionToken,
    );
    final bridgeToken = _extractBridgeAuthTokenMetadata(syncPayload);
    if (bridgeToken.isEmpty) {
      return _persistAccountSyncContractFailureInternal(
        controller,
        message: 'Bridge authorization is unavailable',
        quiet: quiet,
      );
    }

    await controller.storeInternal.saveAccountManagedSecret(
      target: kAccountManagedSecretTargetBridgeAuthToken,
      value: bridgeToken,
    );
    final syncedBridgeServerUrl = _extractBridgeServerUrlMetadata(syncPayload);
    await controller.storeInternal.clearAccountManagedSecret(
      target: kAccountManagedSecretTargetAIGatewayAccessToken,
    );
    await controller.storeInternal.clearAccountManagedSecret(
      target: kAccountManagedSecretTargetOllamaCloudApiKey,
    );

    final nextState = AccountSyncState.defaults().copyWith(
      syncedDefaults: AccountRemoteProfile.defaults().copyWith(
        bridgeServerUrl: syncedBridgeServerUrl,
      ),
      syncState: 'ready',
      syncMessage: 'Bridge access synced',
      lastSyncAtMs: DateTime.now().millisecondsSinceEpoch,
      lastSyncSource: syncedBridgeServerUrl,
      lastSyncError: '',
      profileScope: 'bridge',
      tokenConfigured: const AccountTokenConfigured(bridge: true, vault: false),
    );
    await _persistAccountSyncStateInternal(controller, nextState);
    final currentSettings = controller.snapshotInternal;
    final currentModeConfig = currentSettings.acpBridgeServerModeConfig;

    final nextEffective = resolveAcpBridgeServerEffectiveConfigInternal(
      controller,
      config: currentModeConfig,
    );

    final identifier =
        (await controller.storeInternal.loadAccountSessionIdentifier())
            ?.trim() ??
        '';
    final nextModeConfig = currentModeConfig.copyWith(
      effective: nextEffective,
      cloudSynced: currentModeConfig.cloudSynced.copyWith(
        accountBaseUrl:
            currentModeConfig.cloudSynced.accountBaseUrl.trim().isEmpty
            ? normalizedBaseUrl
            : currentModeConfig.cloudSynced.accountBaseUrl,
        accountIdentifier:
            currentModeConfig.cloudSynced.accountIdentifier.trim().isEmpty
            ? identifier
            : currentModeConfig.cloudSynced.accountIdentifier,
        lastSyncAt: nextState.lastSyncAtMs,
        remoteServerSummary: currentModeConfig.cloudSynced.remoteServerSummary
            .copyWith(endpoint: syncedBridgeServerUrl),
      ),
    );
    final sanitizedSettings = _sanitizeBridgeOnlyAccountSyncSettings(
      currentSettings.copyWith(acpBridgeServerModeConfig: nextModeConfig),
    );
    // Always save the snapshot after a successful sync to ensure Token and URL updates
    // are correctly persisted in the store and reflected in the UI.
    await controller.saveSnapshot(sanitizedSettings);

    await controller.reloadDerivedStateInternal();
    final email = controller.accountSessionInternal?.email.trim() ?? '';
    controller.accountStatusInternal = email.isEmpty
        ? 'Signed in'
        : 'Signed in as $email';
    if (!quiet) {
      controller.accountBusyInternal = false;
      controller.notifyListeners();
    }
    return const AccountSyncResult(
      state: 'ready',
      message: 'Bridge access synced',
    );
  } on AccountRuntimeException catch (error) {
    return _persistAccountSyncContractFailureInternal(
      controller,
      message: error.message,
      quiet: quiet,
    );
  } catch (error) {
    return _persistAccountSyncContractFailureInternal(
      controller,
      message: error.toString(),
      quiet: quiet,
    );
  }
}

Future<void> logoutAccountSettingsInternal(
  SettingsController controller, {
  String statusMessage = 'Signed out',
  bool quiet = false,
}) async {
  if (!quiet) {
    controller.accountBusyInternal = true;
    controller.notifyListeners();
  }
  controller.pendingAccountMfaTicketInternal = '';
  controller.pendingAccountBaseUrlInternal = '';
  await controller.storeInternal.clearAccountSessionToken();
  await controller.storeInternal.clearAccountSessionExpiresAtMs();
  await controller.storeInternal.clearAccountSessionUserId();
  await controller.storeInternal.clearAccountSessionIdentifier();
  await controller.storeInternal.clearAccountSessionSummary();
  await controller.storeInternal.clearAccountSyncState();
  await controller.storeInternal.clearAccountManagedSecrets();
  final currentSnapshot = controller.snapshotInternal;
  final clearedCloudSync = currentSnapshot.acpBridgeServerModeConfig.cloudSynced
      .copyWith(
        accountBaseUrl: quiet
            ? currentSnapshot
                  .acpBridgeServerModeConfig
                  .cloudSynced
                  .accountBaseUrl
            : '',
        accountIdentifier: quiet
            ? currentSnapshot
                  .acpBridgeServerModeConfig
                  .cloudSynced
                  .accountIdentifier
            : '',
        lastSyncAt: 0,
        remoteServerSummary: currentSnapshot
            .acpBridgeServerModeConfig
            .cloudSynced
            .remoteServerSummary
            .copyWith(endpoint: ''),
      );
  await controller.saveSnapshot(
    currentSnapshot.copyWith(
      acpBridgeServerModeConfig: currentSnapshot.acpBridgeServerModeConfig
          .copyWith(cloudSynced: clearedCloudSync),
    ),
  );
  controller.accountStatusInternal = statusMessage;
  if (!quiet) {
    controller.accountBusyInternal = false;
    controller.notifyListeners();
  }
}

Future<AccountSyncResult> markAccountBridgeRuntimeUnavailableInternal(
  SettingsController controller, {
  required String message,
}) async {
  final current = controller.accountSyncStateInternal;
  final nextState = (current ?? AccountSyncState.defaults()).copyWith(
    syncState: 'blocked',
    syncMessage: message,
    lastSyncAtMs: DateTime.now().millisecondsSinceEpoch,
    lastSyncError: message,
    profileScope: 'bridge',
  );
  await _persistAccountSyncStateInternal(controller, nextState);
  controller.accountStatusInternal = message;
  controller.notifyListeners();
  return AccountSyncResult(state: 'blocked', message: message);
}

Future<void> cancelAccountMfaChallengeSettingsInternal(
  SettingsController controller,
) async {
  controller.pendingAccountMfaTicketInternal = '';
  controller.pendingAccountBaseUrlInternal = '';
  if (!controller.accountSignedIn) {
    controller.accountStatusInternal = 'Signed out';
  }
  controller.notifyListeners();
}

AccountSessionSummary _accountSessionSummaryFromUserPayload(
  Map<String, dynamic> user,
) {
  final mfa = _asMap(user['mfa']);
  final totpEnabled = mfa['totpEnabled'] as bool? ?? false;
  final totpPending = mfa['totpPending'] as bool? ?? false;
  return AccountSessionSummary(
    userId: _stringValue(user['id']),
    email: _stringValue(user['email']),
    name: _stringValue(user['name']).isNotEmpty
        ? _stringValue(user['name'])
        : _stringValue(user['username']),
    role: _stringValue(user['role']),
    mfaEnabled: user['mfaEnabled'] as bool? ?? totpEnabled,
    totpEnabled: totpEnabled,
    totpPending: totpPending,
  );
}

String normalizeAccountBaseUrlSettingsInternal(
  String raw, {
  String fallback = '',
}) {
  final candidate = raw.trim().isNotEmpty ? raw.trim() : fallback.trim();
  if (candidate.isEmpty) {
    return '';
  }
  return candidate.endsWith('/')
      ? candidate.substring(0, candidate.length - 1)
      : candidate;
}

SettingsSnapshot _sanitizeBridgeOnlyAccountSyncSettings(
  SettingsSnapshot settings,
) {
  final normalizedAiGatewayRef =
      settings.aiGateway.apiKeyRef.trim() ==
          kAccountManagedSecretTargetAIGatewayAccessToken
      ? AiGatewayProfile.defaults().apiKeyRef
      : settings.aiGateway.apiKeyRef;
  final normalizedOllamaRef =
      settings.ollamaCloud.apiKeyRef.trim() ==
          kAccountManagedSecretTargetOllamaCloudApiKey
      ? OllamaCloudConfig.defaults().apiKeyRef
      : settings.ollamaCloud.apiKeyRef;
  return settings.copyWith(
    aiGateway: settings.aiGateway.copyWith(apiKeyRef: normalizedAiGatewayRef),
    ollamaCloud: settings.ollamaCloud.copyWith(apiKeyRef: normalizedOllamaRef),
  );
}

Future<void> _persistAccountSessionSummaryFromProfilePayloadInternal(
  SettingsController controller,
  Map<String, dynamic> payload,
) async {
  final user = _asMap(payload['user']);
  if (user.isEmpty) {
    return;
  }
  final summary = _accountSessionSummaryFromUserPayload(user);
  final hasSessionDetails =
      summary.userId.trim().isNotEmpty ||
      summary.email.trim().isNotEmpty ||
      summary.name.trim().isNotEmpty ||
      summary.role.trim().isNotEmpty;
  if (!hasSessionDetails) {
    return;
  }
  await controller.storeInternal.saveAccountSessionSummary(summary);
  if (summary.userId.trim().isNotEmpty) {
    await controller.storeInternal.saveAccountSessionUserId(summary.userId);
  }
  if (summary.email.trim().isNotEmpty) {
    await controller.storeInternal.saveAccountSessionIdentifier(
      summary.email.trim(),
    );
  }
  final identifier = summary.email.trim().isNotEmpty
      ? summary.email.trim()
      : (await controller.storeInternal.loadAccountSessionIdentifier())
                ?.trim() ??
            controller.snapshotInternal.accountUsername.trim();
  if (identifier.isNotEmpty) {
    await controller.storeInternal.saveAccountSessionIdentifier(identifier);
  }
}

Future<AccountSyncResult> _persistAccountSyncFailureInternal(
  SettingsController controller, {
  required String state,
  required String message,
  required bool quiet,
}) async {
  await _persistAccountSyncStateInternal(
    controller,
    AccountSyncState.defaults().copyWith(
      syncState: state,
      syncMessage: message,
      lastSyncAtMs: DateTime.now().millisecondsSinceEpoch,
      lastSyncError: message,
      profileScope: 'bridge',
    ),
  );
  controller.accountStatusInternal = message;
  if (!quiet) {
    controller.accountBusyInternal = false;
    controller.notifyListeners();
  }
  return AccountSyncResult(state: state, message: message);
}

Future<AccountSyncResult> _persistAccountSyncContractFailureInternal(
  SettingsController controller, {
  required String message,
  required bool quiet,
}) async {
  await controller.storeInternal.clearAccountManagedSecret(
    target: kAccountManagedSecretTargetBridgeAuthToken,
  );
  return _persistAccountSyncFailureInternal(
    controller,
    state: 'blocked',
    message: message,
    quiet: quiet,
  );
}

String _extractBridgeServerUrlMetadata(Map<String, dynamic> payload) {
  final explicit = _stringValue(payload['BRIDGE_SERVER_URL']);
  if (explicit.isNotEmpty) {
    return explicit;
  }
  final camelCase = _stringValue(payload['bridgeServerUrl']);
  if (camelCase.isNotEmpty) {
    return camelCase;
  }
  return '';
}

String _extractBridgeAuthTokenMetadata(Map<String, dynamic> payload) {
  final aiWorkspaceToken = _stringValue(payload['AI_WORKSPACE_AUTH_TOKEN']);
  if (aiWorkspaceToken.isNotEmpty) {
    return aiWorkspaceToken;
  }
  return _stringValue(payload['BRIDGE_AUTH_TOKEN']);
}

AcpBridgeServerEffectiveConfig resolveAcpBridgeServerEffectiveConfigInternal(
  SettingsController controller, {
  required AcpBridgeServerModeConfig config,
}) {
  final accountSyncState = controller.accountSyncState;
  final managedBridgeReady =
      controller.accountSessionTokenInternal.trim().isNotEmpty &&
      accountSyncState?.syncState.trim().toLowerCase() == 'ready' &&
      accountSyncState?.tokenConfigured.bridge == true;
  if (managedBridgeReady) {
    return const AcpBridgeServerEffectiveConfig(
      endpoint: kManagedBridgeServerUrl,
      tokenRef: '',
      source: 'cloud',
      reason: 'Account sync is ready and the managed bridge token is available',
    );
  }

  if (config.selfHosted.isConfigured) {
    return AcpBridgeServerEffectiveConfig(
      endpoint: config.selfHosted.serverUrl,
      tokenRef: config.selfHosted.passwordRef,
      source: 'bridge',
      reason: 'Manual Bridge configuration is present and valid',
    );
  }

  return AcpBridgeServerEffectiveConfig(
    endpoint: '',
    tokenRef: '',
    source: 'default',
    reason: 'No active Bridge source is configured',
  );
}

Future<SettingsSnapshot> buildSavedAccountProfileSettingsInternal(
  SettingsController controller, {
  required SettingsSnapshot settings,
  required String accountBaseUrl,
  required String accountIdentifier,
  required String bridgeServerUrl,
  required String bridgeToken,
  required bool isManualBridge,
}) async {
  final bridgeConfig = settings.acpBridgeServerModeConfig;
  final trimmedBridgeServerUrl = bridgeServerUrl.trim();
  final trimmedBridgeToken = bridgeToken.trim();
  final existingBridgeToken = isManualBridge
      ? ((await controller.storeInternal.loadSecretValueByRef(
              bridgeConfig.selfHosted.passwordRef,
            ))?.trim() ??
            '')
      : '';
  if (isManualBridge) {
    _validateManualBridgeProfile(
      serverUrl: trimmedBridgeServerUrl,
      tokenConfigured:
          trimmedBridgeToken.isNotEmpty || existingBridgeToken.isNotEmpty,
    );
  }
  final nextBridgeConfig = bridgeConfig.copyWith(
    selfHosted: isManualBridge
        ? bridgeConfig.selfHosted.copyWith(
            serverUrl: trimmedBridgeServerUrl,
            username: 'admin',
          )
        : bridgeConfig.selfHosted,
  );
  final nextEffective = resolveAcpBridgeServerEffectiveConfigInternal(
    controller,
    config: nextBridgeConfig,
  );
  final nextSettings = settings.copyWith(
    accountBaseUrl: accountBaseUrl.trim(),
    accountUsername: accountIdentifier.trim(),
    acpBridgeServerModeConfig: nextBridgeConfig.copyWith(
      effective: nextEffective,
    ),
  );
  if (isManualBridge && trimmedBridgeToken.isNotEmpty) {
    await controller.saveSecretValueByRef(
      nextSettings.acpBridgeServerModeConfig.selfHosted.passwordRef,
      trimmedBridgeToken,
      provider: 'Bridge',
      module: 'Manual',
    );
  }
  return nextSettings;
}

void _validateManualBridgeProfile({
  required String serverUrl,
  required bool tokenConfigured,
}) {
  if (serverUrl.isEmpty) {
    throw ArgumentError.value(
      serverUrl,
      'bridgeServerUrl',
      'Bridge URL is required',
    );
  }
  if (!tokenConfigured) {
    throw ArgumentError.value(
      '',
      'bridgeToken',
      'Bridge auth token is required',
    );
  }
  final uri = Uri.tryParse(serverUrl);
  if (uri == null || !uri.hasScheme || uri.host.trim().isEmpty) {
    throw ArgumentError.value(
      serverUrl,
      'bridgeServerUrl',
      'Bridge URL must be a valid URL',
    );
  }
  final scheme = uri.scheme.toLowerCase();
  final host = uri.host.toLowerCase();
  final isLocalHttp =
      scheme == 'http' &&
      (host == '127.0.0.1' || host == 'localhost') &&
      uri.hasPort &&
      uri.port >= 1 &&
      uri.port <= 65535;
  if (isLocalHttp) {
    return;
  }
  if (scheme == 'https') {
    return;
  }
  throw ArgumentError.value(
    serverUrl,
    'bridgeServerUrl',
    'Manual Bridge URL must be http://127.0.0.1:<port> or http://localhost:<port> for local mode, or https:// for public custom bridge mode',
  );
}

int _parseExpiresAtMs(Object? value) {
  if (value is int) {
    return value;
  }
  if (value is num) {
    return value.toInt();
  }
  final raw = _stringValue(value);
  if (raw.isEmpty) {
    return 0;
  }
  final asInt = int.tryParse(raw);
  if (asInt != null) {
    return asInt;
  }
  return DateTime.tryParse(raw)?.millisecondsSinceEpoch ?? 0;
}

Map<String, dynamic> _asMap(Object? value) {
  if (value is Map<String, dynamic>) {
    return value;
  }
  if (value is Map) {
    return value.cast<String, dynamic>();
  }
  return const <String, dynamic>{};
}

String _stringValue(Object? value) {
  return value?.toString().trim() ?? '';
}

Future<void> _persistAccountSyncStateInternal(
  SettingsController controller,
  AccountSyncState value,
) async {
  await controller.storeInternal.saveAccountSyncState(value);
  controller.accountSyncStateInternal = value;
}
