class OidcRedirectCheckResult {
  final Uri? uri;
  final bool isValid;
  final String reason;
  final int length;
  final String scheme;
  final String host;
  final String path;
  final int queryParamCount;
  final List<String> queryKeys;
  final bool hasLoginVerifier;
  final int loginVerifierLength;
  final bool hasState;
  final int stateLength;
  final bool hasClientId;
  final String clientId;
  final bool hasCodeChallenge;
  final int codeChallengeLength;
  final String codeChallengeMethod;
  final bool hasRedirectUri;
  final int redirectUriLength;
  final String redirectUriScheme;
  final String redirectUriHost;
  final int redirectUriPort;
  final String redirectUriPath;
  final String responseType;
  final int scopeCount;
  final bool isOidcAuthPath;

  const OidcRedirectCheckResult({
    required this.uri,
    required this.isValid,
    required this.reason,
    required this.length,
    required this.scheme,
    required this.host,
    required this.path,
    required this.queryParamCount,
    required this.queryKeys,
    required this.hasLoginVerifier,
    required this.loginVerifierLength,
    required this.hasState,
    required this.stateLength,
    required this.hasClientId,
    required this.clientId,
    required this.hasCodeChallenge,
    required this.codeChallengeLength,
    required this.codeChallengeMethod,
    required this.hasRedirectUri,
    required this.redirectUriLength,
    required this.redirectUriScheme,
    required this.redirectUriHost,
    required this.redirectUriPort,
    required this.redirectUriPath,
    required this.responseType,
    required this.scopeCount,
    required this.isOidcAuthPath,
  });

  Map<String, Object?> toDiagnostics() {
    return {
      'is_valid': isValid,
      'reason': reason,
      'length': length,
      'scheme': scheme,
      'host': host,
      'path': path,
      'is_oidc_auth_path': isOidcAuthPath,
      'query_param_count': queryParamCount,
      'query_keys': queryKeys,
      'has_login_verifier': hasLoginVerifier,
      'login_verifier_len': loginVerifierLength,
      'has_state': hasState,
      'state_len': stateLength,
      'has_client_id': hasClientId,
      'client_id': clientId,
      'has_code_challenge': hasCodeChallenge,
      'code_challenge_len': codeChallengeLength,
      'code_challenge_method': codeChallengeMethod,
      'has_redirect_uri': hasRedirectUri,
      'redirect_uri_len': redirectUriLength,
      'redirect_uri_scheme': redirectUriScheme,
      'redirect_uri_host': redirectUriHost,
      'redirect_uri_port': redirectUriPort,
      'redirect_uri_path': redirectUriPath,
      'response_type': responseType,
      'scope_count': scopeCount,
    };
  }
}

OidcRedirectCheckResult validateOidcRedirectTarget(String redirectTo) {
  final trimmed = redirectTo.trim();
  if (trimmed.isEmpty) {
    return const OidcRedirectCheckResult(
      uri: null,
      isValid: false,
      reason: 'empty',
      length: 0,
      scheme: '',
      host: '',
      path: '',
      queryParamCount: 0,
      queryKeys: [],
      hasLoginVerifier: false,
      loginVerifierLength: 0,
      hasState: false,
      stateLength: 0,
      hasClientId: false,
      clientId: '',
      hasCodeChallenge: false,
      codeChallengeLength: 0,
      codeChallengeMethod: '',
      hasRedirectUri: false,
      redirectUriLength: 0,
      redirectUriScheme: '',
      redirectUriHost: '',
      redirectUriPort: 0,
      redirectUriPath: '',
      responseType: '',
      scopeCount: 0,
      isOidcAuthPath: false,
    );
  }

  Uri parsed;
  try {
    parsed = Uri.parse(trimmed);
  } catch (_) {
    return OidcRedirectCheckResult(
      uri: null,
      isValid: false,
      reason: 'parse_error',
      length: trimmed.length,
      scheme: '',
      host: '',
      path: '',
      queryParamCount: 0,
      queryKeys: [],
      hasLoginVerifier: false,
      loginVerifierLength: 0,
      hasState: false,
      stateLength: 0,
      hasClientId: false,
      clientId: '',
      hasCodeChallenge: false,
      codeChallengeLength: 0,
      codeChallengeMethod: '',
      hasRedirectUri: false,
      redirectUriLength: 0,
      redirectUriScheme: '',
      redirectUriHost: '',
      redirectUriPort: 0,
      redirectUriPath: '',
      responseType: '',
      scopeCount: 0,
      isOidcAuthPath: false,
    );
  }

  final scheme = parsed.scheme.toLowerCase();
  final isHttpScheme = scheme == 'http' || scheme == 'https';
  final isAbsolute = parsed.hasScheme && parsed.host.isNotEmpty;
  final isValid = isHttpScheme && isAbsolute;
  final query = parsed.queryParameters;
  final queryKeys = query.keys.toList()..sort();
  final loginVerifier = query['login_verifier'] ?? '';
  final state = query['state'] ?? '';
  final clientId = query['client_id'] ?? '';
  final codeChallenge = query['code_challenge'] ?? '';
  final codeChallengeMethod = query['code_challenge_method'] ?? '';
  final redirectUriValue = query['redirect_uri'] ?? query['redirect_url'] ?? '';
  final responseType = query['response_type'] ?? '';
  final scope = query['scope'] ?? '';

  final Uri? redirectUriParsed = redirectUriValue.isEmpty
      ? null
      : Uri.tryParse(redirectUriValue);
  final redirectUriScheme = redirectUriParsed?.scheme ?? '';
  final redirectUriHost = redirectUriParsed?.host ?? '';
  final redirectUriPort = redirectUriParsed?.port ?? 0;
  final redirectUriPath = redirectUriParsed?.path ?? '';
  final scopeCount = scope.isEmpty
      ? 0
      : scope.split(RegExp(r'\s+')).where((s) => s.isNotEmpty).length;

  final reason = isValid
      ? 'ok'
      : (isAbsolute ? 'unsupported_scheme' : 'not_absolute');

  return OidcRedirectCheckResult(
    uri: isValid ? parsed : null,
    isValid: isValid,
    reason: reason,
    length: trimmed.length,
    scheme: scheme,
    host: parsed.host,
    path: parsed.path,
    queryParamCount: query.length,
    queryKeys: queryKeys,
    hasLoginVerifier: loginVerifier.isNotEmpty,
    loginVerifierLength: loginVerifier.length,
    hasState: state.isNotEmpty,
    stateLength: state.length,
    hasClientId: clientId.isNotEmpty,
    clientId: clientId,
    hasCodeChallenge: codeChallenge.isNotEmpty,
    codeChallengeLength: codeChallenge.length,
    codeChallengeMethod: codeChallengeMethod,
    hasRedirectUri: redirectUriValue.isNotEmpty,
    redirectUriLength: redirectUriValue.length,
    redirectUriScheme: redirectUriScheme,
    redirectUriHost: redirectUriHost,
    redirectUriPort: redirectUriPort,
    redirectUriPath: redirectUriPath,
    responseType: responseType,
    scopeCount: scopeCount,
    isOidcAuthPath: parsed.path == '/oidc/oauth2/auth',
  );
}
