/*
 *   Famedly Matrix SDK
 *   Copyright (C) 2019, 2020 Famedly GmbH
 *
 *   This program is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU Affero General Public License as
 *   published by the Free Software Foundation, either version 3 of the
 *   License, or (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 *   GNU Affero General Public License for more details.
 *
 *   You should have received a copy of the GNU Affero General Public License
 *   along with this program.  If not, see .
 */
import 'dart:convert';
import 'package:http/http.dart' as http;
enum MatrixError {
  M_UNKNOWN,
  M_UNKNOWN_TOKEN,
  M_NOT_FOUND,
  M_FORBIDDEN,
  M_LIMIT_EXCEEDED,
  M_USER_IN_USE,
  M_THREEPID_IN_USE,
  M_THREEPID_DENIED,
  M_THREEPID_NOT_FOUND,
  M_THREEPID_AUTH_FAILED,
  M_TOO_LARGE,
  M_MISSING_PARAM,
  M_UNSUPPORTED_ROOM_VERSION,
  M_UNRECOGNIZED,
}
/// Represents a special response from the Homeserver for errors.
class MatrixException implements Exception {
  final Map raw;
  /// The unique identifier for this error.
  String get errcode =>
      raw['errcode'] ??
      (requireAdditionalAuthentication ? 'M_FORBIDDEN' : 'M_UNKNOWN');
  /// A human readable error description.
  String get errorMessage =>
      raw['error'] ??
      (requireAdditionalAuthentication
          ? 'Require additional authentication'
          : 'Unknown error');
  /// The frozen request which triggered this Error
  http.Response response;
  MatrixException(this.response) : raw = json.decode(response.body);
  MatrixException.fromJson(Map content) : raw = content;
  @override
  String toString() => '$errcode: $errorMessage';
  /// Returns the [ResponseError]. Is ResponseError.NONE if there wasn't an error.
  MatrixError get error => MatrixError.values.firstWhere(
      (e) => e.toString() == 'MatrixError.${(raw["errcode"] ?? "")}',
      orElse: () => MatrixError.M_UNKNOWN);
  int get retryAfterMs => raw['retry_after_ms'];
  /// This is a session identifier that the client must pass back to the homeserver, if one is provided,
  /// in subsequent attempts to authenticate in the same API call.
  String get session => raw['session'];
  /// Returns true if the server requires additional authentication.
  bool get requireAdditionalAuthentication => response != null
      ? response.statusCode == 401
      : authenticationFlows != null;
  /// For each endpoint, a server offers one or more 'flows' that the client can use
  /// to authenticate itself. Each flow comprises a series of stages. If this request
  /// doesn't need additional authentication, then this is null.
  List get authenticationFlows {
    if (!raw.containsKey('flows') || !(raw['flows'] is List)) return null;
    var flows = [];
    for (Map flow in raw['flows']) {
      if (flow['stages'] is List) {
        flows.add(AuthenticationFlow(List.from(flow['stages'])));
      }
    }
    return flows;
  }
  /// This section contains any information that the client will need to know in order to use a given type
  /// of authentication. For each authentication type presented, that type may be present as a key in this
  /// dictionary. For example, the public part of an OAuth client ID could be given here.
  Map get authenticationParams => raw['params'];
  /// Returns the list of already completed authentication flows from previous requests.
  List get completedAuthenticationFlows =>
      List.from(raw['completed'] ?? []);
}
/// For each endpoint, a server offers one or more 'flows' that the client can use
/// to authenticate itself. Each flow comprises a series of stages
class AuthenticationFlow {
  final List stages;
  const AuthenticationFlow(this.stages);
}