import { browser } from '$app/environment';
import type { Did } from '@atcute/lexicons/syntax';

// atcute owns oauth sessions; this stores metadata/order and active-account cookies.

export const CURRENT_DID_KEY = 'tangled.currentDid';
export const CURRENT_HANDLE_KEY = 'tangled.currentHandle';
const ACCOUNTS_KEY = 'tangled.accounts';

// appview account cap parity
export const MAX_ACCOUNTS = 20;

export interface AuthAccount {
	did: Did;
	handle: string;
	avatar?: string;
	// unix seconds; appview parity
	addedAt: number;
}

const isDid = (value: unknown): value is Did =>
	typeof value === 'string' && value.startsWith('did:');

const isAccount = (value: unknown): value is AuthAccount =>
	!!value &&
	typeof value === 'object' &&
	isDid((value as AuthAccount).did) &&
	typeof (value as AuthAccount).handle === 'string';

export const loadAccounts = (): AuthAccount[] => {
	if (!browser) return [];
	try {
		const raw = localStorage.getItem(ACCOUNTS_KEY);
		if (!raw) return [];
		const parsed = JSON.parse(raw) as unknown;
		if (!Array.isArray(parsed)) return [];
		return parsed.filter(isAccount).map((account) => ({
			did: account.did,
			handle: account.handle,
			avatar: account.avatar,
			addedAt: typeof account.addedAt === 'number' ? account.addedAt : 0
		}));
	} catch {
		return [];
	}
};

export const saveAccounts = (accounts: readonly AuthAccount[]): void => {
	if (!browser) return;
	localStorage.setItem(ACCOUNTS_KEY, JSON.stringify(accounts));
};

// stored sessions are authoritative; metadata supplies order, handle, and avatar.
export const reconcileAccounts = (
	stored: readonly Did[],
	meta: readonly AuthAccount[]
): AuthAccount[] => {
	const storedSet = new Set(stored);
	const known = new Set(meta.map((account) => account.did));
	const ordered = meta.filter((account) => storedSet.has(account.did));
	for (const did of stored) {
		if (!known.has(did)) {
			ordered.push({ did, handle: did, addedAt: Math.floor(Date.now() / 1000) });
		}
	}
	return ordered;
};

// dedupe by did, preserve insertion order, and keep the original addedAt.
export const upsertAccount = (
	accounts: readonly AuthAccount[],
	account: AuthAccount
): AuthAccount[] => {
	const index = accounts.findIndex((existing) => existing.did === account.did);
	if (index >= 0) {
		const next = accounts.slice();
		next[index] = { ...account, addedAt: accounts[index].addedAt };
		return next;
	}
	if (accounts.length >= MAX_ACCOUNTS) return accounts.slice();
	return [...accounts, account];
};

export const dropAccount = (accounts: readonly AuthAccount[], did: Did): AuthAccount[] =>
	accounts.filter((account) => account.did !== did);

export const persistActive = (did: string, handle: string): void => {
	if (!browser) return;
	localStorage.setItem(CURRENT_DID_KEY, did);
	localStorage.setItem(CURRENT_HANDLE_KEY, handle);
	const secure = location.protocol === 'https:' ? '; secure' : '';
	const attrs = `; path=/; max-age=31536000; samesite=lax${secure}`;
	document.cookie = `${CURRENT_DID_KEY}=${encodeURIComponent(did)}${attrs}`;
	document.cookie = `${CURRENT_HANDLE_KEY}=${encodeURIComponent(handle)}${attrs}`;
};

export const clearActive = (): void => {
	if (!browser) return;
	localStorage.removeItem(CURRENT_DID_KEY);
	localStorage.removeItem(CURRENT_HANDLE_KEY);
	document.cookie = `${CURRENT_DID_KEY}=; path=/; max-age=0; samesite=lax`;
	document.cookie = `${CURRENT_HANDLE_KEY}=; path=/; max-age=0; samesite=lax`;
};

export const readActiveDid = (): Did | null => {
	if (!browser) return null;
	const value = localStorage.getItem(CURRENT_DID_KEY);
	return isDid(value) ? value : null;
};
