// Silence may be golden, but sometimes words paint the canvas of understanding.
class LinksyBrokenLinks {
	constructor(token) {
		if (!token || typeof token !== 'string') {
			throw new TypeError('Token must be a string')
		}

		this.selectedMode = LinksyBrokenLinks.FILTER_MODES[0].value

		// private methods
		this._token = token
		this._data = []
		this._pagination = {
			page: 0,
			limit: 10,
			total: 0
		}
	}

	static get SUPPORTED_ACTIONS() {
		return [
			{
				value: 'fix_redirect',
				label: 'Fix Redirect',
				message: 'Fix Redirect.',
			},
			{
				value: 'replace',
				label: 'Replace',
				message: 'Replace.',
			},
            {
				value: 'unlink',
				label: 'Unlink',
				message: 'Unlink removes the link, leaving out the anchor.',
			},
			{
				value: 'recheck',
				label: 'Recheck',
				message: 'Recheck.',
			},
			{
				value: 'ignore',
				label: 'Ignore',
				message: 'Ignore.',
			},
			{
				value: 'undo_ignore',
				label: 'Undo Ignore',
				message: 'Undo Ignore.',
			}
		]
	}

	static get SUPPORTED_OPTIONS() {
		return [
			{
				value: 'edit_url',
				label: 'Edit URL'
			},
			{
				value: 'unlink',
				label: 'Unlink'
			},
			{
				value: 'recheck',
				label: 'Recheck'
			},
			{
				value: 'fix_redirect',
				label: 'Fix Redirect'
			},
			{
				value: 'ignore',
				label: 'Ignore'
			},
			{
				value: 'undo_ignore',
				label: 'Undo Ignore'
			},
			{
				value: 'details',
				label: 'Details'
			}
		]
	}

	static get HTTP_TEXT_ARRAY() {
		return [
            { code: 401, text: 'Unauthorized' },
            { code: 403, text: 'Forbidden' },
            { code: 404, text: 'Not Found' },
            { code: 408, text: 'Request Timeout' }
        ]
	}

	static get FILTER_MODES() {
		return [
			{
				placeholder: 'Filter data by source',
				label: 'Filter source',
				value: 'source',
			},
			{
				placeholder: 'Filter data by link',
				label: 'Filter link',
				value: 'link',
			},
			{
				placeholder: 'Filter data by anchor',
				label: 'Filter anchor',
				value: 'anchor',
			},
		]
	}

	get pagination() {
		return Object.freeze({
			...this._pagination,
			total: this._pagination.total,
		})
	}

	set pagination(value) {
		if (typeof value !== 'object') {
			throw new Error('Invalid pagination value: ' + value)
		}

		this._pagination = {
			...this._pagination,
			...value,
		}
	}

	get data() {
		return this._data
	}

	set data(data) {
		this._data = data
	}

	toPage(page) {
		this._pagination.page = page
	}

	reset() {
		this._data = []
		this._pagination = {
			...this._pagination,
			page: 0,
			total: 0
		}
	}

	async searchBrokenLinks(query, searchMode, filterQuery, filter) {
		this._data.results = []

		const params = toQueryString({
			action: 'linksy_search_and_replace_search_broken_links',
			nonce: this._token,
			search: encodeURIComponent(query.trim()),
			page: this._pagination.page,
			limit: this._pagination.limit,
			filter: JSON.stringify(filter),
			filter_mode: this.selectedMode,
			filter_query: filterQuery,
			search_mode: searchMode || LinksyBrokenLinks.SEARCH_TYPES[0].value
		})

		const {
			data: { data },
		} = await axios.get(ajaxurl + '?' + params)

		// update the pagination
		this._data = data
		this._pagination.total = data.total

		return this._data
	}

	async applySelectedOption(selectedOption, item, link_replacement = '') {
		if (!item) {
			return
		}

		const params = urlSearchParams({
			action: `linksy_search_and_replace_${selectedOption}_links`,
			nonce: this._token,
			item: JSON.stringify(item),
			link_replacement: link_replacement,
			is_broken: true
		})

		const {
			data: { data },
		} = await axios.post(ajaxurl, params)

		return data
	}

	async applyBulkAction(selectedAction, items, link_replacement = '') {

		let fixRedirect = false

		if (selectedAction === 'fix_redirect') {
			selectedAction = 'replace'
			fixRedirect = true
		}
		
		let report = {
			failed: []
		};
		
		selectedAction === 'unlink' ? report.deleted = [] : report.replaced = [];
		
		for (const item of items) {
			const stats = await this.applySelectedOption(
				selectedAction,
				item,
				fixRedirect ? item.final_url : link_replacement
			);
		
			if (selectedAction === 'unlink') {
				const { deleted, failed } = stats;
				report.deleted.push(...deleted);
				report.failed.push(...failed);
			} else {
				const { replaced, failed } = stats;
				report.replaced.push(...replaced);
				report.failed.push(...failed);
			}
		}
		
		return report;

	}

}
