import { appDataDir } from '@tauri-apps/api/path';
import { invoke } from '@tauri-apps/api/core';
import type { TotpProfile } from './totp';

const CLIENT_NAME = 'lendry-totp';
const STORE_KEY = 'totp-profiles';
const PASSWORD_KEY = 'lendry_stronghold_password';

function getStrongholdPassword() {
  const existing = window.localStorage.getItem(PASSWORD_KEY);
  if (existing) return existing;
  const created = crypto.randomUUID() + crypto.randomUUID();
  window.localStorage.setItem(PASSWORD_KEY, created);
  return created;
}

async function openStronghold() {
  const strongholdModule = await import('@tauri-apps/plugin-stronghold');
  const Stronghold = (strongholdModule as unknown as { Stronghold?: unknown }).Stronghold as {
    load: (path: string, password: string) => Promise<unknown>;
  };
  const baseDir = await appDataDir();
  const stronghold = await Stronghold.load(`${baseDir}/totp.stronghold`, getStrongholdPassword());
  const anyStronghold = stronghold as {
    loadClient?: (name: string) => Promise<unknown>;
    createClient?: (name: string) => Promise<unknown>;
    save: () => Promise<void>;
  };
  let client: unknown;
  try {
    client = await anyStronghold.loadClient?.(CLIENT_NAME);
  } catch {
    client = await anyStronghold.createClient?.(CLIENT_NAME);
  }
  if (!client) {
    client = await anyStronghold.createClient?.(CLIENT_NAME);
  }
  const store = (client as { getStore: () => unknown }).getStore();
  return { stronghold: anyStronghold, store: store as StrongholdStore };
}

interface StrongholdStore {
  get(key: string): Promise<number[] | Uint8Array | null>;
  insert(key: string, value: number[] | Uint8Array): Promise<void>;
  remove(key: string): Promise<void>;
}

function encodeProfiles(profiles: TotpProfile[]) {
  return new TextEncoder().encode(JSON.stringify(profiles));
}

function decodeProfiles(value: number[] | Uint8Array | null) {
  if (!value) return [];
  const bytes = value instanceof Uint8Array ? value : new Uint8Array(value);
  const text = new TextDecoder().decode(bytes);
  return JSON.parse(text) as TotpProfile[];
}

export async function loadTotpProfiles() {
  const { store } = await openStronghold();
  return decodeProfiles(await store.get(STORE_KEY));
}

export async function saveTotpProfiles(profiles: TotpProfile[]) {
  const { stronghold, store } = await openStronghold();
  await store.insert(STORE_KEY, encodeProfiles(profiles));
  await stronghold.save();
}

export async function addTotpProfile(profile: Omit<TotpProfile, 'id' | 'createdAt'>) {
  await invoke('validate_totp_profile_input', profile);
  const profiles = await loadTotpProfiles();
  const next: TotpProfile = {
    ...profile,
    id: crypto.randomUUID(),
    createdAt: new Date().toISOString()
  };
  await saveTotpProfiles([...profiles, next]);
  return next;
}

export async function deleteTotpProfile(profileId: string) {
  const profiles = await loadTotpProfiles();
  await saveTotpProfiles(profiles.filter((profile) => profile.id !== profileId));
}
