import { get, writable } from "svelte/store";
import type { Currency } from "../data/entities";
import { trpcApiStore } from "$lib/stores/api";
import { toast } from "svelte-sonner";

export const currencyStore = writable<Currency>({
	id: 0,
	code: "USD",
	currency: "USD (US Dollar)",
	exchangeRate: 1,
	ratio: 1,
});

class CurrencyViewModel {
	currencies = $state<Currency[]>([]);

	queriedCurrencies = $state<Currency[]>([]);
	query = $state<string>("");

	private applyTimeout: ReturnType<typeof setTimeout> | undefined;

	loadCachedSelection() {
		const stored = localStorage.getItem("currency");
		if (stored) {
			const info = JSON.parse(stored);
			if (info) {
				currencyStore.set(info);
			}
		}
	}

	private cacheSelection(info: Currency) {
		localStorage.setItem("currency", JSON.stringify(info));
	}

	async getCurrencies() {
		const api = get(trpcApiStore);
		if (!api) {
			return;
		}
		const out = await api.currency.getCurrencies.query();
		if (out.error) {
			toast.error(out.error.message, { description: out.error.userHint });
		}
		if (out.data) {
			this.currencies = out.data;
			this._applyQuery();
		}
	}

	applyQuery() {
		if (this.applyTimeout) {
			clearTimeout(this.applyTimeout);
		}
		this.applyTimeout = setTimeout(() => {
			this._applyQuery();
		}, 500);
	}

	private _applyQuery() {
		if (this.query.length < 2) {
			this.queriedCurrencies = this.currencies;
			return;
		}
		const queryNormalized = this.query.toLowerCase();
		this.queriedCurrencies = this.currencies.filter((c) => {
			return c.currency.toLowerCase().includes(queryNormalized);
		});
	}

	setCurrency(code: string) {
		const found = this.currencies.find((c) => c.code === code);
		if (found) {
			currencyStore.set(found);
			this.cacheSelection(found);
		}
		setTimeout(() => {
			window.location.reload();
		}, 500);
	}

	convertToUsd(amount: number, currencyCode: string) {
		const currency = this.currencies.find((c) => c.code === currencyCode);
		if (!currency) {
			return 0;
		}
		return amount / currency.exchangeRate;
	}

	convertFromUsd(amount: number, currencyCode: string) {
		const currency = this.currencies.find((c) => c.code === currencyCode);
		if (!currency) {
			return 0;
		}
		return amount * currency.exchangeRate;
	}
}

export const currencyVM = new CurrencyViewModel();

export function convertAndFormatCurrency(amount: number) {
	const code = get(currencyStore).code;
	return new Intl.NumberFormat("en-US", {
		style: "currency",
		currency: code,
		minimumFractionDigits: 2,
		maximumFractionDigits: 2,
	}).format(currencyVM.convertFromUsd(amount, code));
}
