import 'otpauth_migration.dart';
import 'totp_algorithm.dart';
import 'totp_item.dart' show TotpItem;


/// Parses TOTP key URI into TOTPItems.
///
/// Reference:
/// * https://github.com/google/google-authenticator/wiki/Key-Uri-Format
class OtpUri {
  /// Parses a TOTP key URI and returns a TOTP object
  static TotpItem fromUri(String uri) {
    // Use dart-core/Uri to parse
    var parsed = Uri.parse(uri);

    // Check scheme
    if (parsed.scheme != "otpauth") {
      try {
        final otp_auth_parser = OtpAuthMigration();

        List<String> parseds = otp_auth_parser.decode(uri);
        parsed = Uri.parse(parseds.first);
      } catch (e) {
        throw FormatException("Not OTP URI");
      }

    }
    if (parsed.authority != "totp" && parsed.authority != "hotp") {
      throw FormatException("Unsupported authority");
    }

    // Extract issuer/account name
    if (parsed.pathSegments.length > 1) {
      throw FormatException("Should have more than 1 path segment");
    }
    var pathSplit = parsed.pathSegments[0].split(':');
    var issuer = pathSplit[0];
    var accountName = pathSplit.length > 1 ? pathSplit[1] : '';

    // Extract algorithm, digits, period and secret
    var algorithm = "sha1";
    var digits = 6;
    var period = 30;
    var secret = "";

    if (!parsed.queryParameters.containsKey("secret")) {
      throw FormatException("Query parameter does not contain secret");
    }
    secret = parsed.queryParameters["secret"]!;

    if (parsed.queryParameters.containsKey("algorithm")) {
      algorithm = parsed.queryParameters["algorithm"]!.toLowerCase();
      if (algorithm != "sha1" &&
          algorithm != "sha256" &&
          algorithm != "sha512") {
        throw FormatException("Unrecognised algorithm");
      }
    }

    if (parsed.queryParameters.containsKey("digits")) {
      digits = int.parse(parsed.queryParameters["digits"]!);
    }

    if (parsed.queryParameters.containsKey("period")) {
      period = int.parse(parsed.queryParameters["period"]!);
    }

    try {
      return TotpItem.newTotpItem(secret, digits, period,
          OtpHashAlgorithm.fromString(algorithm), issuer, accountName);
    } catch (error) {
      throw FormatException("Incorrect parameters");
    }
  }
}
