import type { SecretStore } from '@chat-app/shared/auth';
import { appLocalDataDir } from '@tauri-apps/api/path';
import { type Client, type Store, Stronghold } from '@tauri-apps/plugin-stronghold';

// Stronghold-backed SecretStore. Vault file lives in Tauri's
// `appLocalDataDir/chatapp.stronghold` and survives app re-installs (the
// directory is preserved by the OS on macOS/Windows/Linux unless the user
// manually removes it). Vault password is derived from the Supabase user-id
// so the same user re-installing the app on the same machine recovers their
// device key automatically.

const VAULT_NAME = 'chatapp.stronghold';
const CLIENT_NAME = 'chatapp';

let strongholdRef: Stronghold | null = null;
let storeRef: Store | null = null;
let initPromise: Promise<void> | null = null;
let initializedFor: string | null = null;

async function derivePassword(userId: string): Promise<string> {
  const enc = new TextEncoder();
  const buf = await crypto.subtle.digest(
    'SHA-256',
    enc.encode('chatapp-stronghold-v1:' + userId),
  );
  return Array.from(new Uint8Array(buf))
    .map((b) => b.toString(16).padStart(2, '0'))
    .join('');
}

async function ensureInit(userId: string): Promise<void> {
  if (initializedFor === userId && storeRef) return;
  if (initPromise) return initPromise;

  initPromise = (async () => {
    const dir = await appLocalDataDir();
    const sep = dir.endsWith('/') || dir.endsWith('\\') ? '' : '/';
    const vaultPath = dir + sep + VAULT_NAME;
    const password = await derivePassword(userId);

    strongholdRef = await Stronghold.load(vaultPath, password);
    let client: Client;
    try {
      client = await strongholdRef.loadClient(CLIENT_NAME);
    } catch {
      client = await strongholdRef.createClient(CLIENT_NAME);
    }
    storeRef = client.getStore();
    initializedFor = userId;
  })().finally(() => {
    initPromise = null;
  });
  return initPromise;
}

export function makeStrongholdStore(userId: string): SecretStore {
  return {
    async getSecret(key: string): Promise<Uint8Array | null> {
      await ensureInit(userId);
      const val = await storeRef!.get(key);
      if (!val) return null;
      return val instanceof Uint8Array ? val : new Uint8Array(val);
    },
    async setSecret(key: string, value: Uint8Array): Promise<void> {
      await ensureInit(userId);
      await storeRef!.insert(key, Array.from(value));
      await strongholdRef!.save();
    },
    async removeSecret(key: string): Promise<void> {
      await ensureInit(userId);
      await storeRef!.remove(key);
      await strongholdRef!.save();
    },
  };
}

// One-time migration: copies any keys we find in localStorage (the legacy
// dev store) into Stronghold so a user who upgrades from a localStorage-only
// build doesn't lose their device key. Safe to call multiple times — no-op
// once the marker key is present.
export async function migrateLocalStorageToStronghold(
  userId: string,
  prefix: string,
): Promise<void> {
  await ensureInit(userId);
  if (!storeRef) return;
  const markerKey = '__migrated_from_localstorage';
  const already = await storeRef.get(markerKey);
  if (already) return;

  for (let i = 0; i < window.localStorage.length; i++) {
    const fullKey = window.localStorage.key(i);
    if (!fullKey || !fullKey.startsWith(prefix)) continue;
    const raw = window.localStorage.getItem(fullKey);
    if (!raw) continue;
    try {
      const decoded = Uint8Array.from(atob(raw), (c) => c.charCodeAt(0));
      const shortKey = fullKey.slice(prefix.length);
      await storeRef.insert(shortKey, Array.from(decoded));
    } catch {
      // Skip malformed entries.
    }
  }
  await storeRef.insert(markerKey, [1]);
  if (strongholdRef) await strongholdRef.save();
}
