<script context="module" lang="ts">
	import { APIKey, Device, PreAuthKey, Route, User } from '$lib/common/classes';
	import { deviceStore, userStore, apiTestStore } from '$lib/common/stores.js';
	import { filterDevices, filterUsers } from './searching.svelte';

	export async function getUsers(): Promise<any> {
		// variables in local storage
		let headscaleURL = localStorage.getItem('headscaleURL') || '';
		let headscaleAPIKey = localStorage.getItem('headscaleAPIKey') || '';
		let sortKey = localStorage.getItem('headscaleUserSort') || '';
		let sortDirection = localStorage.getItem('headscaleUserSortDirection') || '';

		// endpoint url for getting users
		let endpointURL = '/api/v1/namespace';

		//returning variables
		let headscaleUsers = [new User()];
		let headscaleUsersResponse: Response = new Response();

		await fetch(headscaleURL + endpointURL, {
			method: 'GET',
			headers: {
				Accept: 'application/json',
				Authorization: `Bearer ${headscaleAPIKey}`
			}
		})
			.then((response) => {
				if (response.ok) {
					// return the api data
					headscaleUsersResponse = response;
				} else {
					return response.text().then((text) => {
						apiTestStore.set('failed');
						throw text;
					});
				}
			})
			.catch((error) => {
				apiTestStore.set('failed');
				throw error;
			});

		await headscaleUsersResponse.json().then((data) => {
			let collator = new Intl.Collator([], { numeric: true });
			if (sortDirection == 'ascending') {
				switch (sortKey) {
					case 'id':
						headscaleUsers = data.namespaces.sort((a: User, b: User) => collator.compare(a.id, b.id));
						break;
					case 'createdAt':
						headscaleUsers = data.namespaces.sort((a: User, b: User) => -collator.compare(a.createdAt, b.createdAt));
						break;
					case 'name':
						headscaleUsers = data.namespaces.sort((a: User, b: User) => collator.compare(a.name, b.name));
						break;
				}
			}
			if (sortDirection == 'descending') {
				switch (sortKey) {
					case 'id':
						headscaleUsers = data.namespaces.sort((a: User, b: User) => -collator.compare(a.id, b.id));
						break;
					case 'createdAt':
						headscaleUsers = data.namespaces.sort((a: User, b: User) => collator.compare(a.createdAt, b.createdAt));
						break;
					case 'name':
						headscaleUsers = data.namespaces.sort((a: User, b: User) => -collator.compare(a.name, b.name));
						break;
				}
			}
		});
		// Set the store
		apiTestStore.set('succeeded');
		userStore.set(headscaleUsers);
		// Filter the store
		filterUsers();
	}

	export async function editUser(currentUsername: string, newUsername: string): Promise<any> {
		// variables in local storage
		let headscaleURL = localStorage.getItem('headscaleURL') || '';
		let headscaleAPIKey = localStorage.getItem('headscaleAPIKey') || '';

		// endpoint url for editing users
		let endpointURL = '/api/v1/namespace/' + currentUsername + '/rename/' + newUsername;

		await fetch(headscaleURL + endpointURL, {
			method: 'POST',
			headers: {
				Accept: 'application/json',
				Authorization: `Bearer ${headscaleAPIKey}`
			}
		})
			.then((response) => {
				if (response.ok) {
					return response;
				} else {
					return response.text().then((text) => {
						throw JSON.parse(text).message;
					});
				}
			})
			.catch((error) => {
				throw error;
			});
	}

	export async function newAPIKey(APIKeyExpiration: string): Promise<string> {
		// variables in local storage
		let headscaleURL = localStorage.getItem('headscaleURL') || '';
		let headscaleAPIKey = localStorage.getItem('headscaleAPIKey') || '';

		// endpoint url for editing users
		let endpointURL = '/api/v1/apikey';

		let APIKeyResponse = new Response();
		let APIKeyString = '';

		await fetch(headscaleURL + endpointURL, {
			method: 'POST',
			headers: {
				Accept: 'application/json',
				Authorization: `Bearer ${headscaleAPIKey}`
			},
			body: JSON.stringify({
				expiration: APIKeyExpiration
			})
		})
			.then((response) => {
				if (response.ok) {
					APIKeyResponse = response;
				} else {
					return response.text().then((text) => {
						throw JSON.parse(text).message;
					});
				}
			})
			.catch((error) => {
				throw error;
			});
		await APIKeyResponse.json().then((data) => {
			APIKeyString = data.apiKey;
		});

		return APIKeyString;
	}

	export async function expireAPIKey(APIKeyPrefix: string) {
		// variables in local storage
		let headscaleURL = localStorage.getItem('headscaleURL') || '';
		let headscaleAPIKey = localStorage.getItem('headscaleAPIKey') || '';

		// endpoint url for editing users
		let endpointURL = '/api/v1/apikey/expire';

		await fetch(headscaleURL + endpointURL, {
			method: 'POST',
			headers: {
				Accept: 'application/json',
				Authorization: `Bearer ${headscaleAPIKey}`
			},
			body: JSON.stringify({
				prefix: APIKeyPrefix
			})
		})
			.then((response) => {
				if (response.ok) {
				} else {
					return response.text().then((text) => {
						throw JSON.parse(text).message;
					});
				}
			})
			.catch((error) => {
				throw error;
			});
	}

	export async function updateTags(deviceID: string, tags: string[]): Promise<any> {
		// variables in local storage
		let headscaleURL = localStorage.getItem('headscaleURL') || '';
		let headscaleAPIKey = localStorage.getItem('headscaleAPIKey') || '';

		// endpoint url for editing users
		let endpointURL = '/api/v1/machine/' + deviceID + '/tags';

		await fetch(headscaleURL + endpointURL, {
			method: 'POST',
			headers: {
				Accept: 'application/json',
				Authorization: `Bearer ${headscaleAPIKey}`
			},
			body: JSON.stringify({
				tags: tags
			})
		})
			.then((response) => {
				if (response.ok) {
					return response;
				} else {
					return response.text().then((text) => {
						throw JSON.parse(text).message;
					});
				}
			})
			.catch((error) => {
				throw error;
			});
	}

	export async function removeUser(currentUsername: string): Promise<any> {
		// variables in local storage
		let headscaleURL = localStorage.getItem('headscaleURL') || '';
		let headscaleAPIKey = localStorage.getItem('headscaleAPIKey') || '';

		// endpoint url for editing users
		let endpointURL = '/api/v1/namespace/' + currentUsername;

		await fetch(headscaleURL + endpointURL, {
			method: 'DELETE',
			headers: {
				Accept: 'application/json',
				Authorization: `Bearer ${headscaleAPIKey}`
			}
		})
			.then((response) => {
				if (response.ok) {
					return response;
				} else {
					return response.text().then((text) => {
						throw JSON.parse(text).message;
					});
				}
			})
			.catch((error) => {
				throw error;
			});
	}

	export async function newUser(newUsername: string): Promise<any> {
		// variables in local storage
		let headscaleURL = localStorage.getItem('headscaleURL') || '';
		let headscaleAPIKey = localStorage.getItem('headscaleAPIKey') || '';

		// endpoint url for editing users
		let endpointURL = '/api/v1/namespace';

		await fetch(headscaleURL + endpointURL, {
			method: 'POST',
			headers: {
				Accept: 'application/json',
				Authorization: `Bearer ${headscaleAPIKey}`
			},
			body: JSON.stringify({
				name: newUsername.toLowerCase()
			})
		})
			.then((response) => {
				if (response.ok) {
					return response;
				} else {
					return response.text().then((text) => {
						throw JSON.parse(text).message;
					});
				}
			})
			.catch((error) => {
				throw error;
			});
	}

	export async function getDevices(): Promise<any> {
		// variables in local storage
		let headscaleURL = localStorage.getItem('headscaleURL') || '';
		let headscaleAPIKey = localStorage.getItem('headscaleAPIKey') || '';
		let sortKey = localStorage.getItem('headscaleDeviceSort') || '';
		let sortDirection = localStorage.getItem('headscaleDeviceSortDirection') || '';

		// endpoint url for getting users
		let endpointURL = '/api/v1/machine';

		//returning variables
		let headscaleDevices = [new Device()];
		let headscaleDeviceResponse: Response = new Response();

		// attempt to get the user data
		await fetch(headscaleURL + endpointURL, {
			method: 'GET',
			headers: {
				Accept: 'application/json',
				Authorization: `Bearer ${headscaleAPIKey}`
			}
		})
			.then((response) => {
				if (response.ok) {
					// return the api data
					headscaleDeviceResponse = response;
				} else {
					return response.text().then((text) => {
						apiTestStore.set('failed');
						throw text;
					});
				}
			})
			.catch((error) => {
				apiTestStore.set('failed');
				throw error;
			});

		await headscaleDeviceResponse.json().then((data) => {
			let collator = new Intl.Collator([], { numeric: true });
			if (sortDirection == 'ascending') {
				switch (sortKey) {
					case 'id':
						headscaleDevices = data.machines.sort((a: Device, b: Device) => collator.compare(a.id, b.id));
						break;
					case 'lastSeen':
						headscaleDevices = data.machines.sort((a: Device, b: Device) => -collator.compare(a.lastSeen, b.lastSeen));
						break;
					case 'givenName':
						headscaleDevices = data.machines.sort((a: Device, b: Device) => collator.compare(a.givenName, b.givenName));
						break;
				}
			}
			if (sortDirection == 'descending') {
				switch (sortKey) {
					case 'id':
						headscaleDevices = data.machines.sort((a: Device, b: Device) => -collator.compare(a.id, b.id));
						break;
					case 'lastSeen':
						headscaleDevices = data.machines.sort((a: Device, b: Device) => collator.compare(a.lastSeen, b.lastSeen));
						break;
					case 'givenName':
						headscaleDevices = data.machines.sort((a: Device, b: Device) => -collator.compare(a.givenName, b.givenName));
						break;
				}
			}
		});
		// set the stores
		apiTestStore.set('succeeded');
		deviceStore.set(headscaleDevices);
		// filter the store
		filterDevices();
	}

	export async function getDeviceRoutes(deviceID: string): Promise<Route> {
		// variables in local storage
		let headscaleURL = localStorage.getItem('headscaleURL') || '';
		let headscaleAPIKey = localStorage.getItem('headscaleAPIKey') || '';

		// endpoint url for getting users
		let endpointURL = '/api/v1/machine/' + deviceID + '/routes';

		//returning variables
		let headscaleRoute = new Route();
		let headscaleDeviceResponse: Response = new Response();

		await fetch(headscaleURL + endpointURL, {
			method: 'GET',
			headers: {
				Accept: 'application/json',
				Authorization: `Bearer ${headscaleAPIKey}`
			}
		})
			.then((response) => {
				if (response.ok) {
					// return the api data
					headscaleDeviceResponse = response;
				} else {
					return response.text().then((text) => {
						throw JSON.parse(text).message;
					});
				}
			})
			.catch((error) => {
				throw error;
			});

		await headscaleDeviceResponse.json().then((data) => {
			headscaleRoute = data.routes;
		});
		return headscaleRoute;
	}

	export async function enableDeviceRoute(deviceID: string, routes: string[]): Promise<any> {
		// variables in local storage
		let headscaleURL = localStorage.getItem('headscaleURL') || '';
		let headscaleAPIKey = localStorage.getItem('headscaleAPIKey') || '';

		// endpoint url for getting users
		let endpointURL =
			'/api/v1/machine/' +
			deviceID +
			'/routes?' +
			routes
				.map(encodeURIComponent)
				.map((route) => `routes=${route}`)
				.join('&');

		//returning variables
		let headscaleDeviceResponse: Response = new Response();

		await fetch(headscaleURL + endpointURL, {
			method: 'POST',
			headers: {
				Accept: 'application/json',
				Authorization: `Bearer ${headscaleAPIKey}`
			}
		})
			.then((response) => {
				if (response.ok) {
					// return the api data
					headscaleDeviceResponse = response;
				} else {
					return response.text().then((text) => {
						throw JSON.parse(text).message;
					});
				}
			})
			.catch((error) => {
				throw error;
			});
	}

	export async function getAPIKeys(): Promise<APIKey[]> {
		// variables in local storage
		let headscaleURL = localStorage.getItem('headscaleURL') || '';
		let headscaleAPIKey = localStorage.getItem('headscaleAPIKey') || '';

		// endpoint url for editing users
		let endpointURL = '/api/v1/apikey';
		let apiKeysResponse = new Response();
		let apiKeys = [new APIKey()];

		await fetch(headscaleURL + endpointURL, {
			method: 'GET',
			headers: {
				Accept: 'application/json',
				Authorization: `Bearer ${headscaleAPIKey}`
			}
		})
			.then((response) => {
				if (response.ok) {
					apiKeysResponse = response;
				} else {
					return response.text().then((text) => {
						throw JSON.parse(text).message;
					});
				}
			})
			.catch((error) => {
				throw error;
			});

		await apiKeysResponse.json().then((data) => {
			apiKeys = data.apiKeys;
		});
		return apiKeys;
	}

	export async function getPreauthKeys(userName: string): Promise<PreAuthKey[]> {
		// variables in local storage
		let headscaleURL = localStorage.getItem('headscaleURL') || '';
		let headscaleAPIKey = localStorage.getItem('headscaleAPIKey') || '';

		// endpoint url for editing users
		let endpointURL = '/api/v1/preauthkey';

		//returning variables
		let headscalePreAuthKey = [new PreAuthKey()];
		let headscalePreAuthKeyResponse: Response = new Response();

		await fetch(headscaleURL + endpointURL + '?namespace=' + userName, {
			method: 'GET',
			headers: {
				Accept: 'application/json',
				Authorization: `Bearer ${headscaleAPIKey}`
			}
		})
			.then((response) => {
				if (response.ok) {
					headscalePreAuthKeyResponse = response;
				} else {
					return response.text().then((text) => {
						throw JSON.parse(text).message;
					});
				}
			})
			.catch((error) => {
				throw error;
			});

		await headscalePreAuthKeyResponse.json().then((data) => {
			headscalePreAuthKey = data.preAuthKeys;
		});
		return headscalePreAuthKey;
	}

	export async function newPreAuthKey(userName: string, expiry: string, reusable: boolean, ephemeral: boolean): Promise<any> {
		// variables in local storage
		let headscaleURL = localStorage.getItem('headscaleURL') || '';
		let headscaleAPIKey = localStorage.getItem('headscaleAPIKey') || '';
		// endpoint url for editing users
		let endpointURL = '/api/v1/preauthkey';

		await fetch(headscaleURL + endpointURL, {
			method: 'POST',
			headers: {
				Accept: 'application/json',
				Authorization: `Bearer ${headscaleAPIKey}`
			},
			body: JSON.stringify({
				namespace: userName,
				expiration: expiry,
				reusable: reusable,
				ephemeral: ephemeral
			})
		})
			.then((response) => {
				if (response.ok) {
					return response;
				} else {
					return response.text().then((text) => {
						throw JSON.parse(text).message;
					});
				}
			})
			.catch((error) => {
				throw error;
			});
	}

	export async function removePreAuthKey(userName: string, preAuthKey: string): Promise<any> {
		// variables in local storage
		let headscaleURL = localStorage.getItem('headscaleURL') || '';
		let headscaleAPIKey = localStorage.getItem('headscaleAPIKey') || '';

		// endpoint url for removing devices
		let endpointURL = '/api/v1/preauthkey/expire';

		await fetch(headscaleURL + endpointURL, {
			method: 'POST',
			headers: {
				Accept: 'application/json',
				Authorization: `Bearer ${headscaleAPIKey}`
			},
			body: JSON.stringify({
				namespace: userName,
				key: preAuthKey
			})
		})
			.then((response) => {
				if (response.ok) {
					return response;
				} else {
					return response.text().then((text) => {
						throw JSON.parse(text).message;
					});
				}
			})
			.catch((error) => {
				throw error;
			});
	}

	export async function newDevice(key: string, userName: string): Promise<any> {
		// variables in local storage
		let headscaleURL = localStorage.getItem('headscaleURL') || '';
		let headscaleAPIKey = localStorage.getItem('headscaleAPIKey') || '';

		// endpoint url for editing users
		let endpointURL = '/api/v1/machine/register';

		await fetch(headscaleURL + endpointURL + '?namespace=' + userName + '&key=' + key, {
			method: 'POST',
			headers: {
				Accept: 'application/json',
				Authorization: `Bearer ${headscaleAPIKey}`
			}
		})
			.then((response) => {
				if (response.ok) {
					return response;
				} else {
					return response.text().then((text) => {
						throw JSON.parse(text).message;
					});
				}
			})
			.catch((error) => {
				throw error;
			});
	}

	export async function moveDevice(deviceID: string, user: string): Promise<any> {
		// variables in local storage
		let headscaleURL = localStorage.getItem('headscaleURL') || '';
		let headscaleAPIKey = localStorage.getItem('headscaleAPIKey') || '';

		// endpoint url for editing users
		let endpointURL = '/api/v1/machine/' + deviceID + '/namespace?namespace=' + user;

		await fetch(headscaleURL + endpointURL, {
			method: 'POST',
			headers: {
				Accept: 'application/json',
				Authorization: `Bearer ${headscaleAPIKey}`
			}
		})
			.then((response) => {
				if (response.ok) {
					return response;
				} else {
					return response.text().then((text) => {
						throw JSON.parse(text).message;
					});
				}
			})
			.catch((error) => {
				throw error;
			});
	}

	export async function renameDevice(deviceID: string, name: string): Promise<any> {
		// variables in local storage
		let headscaleURL = localStorage.getItem('headscaleURL') || '';
		let headscaleAPIKey = localStorage.getItem('headscaleAPIKey') || '';

		// endpoint url for editing users
		let endpointURL = '/api/v1/machine/' + deviceID + '/rename/' + name;

		await fetch(headscaleURL + endpointURL, {
			method: 'POST',
			headers: {
				Accept: 'application/json',
				Authorization: `Bearer ${headscaleAPIKey}`
			}
		})
			.then((response) => {
				if (response.ok) {
					return response;
				} else {
					return response.text().then((text) => {
						throw JSON.parse(text).message;
					});
				}
			})
			.catch((error) => {
				throw error;
			});
	}

	export async function removeDevice(deviceID: string): Promise<any> {
		// variables in local storage
		let headscaleURL = localStorage.getItem('headscaleURL') || '';
		let headscaleAPIKey = localStorage.getItem('headscaleAPIKey') || '';

		// endpoint url for removing devices
		let endpointURL = '/api/v1/machine/' + deviceID;

		await fetch(headscaleURL + endpointURL, {
			method: 'DELETE',
			headers: {
				Accept: 'application/json',
				Authorization: `Bearer ${headscaleAPIKey}`
			}
		})
			.then((response) => {
				if (response.ok) {
					return response;
				} else {
					return response.text().then((text) => {
						throw JSON.parse(text).message;
					});
				}
			})
			.catch((error) => {
				throw error;
			});
	}
</script>
