// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'dart:io';

import 'package:collection/collection.dart';
import 'package:http/http.dart' as http;
import 'package:http_parser/http_parser.dart';

import '../http.dart';
import '../log.dart' as log;
import '../system_cache.dart';
import '../utils.dart';
import 'credential.dart';

/// This client authenticates requests by injecting `Authentication` header to
/// requests.
///
/// Requests to URLs not under [_credential]'s url will not be authenticated.
class _AuthenticatedClient extends http.BaseClient {
  /// Constructs Http client wrapper that injects `authorization` header to
  /// requests and handles authentication errors.
  ///
  /// [_credential] might be `null`. In that case `authorization` header will
  /// not be injected to requests.
  _AuthenticatedClient(this._inner, this._credential);

  final http.BaseClient _inner;

  /// Authentication scheme that could be used for authenticating requests.
  final Credential? _credential;

  /// Detected that [_credential] are invalid, happens when server responds 401.
  bool _detectInvalidCredentials = false;

  @override
  Future<http.StreamedResponse> send(http.BaseRequest request) async {
    // Let's last time make sure that, we're allowed to use credential for this
    // request.
    //
    // This check ensures that this client will only authenticate requests sent
    // to given serverBaseUrl. Otherwise credential leaks might occur when
    // archive_url hosted on 3rd party server that should not receive
    // credentials of the first party.
    if (_credential != null &&
        _credential.canAuthenticate(request.url.toString())) {
      request.headers[HttpHeaders.authorizationHeader] =
          await _credential.getAuthorizationHeaderValue();
    }

    final response = await _inner.send(request);
    if (response.statusCode == 401) {
      _detectInvalidCredentials = true;
    }
    if (response.statusCode == 401 || response.statusCode == 403) {
      _throwAuthException(response);
    }
    return response;
  }

  /// Throws [AuthenticationException] that includes response status code and
  /// message parsed from WWW-Authenticate header usign
  /// [RFC 7235 section 4.1][RFC] specifications.
  ///
  /// [RFC]: https://datatracker.ietf.org/doc/html/rfc7235#section-4.1
  void _throwAuthException(http.BaseResponse response) {
    String? serverMessage;
    if (response.headers.containsKey(HttpHeaders.wwwAuthenticateHeader)) {
      try {
        final header = response.headers[HttpHeaders.wwwAuthenticateHeader]!;
        final challenge = AuthenticationChallenge.parseHeader(
          header,
        ).firstWhereOrNull(
          (challenge) =>
              challenge.scheme == 'bearer' &&
              challenge.parameters['realm'] == 'pub' &&
              challenge.parameters['message'] != null,
        );
        if (challenge != null) {
          serverMessage = challenge.parameters['message'];
        }
      } on FormatException {
        // Ignore errors might be caused when parsing invalid header values
      }
    }
    if (serverMessage != null) {
      serverMessage = sanitizeForTerminal(serverMessage);
    }
    throw AuthenticationException(response.statusCode, serverMessage);
  }

  @override
  void close() => _inner.close();
}

/// Token authenticated related exception.
class AuthenticationException implements Exception {
  const AuthenticationException(this.statusCode, this.serverMessage);

  final int statusCode;
  final String? serverMessage;

  @override
  String toString() {
    var message = 'Authentication error ($statusCode)';
    if (serverMessage != null) {
      message += ': $serverMessage';
    }
    return message;
  }
}

/// Invoke [fn] with a [http.Client] capable of authenticating against
/// [hostedUrl].
///
/// Importantly, requests to URLs not under [hostedUrl] will not be
/// authenticated.
Future<T> withAuthenticatedClient<T>(
  SystemCache systemCache,
  Uri hostedUrl,
  Future<T> Function(http.Client) fn,
) async {
  final credential = systemCache.tokenStore.findCredential(hostedUrl);
  final client = _AuthenticatedClient(globalHttpClient, credential);

  try {
    return await fn(client);
  } finally {
    if (client._detectInvalidCredentials) {
      // try to remove the credential, if we detected that it is invalid!
      final removed = systemCache.tokenStore.removeCredential(hostedUrl);
      if (removed) {
        log.warning('Invalid token for $hostedUrl deleted.');
      }
    }
  }
}
