public class Tuba.API.Account : Entity, Widgetizable, SearchResult {
	public class FeatureApproval : Entity {
		public string current_user { get; set; }
		//  public Gee.ArrayList<string> automatic { get; set; }
		//  public Gee.ArrayList<string> manual { get; set; }

		//  public override Type deserialize_array_type (string prop) {
		//  	switch (prop) {
		//  		case "automatic":
		//  		case "manual":
		//  			return Type.STRING;
		//  	}

		//  	return base.deserialize_array_type (prop);
		//  }

		public bool tuba_can_invite {
			get {
				return this.current_user == "automatic" || this.current_user == "manual";
			}
		}
	}

	public bool tuba_row { get; set; default = false; }
	public API.Relationship? tuba_rs { get; set; default=null; }
	public GLib.Regex? tuba_search_query_regex { get; set; default = null; }

	public string id { get; set; }
	public string username { get; set; }
	public string acct { get; set; }

	/* internal display name representation */
	private string _display_name = "";
	/* User's display name: Specific display name, or falling back to the
	   nickname */
	public string display_name {
		set {
			_display_name = value;
		}
		get {
			return (( _display_name != null && _display_name.length > 0 ) ? _display_name : username );
		}
	}

	public string note { get; set; default=""; }
	public bool locked { get; set; }
	public string header { get; set; }
	public string? header_description { get; set; default=null; }
	public string avatar { get; set; }
	public string? avatar_description { get; set; default=null; }
	public string url { get; set; }
	public bool bot { get; set; default=false; }
	public bool limited { get; set; default=false; }
	public bool suspended { get; set; default=false; }
	public bool memorial { get; set; default=false; }
	public bool show_media { get; set; default=true; }
	public bool show_media_replies { get; set; default=true; }
	public bool show_featured { get; set; default=true; }
	public bool enable_rss { get; set; default=false; }
	public string created_at { get; set; }
	public Gee.ArrayList<API.Emoji>? emojis { get; set; }
	public int64 followers_count { get; set; }
	public int64 following_count { get; set; }
	public int64 statuses_count { get; set; }
	public string? last_status_at { get; set; default=null; }
	public Gee.ArrayList<API.AccountRole>? roles { get; set; default = null; }
	public Gee.ArrayList<API.AccountField>? fields { get; set; default = null; }
	public AccountSource? source { get; set; default = null; }
	public API.AccountRole? role { get; set; default = null; }
	public API.Account? moved { get; set; default = null; }
	public bool hide_collections { get; set; default = false; }
	public FeatureApproval? feature_approval { get; set; default = null; }

	public override Type deserialize_array_type (string prop) {
		switch (prop) {
			case "emojis":
				return typeof (API.Emoji);
			case "fields":
				return typeof (API.AccountField);
			case "roles":
				return typeof (API.AccountRole);
		}

		return base.deserialize_array_type (prop);
	}

	public string handle {
		owned get {
			return "@" + acct;
		}
	}
	public string domain {
		owned get {
			Uri uri;
			try {
				uri = Uri.parse (url, UriFlags.NONE);
			} catch (GLib.UriError e) {
				warning (e.message);
				return "";
			}
			return uri.get_host ();
		}
	}
	public string full_handle {
		owned get {
			return @"@$username@$domain";
		}
	}

	public Gee.HashMap<string, string>? emojis_map {
		owned get {
			return gen_emojis_map ();
		}
	}

	private Gee.HashMap<string, string>? gen_emojis_map () {
		var res = new Gee.HashMap<string, string> ();
		if (emojis != null && emojis.size > 0) {
			emojis.@foreach (e => {
				res.set (e.shortcode, e.url);
				return true;
			});
		}

		return res;
	}

	public static Account from (Json.Node node) throws Error {
		return Entity.from_json (typeof (API.Account), node) as API.Account;
	}

	public static RequestV2 search (string query) throws Error {
		var req = new RequestV2 ("/api/v1/accounts/search") { account = accounts.active };
		req.add_parameter ("q", query);
		req.add_parameter ("resolve", "false");
		req.add_parameter ("limit", "4");
		return req;
	}

	public bool is_self () {
		return id == accounts.active.id;
	}

	public override bool is_local (InstanceAccount account) {
		return account.domain in url;
	}

	public override Gtk.Widget to_widget () {
		if (this.tuba_row) {
			var widg = new Widgets.AccountRow (this, false);
			widg.add_rs_button (true);
			widg.enable_activation ();
			widg.add_followers_and_verified_link ();
			widg.add_note ();
			return widg;
		}
		return new Widgets.Account (this);
	}

	public override void open () {
		var view = new Views.Profile (this);
		app.main_window.open_view (view);
	}

	public override void resolve_open (InstanceAccount account) {
		if (is_local (account))
			open ();
		else {
			account.resolve.begin (url, (obj, res) => {
				try {
					account.resolve.end (res).open ();
				} catch (Error e) {
					warning (@"Error opening account: $(account.handle) - $(e.message)");
				}
			});
		}
	}

	public RequestV2 accept_follow_request () {
		return new RequestV2 (@"/api/v1/follow_requests/$id/authorize", POST) { account = accounts.active };
	}

	public RequestV2 decline_follow_request () {
		return new RequestV2 (@"/api/v1/follow_requests/$id/reject", POST) { account = accounts.active };
	}
}
