/* -*- Mode: Vala; indent-tabs-mode: nil; tab-width: 2 -*-
 *
 * SPDX-License-Identifier: GPL-3.0-or-later
 * SPDX-FileCopyrightText: Michael Terry
 */

using GLib;

errordomain DejaDup.BackendError {
    MOUNT_OP_NEEDED,
}

public abstract class DejaDup.Backend : Object
{
  public enum Kind {
    UNKNOWN,
    LOCAL,
    GVFS,
    GOOGLE,
    MICROSOFT,
    RCLONE,
  }
  public Kind kind {get; construct; default=Kind.UNKNOWN;}

  public Settings settings {get; construct;}

  public signal void pause_op(string? header, string? msg);

  public signal void show_backend_password_page(string desc, string label, string? error);
  public bool needs_backend_password {get; protected set;}
  public virtual async void provide_backend_password(string password, bool save) {}

  public signal void show_oauth_consent_page(string message, string header, string url);

  public MountOperation mount_op {get; set;}

  public abstract bool is_native(); // must be callable when nothing is mounted, nothing is prepared

  public virtual Icon? get_icon() {return null;}
  public Icon get_icon_safe() {
    var icon = get_icon();
    return icon == null ? new ThemedIcon("folder") : icon;
  }

  public abstract string get_location_pretty(); // short description for user

  // Returns a short hash of this backend location, to distinguish it from
  // other backend locations (useful for caches or mount dirs).
  // Is not suitable for security-oriented tasks, as it uses MD5.
  // Only call this after prepare().
  public string get_unique_id() {
    var location = get_unique_location();
    // Version the unique ID with a prefix, just in case.
    return "0." + Checksum.compute_for_string(ChecksumType.MD5, location);
  }
  protected abstract string get_unique_location();

  // list of what-provides hints
  public virtual string[] get_dependencies() {return {};}
  public virtual bool needs_dependencies() {return true;}

  // must be callable when nothing is mounted, nothing is prepared
  public virtual async bool is_ready(out string reason, out string message) {
    reason = null;
    message = null;
    return true;
  }

  // If return is false, reason will hold a user-visible message.
  // This method is useful for cases like "local folder is not accessible"
  // inside a container.
  // Not async, because this is often used for quick UI feedback.
  public virtual bool is_acceptable(out string reason)
  {
    reason = null;
    return true;
  }

  // Lets the backend mount itself or whatever else it needs
  public virtual async void prepare() throws Error {}

  public virtual async void cleanup() {}

  // Must be prepared already. Returns at least 20 files (used for detecting
  // what type of tool repository is present, if any). Ignores hidden files
  // (usually dotfiles, but that can be filesystem dependent).
  // May return files in any order from the directory (i.e. the last 20
  // non-hidden files).
  public virtual async List<string> peek_at_files() {return new List<string>();}

  // Only called during backup
  public const uint64 INFINITE_SPACE = uint64.MAX;
  public virtual async void get_space(out uint64 free, out uint64 total) {
    free = INFINITE_SPACE;
    total = INFINITE_SPACE;
  }

  public virtual void add_excludes(ref List<File> excludes) {}

  public static Backend get_for_key(string key, Settings? settings = null)
  {
    if (key == "auto")
      return new BackendAuto();
    else if (key == "google")
      return new BackendGoogle(settings);
    else if (key == "microsoft")
      return new BackendMicrosoft(settings);
    else if (key == "drive")
      return new BackendDrive(settings);
    else if (key == "remote")
      return new BackendRemote(settings);
    else if (key == "local")
      return new BackendLocal(settings);
    else if (key == "rclone")
      return new BackendRclone(settings);
    else
      return new BackendUnsupported(key);
  }

  public static string get_key_name(Settings settings)
  {
    return settings.get_string(BACKEND_KEY);
  }

  public static Backend get_default()
  {
    return get_for_key(get_default_key());
  }

  public static string get_default_key()
  {
    return get_key_name(get_settings());
  }
}
