import 'dart:convert';

import 'package:result_monad/src/result_monad_base.dart';
import 'package:uuid/uuid.dart';

import '../exec_error.dart';
import 'credentials_intf.dart';

class BasicCredentials implements ICredentials {
  @override
  late final String id;
  final String username;
  final String password;
  @override
  final String serverName;
  late final String _authHeaderValue;

  @override
  String get authHeaderValue => _authHeaderValue;

  BasicCredentials({
    String? id,
    required this.username,
    required this.password,
    required this.serverName,
  }) {
    this.id = id ?? const Uuid().v4();
    final authenticationString = "$username:$password";
    final encodedAuthString = base64Encode(utf8.encode(authenticationString));
    _authHeaderValue = "Basic $encodedAuthString";
  }

  factory BasicCredentials.fromJson(Map<String, dynamic> json) =>
      BasicCredentials(
        username: json['username'],
        password: json['password'],
        serverName: json['serverName'],
      );

  factory BasicCredentials.empty() => BasicCredentials(
        username: '',
        password: '',
        serverName: '',
      );

  bool get isEmpty =>
      username.isEmpty && password.isEmpty && serverName.isEmpty;

  BasicCredentials copy({
    String? username,
    String? password,
    String? serverName,
  }) {
    return BasicCredentials(
      username: username ?? this.username,
      password: password ?? this.password,
      serverName: serverName ?? this.serverName,
    );
  }

  @override
  String toString() {
    return 'Credentials{username: $username, password?: ${password.isNotEmpty}, serverName: $serverName}';
  }

  @override
  FutureResult<ICredentials, ExecError> signIn() async {
    return Result.ok(this);
  }

  @override
  Map<String, dynamic> toJson() => {
        'username': username,
        'password': password,
        'serverName': serverName,
      };

  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
      other is BasicCredentials &&
          runtimeType == other.runtimeType &&
          id == other.id;

  @override
  int get hashCode => id.hashCode;
}
