export class API {
	// query resolves into the JSON data produced by the application, or an exception with 'type' and 'error' properties.
	static async query(method, path, request) {
		try {
			const body = JSON.stringify(request)
			const headers = {}

			// Authentication is done with a bearer token.
			// Here provided to the backend if set.
			const token = localStorage.getItem('token')
			if (token) {
				headers.Authorization = `Bearer ${token}`
			}

			const res = await fetch(path, { method, headers, body })
			// An HTTP communication level error occured.
			if (!res.ok || res.status != 200)
				throw new Error('HTTP error', { cause: { type: 'http', error: res, } })

			// Application level response are handled here.
			const json = await res.json()
			if (!json.OK)
				throw new Error(json.Error, { cause: { type: 'application', application: json, } })

			return json
		} catch (err) {
			// Catch any other errors from fetch.
			throw new Error(err.message, { cause: { type: 'http', error: err, } })
		}
	}

	// Sends a block of binary data to server.
	static async upload(uuid, data, sentBytes, metadata) {
		try {
			const path = `/sync/file/upload/${uuid}`
			const headers = {
				'X-File-Sent-Bytes': sentBytes,
				'X-File-Total-Bytes': metadata.size,
			}

			// Metadata is needed for the database.
			// No need to send it every block.
			if (sentBytes === 0) {
				headers['X-File-Name'] = metadata.name
				headers['X-File-Size'] = metadata.size
				headers['X-File-Type'] = metadata.type
				headers['X-File-Modified'] = metadata.modified
			}

			// Authentication is done with a bearer token.
			// Here provided to the backend if set.
			const token = localStorage.getItem('token')
			if (token) {
				headers.Authorization = `Bearer ${token}`
			}

			const res = await fetch(path, { method: 'POST', headers, body: data })
			// An HTTP communication level error occured.
			if (!res.ok || res.status != 200)
				throw new Error('HTTP error', { cause: { type: 'http', error: res, } })

			// Application level response are handled here.
			const json = await res.json()
			if (!json.OK)
				throw new Error(json.Error, { cause: { type: 'application', application: json, } })

			return json

		} catch (err) {
			// Catch any other errors from fetch.
			console.error(err)
			throw new Error(err, { cause: { type: 'http', error: err } })
		}
	}

	static hasAuthenticationToken() {//{{{
		const token = localStorage.getItem('token')
		return token !== null && token !== ''
	}//}}}
	static authenticate(username, password) {//{{{
		return new Promise((resolve, reject) => {
			const req = { username, password }
			API.query('POST', '/user/authenticate', req)
				.then(response => {
					localStorage.setItem('token', response.Token)
					localStorage.setItem('user', JSON.stringify(response.User))
					resolve(response.User)
				})
				.catch(e => {
					console.log(e.type, e.error)
					reject(e.error)
				})
		})
	}//}}}
	static logout() {//{{{
		localStorage.removeItem('token')
		location.href = '/'
	}//}}}
}
