import { execFileSync } from 'child_process';

const BW = 'bw';
const ORG_ID = '4bd75130-b4d3-48d4-a4cb-e52b70295a51';
const AI_COLLECTION = '5be27a82-8475-4c38-96b2-fa94ec8c957b';

let _session = null;

function bwEnv() {
  const env = { ...process.env };
  for (const k of ['HTTPS_PROXY','HTTP_PROXY','ALL_PROXY','https_proxy','http_proxy','all_proxy'])
    delete env[k];
  env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
  return env;
}

function run(args, input) {
  try {
    return execFileSync(BW, args, {
      env: bwEnv(),
      encoding: 'utf8',
      input,
      stdio: input ? ['pipe','pipe','pipe'] : ['ignore','pipe','pipe'],
    }).trim();
  } catch (e) {
    // SECURITY: execFileSync puts the FULL argv in e.message
    // ("Command failed: bw unlock <BW_PASSWORD> --raw"), and login/unlock pass
    // the master password as argv. That message propagates to console.error /
    // tool errors -> docker logs. Re-throw with the argv stripped: keep only the
    // subcommand + exit code + stderr, and scrub the password out of stderr too
    // (defensive; bw doesn't normally echo it). Never let argv reach a log.
    const sub = Array.isArray(args) && args.length ? args[0] : '?';
    let stderr = (e && e.stderr ? e.stderr.toString() : '').trim();
    const secret = process.env.BW_PASSWORD;
    if (secret && stderr.includes(secret)) stderr = stderr.split(secret).join('<redacted>');
    const err = new Error(`bw ${sub} failed (exit ${e && e.status != null ? e.status : '?'})` +
      (stderr ? `: ${stderr}` : ''));
    err.status = e && e.status;
    throw err;
  }
}

export async function initVaultwarden() {
  const email = process.env.BW_EMAIL || 'allogn@gmail.com';
  const password = process.env.BW_PASSWORD;

  // Data dir is mounted from host — server already configured, skip bw config server

  let status = 'unauthenticated';
  try {
    status = JSON.parse(run(['status'])).status;
  } catch {}

  if (status === 'unauthenticated') {
    run(['login', email, password, '--raw']);
  }

  _session = run(['unlock', password, '--raw']);
  run(['sync', '--session', _session]);
  console.log('Vaultwarden: ready');
}

function session() {
  if (!_session) throw new Error('Vaultwarden not initialized');
  return _session;
}

export function vwGetPassword(name) {
  return run(['get', 'password', name, '--session', session()]);
}

export function vwGetItem(name) {
  return JSON.parse(run(['get', 'item', name, '--session', session()]));
}

export function vwListItems(search) {
  const args = ['list', 'items', '--session', session()];
  if (search) args.push('--search', search);
  return JSON.parse(run(args));
}

export function vwListOrgItems(search) {
  const args = ['list', 'items', '--organizationid', ORG_ID, '--session', session()];
  if (search) args.push('--search', search);
  return JSON.parse(run(args));
}

export function vwCreateLogin({ name, username, password, url, notes }) {
  const item = {
    organizationId: ORG_ID,
    collectionIds: [AI_COLLECTION],
    folderId: null,
    type: 1,
    name,
    notes: notes || null,
    favorite: false,
    login: {
      username: username || null,
      password,
      uris: url ? [{ match: null, uri: url }] : [],
    },
  };
  const encoded = run(['encode'], JSON.stringify(item));
  return JSON.parse(run(['create', 'item', encoded, '--session', session()]));
}

export function vwUpdatePassword(nameOrId, newPassword) {
  let item;
  try {
    item = JSON.parse(run(['get', 'item', nameOrId, '--session', session()]));
  } catch {
    const items = vwListOrgItems(nameOrId);
    item = items.find(i => i.name === nameOrId);
    if (!item) throw new Error(`Item not found: ${nameOrId}`);
  }
  item.login.password = newPassword;
  const encoded = run(['encode'], JSON.stringify(item));
  return JSON.parse(run(['edit', 'item', item.id, encoded, '--session', session()]));
}
