const filterBuilder = require("./utils/filters");

/**
 * Search for items on AniList
 * @since 1.7.0
 * @memberof AniList
 */
class Search {
	/**
	 * @description This constructor is meant for internal use and is apart of initializing. You cannot access this
	 * through the AniList class and are not expect to.
	 * @param { Utilities } utilities - The AniList Utilities class.
	 * @hideconstructor
	 */
	constructor(utilities) {
		this.util = utilities;
	}

	/**
	 * Search for a specific character
	 * @param {String} term - Required. The term to lookup. (ie: "Myne" or "Chise Hatori")
	 * @param {Number} page - Which page of the results to look at. Will default to 1 if not provided.
	 * @param {Number} amount - The amount of results per page. AniList will cap this at 25 and function will default to 5 if not provided.
	 * @return { SearchEntry }
	 * @since 1.7.0
	 */
	character(term, page = 1, amount = 5) {
		if (!term) {
			throw new Error("Search term was not provided!");
		}

		//Validate all type conditions.
		if (typeof term !== "string") {
			throw new Error("Term is not a string");
		}
		if (typeof page !== "number") {
			throw new Error("Page number is not a number");
		}
		if (typeof amount !== "number") {
			throw new Error("Amount is not a number");
		}

		return this.util.send(
			`query ($page: Int, $perPage: Int, $search: String) {
            Page (page: $page, perPage: $perPage) { pageInfo { total currentPage lastPage hasNextPage perPage } 
            characters (search: $search) { id name { english: full } } } }`,
			{ search: term, page: page, perPage: amount }
		);
	}

	/**
	 * Search for a specific studio
	 * @param {String} term - Required. The term to lookup. (ie: "White Fox")
	 * @param {Number} page - Which page of the results to look at. Will default to 1 if not provided.
	 * @param {Number} amount - The amount of results per page. AniList will cap this at 25 and function will default to 5 if not provided.
	 * @return { SearchEntry }
	 * @since 1.7.0
	 */
	studio(term, page = 1, amount = 5) {
		if (!term) {
			throw new Error("Search term was not provided!");
		}

		//Validate all type conditions.
		if (typeof term !== "string") {
			throw new Error("Term is not a string");
		}
		if (typeof page !== "number") {
			throw new Error("Page number is not a number");
		}
		if (typeof amount !== "number") {
			throw new Error("Amount is not a number");
		}

		return this.util.send(
			`query ($page: Int, $perPage: Int, $search: String) {
            Page (page: $page, perPage: $perPage) { pageInfo { total currentPage lastPage hasNextPage perPage } 
            studios (search: $search) { id name } } }`,
			{ search: term, page: page, perPage: amount }
		);
	}

	/**
	 * Search for a specific staff member
	 * @param {String} term - Required. The term to lookup. (ie: "Yuka Iguchi")
	 * @param {Number} page - Which page of the results to look at. Will default to 1 if not provided.
	 * @param {Number} amount - The amount of results per page. AniList will cap this at 25 and function will default to 5 if not provided.
	 * @return { SearchEntry }
	 * @since 1.7.0
	 */
	staff(term, page = 1, amount = 5) {
		if (!term) {
			throw new Error("Search term was not provided!");
		}

		//Validate all type conditions.
		if (typeof term !== "string") {
			throw new Error("Term is not a string");
		}
		if (typeof page !== "number") {
			throw new Error("Page number is not a number");
		}
		if (typeof amount !== "number") {
			throw new Error("Amount is not a number");
		}

		return this.util.send(
			`query ($page: Int, $perPage: Int, $search: String) {
            Page (page: $page, perPage: $perPage) { pageInfo { total currentPage lastPage hasNextPage perPage } 
            staff (search: $search) { id name { english: full } } } }`,
			{ search: term, page: page, perPage: amount }
		);
	}

	/**
	 * Search for a specific user
	 * @param {String} term - Required. The term to lookup. (ie: "AurelicButter")
	 * @param {Number} page - Which page of the results to look at. Will default to 1 if not provided.
	 * @param {Number} amount - The amount of results per page. AniList will cap this at 25 and function will default to 5 if not provided.
	 * @return { SearchEntry }
	 * @since 1.7.0
	 */
	user(term, page = 1, amount = 5) {
		if (!term) {
			throw new Error("Search term was not provided!");
		}

		//Validate all type conditions.
		if (typeof term !== "string") {
			throw new Error("Term is not a string");
		}
		if (typeof page !== "number") {
			throw new Error("Page number is not a number");
		}
		if (typeof amount !== "number") {
			throw new Error("Amount is not a number");
		}

		return this.util.send(
			`query ($page: Int, $perPage: Int, $search: String) {
            Page (page: $page, perPage: $perPage) { pageInfo { total currentPage lastPage hasNextPage perPage } 
            users (search: $search) { id name } } }`,
			{ search: term, page: page, perPage: amount }
		);
	}

	/**
	 * Search for a specific anime
	 * @param {String} term - The term to lookup. (ie: "Log Horizon"). For no term, input a null value
	 * @param {Object} filter - A key-value paired object to filter search data.
	 * @param {Number} page - Which page of the results to look at. Will default to 1 if not provided.
	 * @param {Number} amount - The amount of results per page. AniList will cap this at 25 and function will default to 5 if not provided.
	 * @return { SearchEntry }
	 * @since 1.7.0
	 */
	anime(term = null, filter = null, page = 1, amount = 5) {
		if (term && typeof term !== "string") {
			throw new Error("Search term is not a string");
		}
		if (typeof page !== "number") {
			throw new Error("Page number is not a number");
		}
		if (typeof amount !== "number") {
			throw new Error("Amount is not a number");
		}

		let query = filterBuilder("anime", filter);

		query += "id title { romaji english native userPreferred } } } }";
		return this.util.send(query, { search: term, page: page, perPage: amount });
	}

	/**
	 * Search for a specific manga
	 * @param {String} term - The term to lookup. (ie: "Mahoutsukai no Yome"). For no term, input a null value.
	 * @param {Object} filter - A key-value paired object to filter search data.
	 * @param {Number} page - Which page of the results to look at. Will default to 1 if not provided.
	 * @param {Number} amount - The amount of results per page. AniList will cap this at 25 and function will default to 5 if not provided.
	 * @return { SearchEntry }
	 * @since 1.7.0
	 */
	manga(term = null, filter = null, page = 1, amount = 5) {
		if (term && typeof term !== "string") {
			throw new Error("Search term is not a string");
		}
		if (typeof page !== "number") {
			throw new Error("Page number is not a number");
		}
		if (typeof amount !== "number") {
			throw new Error("Amount is not a number");
		}

		let query = filterBuilder("manga", filter);

		query += "id title { romaji english native userPreferred } } } }";
		return this.util.send(query, { search: term, page: page, perPage: amount });
	}

	/**
	 * Search for a specific activity
	 * @param {Number} activityID - The activityID to lookup. (ie: 152876349). For no term, input a null value.
	 * @param {Object} filter - A key-value paired object to filter search data.
	 * @param {Number} page - Which page of the results to look at. Will default to 1 if not provided.
	 * @param {Number} amount - The amount of results per page. AniList will cap this at 25 and function will default to 5 if not provided.
	 * @return { ActivityEntry }
	 * @since 1.7.0
	 */
	activity(activityID = null, filter = null, page = 1, amount = 5) {
		if (activityID && typeof activityID !== "number") {
			throw new Error("activityID is not a number.");
		}
		if (typeof page !== "number") {
			throw new Error("Page number is not a number");
		}
		if (typeof amount !== "number") {
			throw new Error("Amount is not a number");
		}

		let query = filterBuilder("activity", filter);

		query += `... on ListActivity { id type createdAt likeCount }
        ... on TextActivity { id type createdAt likeCount }
        ... on MessageActivity { id type createdAt likeCount }}}}`;

		return this.util.send(query, { id: activityID, page: page, perPage: amount });
	}
}

module.exports = Search;
