/**
 * E2-Abnahme: Mandantentrennung – geprüft über die API, nicht über das UI.
 *
 * Legt zwei echte Konten an und baut für beide Team + brands-Zeile genau so wie
 * client/src/lib/auth.ts. Danach: sieht Konto B irgendetwas von Konto A?
 *
 * Kein SDK, nur fetch mit eigenem Cookie-Speicher – so verhält sich der Aufruf
 * wie ein Browser, und der Test hängt nicht an SDK-Eigenheiten.
 */
const ENDPOINT = 'https://appwrite.webklar.com/v1';
const PROJECT = '6a5cee34002bb8360c34';
const DB = 'brandloop';
const KEY = process.env.APPWRITE_API_KEY;
if (!KEY) { console.error('APPWRITE_API_KEY fehlt'); process.exit(1); }

const stamp = Date.now();
let fehler = 0;
const ok = (m) => console.log(`  ok   ${m}`);
const bad = (m) => { fehler++; console.log(`  FEHL ${m}`); };
const limit = encodeURIComponent(JSON.stringify({ method: 'limit', values: [100] }));

/** Ein Konto = ein Cookie-Speicher, so wie ein Browser-Profil. */
function neueSitzung() {
  const jar = new Map();
  return async function call(method, path, body) {
    const headers = { 'X-Appwrite-Project': PROJECT, 'Content-Type': 'application/json' };
    if (jar.size) headers.Cookie = [...jar].map(([k, v]) => `${k}=${v}`).join('; ');
    const res = await fetch(`${ENDPOINT}${path}`, {
      method, headers, body: body ? JSON.stringify(body) : undefined, redirect: 'manual',
    });
    for (const c of res.headers.getSetCookie?.() ?? []) {
      const [pair] = c.split(';');
      const i = pair.indexOf('=');
      if (i > 0) jar.set(pair.slice(0, i).trim(), pair.slice(i + 1).trim());
    }
    const text = await res.text();
    let json; try { json = JSON.parse(text); } catch { json = { message: text }; }
    return { status: res.status, json };
  };
}

const admin = async (method, path, body) => {
  const res = await fetch(`${ENDPOINT}${path}`, {
    method,
    headers: { 'X-Appwrite-Project': PROJECT, 'X-Appwrite-Key': KEY, 'Content-Type': 'application/json' },
    body: body ? JSON.stringify(body) : undefined,
  });
  const text = await res.text();
  let json; try { json = JSON.parse(text); } catch { json = { message: text }; }
  return { status: res.status, json };
};

function muss(r, was) {
  if (r.status >= 200 && r.status < 300) return r.json;
  throw new Error(`${was}: HTTP ${r.status} – ${r.json?.message}`);
}

/** Spiegelt client/src/lib/auth.ts: Konto → Session → Team → brands-Zeile. */
async function kontoAnlegen(kennung) {
  const call = neueSitzung();
  const email = `e2-${kennung}-${stamp}@brandloop.test`;
  const password = `Test-${stamp}-${kennung}!`;
  const label = `Marke ${kennung.toUpperCase()}`;

  const user = muss(await call('POST', '/account', { userId: 'unique()', email, password, name: label }), 'account');
  muss(await call('POST', '/account/sessions/email', { email, password }), 'session');

  const team = muss(await call('POST', '/teams', { teamId: 'unique()', name: label }), 'team');
  const rolle = `team:${team.$id}`;
  const brand = muss(await call('POST', `/tablesdb/${DB}/tables/brands/rows`, {
    rowId: 'unique()',
    data: { team_id: team.$id, label_name: label, status: 'trial', plan: 'trial' },
    permissions: [`read("${rolle}")`, `update("${rolle}")`, `delete("${rolle}")`],
  }), 'brands-Zeile');

  return { call, userId: user.$id, teamId: team.$id, brandId: brand.$id, label };
}

console.log('Konten anlegen (wie der Client es tut):');
const A = await kontoAnlegen('a');
console.log(`  A: user=${A.userId} team=${A.teamId} brand=${A.brandId}`);
const B = await kontoAnlegen('b');
console.log(`  B: user=${B.userId} team=${B.teamId} brand=${B.brandId}`);

console.log('\nMandantentrennung:');

const liste = await B.call('GET', `/tablesdb/${DB}/tables/brands/rows?queries[]=${limit}`);
const ids = (liste.json.rows ?? []).map((r) => r.$id);
if (ids.includes(A.brandId)) bad(`B sieht A's Zeile in der Liste`);
else ok(`B listet ${ids.length} brands-Zeile(n), A's ist nicht dabei`);
if (!ids.includes(B.brandId)) bad('B sieht die EIGENE Zeile nicht – Rechte zu streng');
else ok('B sieht die eigene Zeile');

const direkt = await B.call('GET', `/tablesdb/${DB}/tables/brands/rows/${A.brandId}`);
if (direkt.status < 300) bad(`B konnte A's Zeile direkt lesen (HTTP ${direkt.status})`);
else ok(`Direktzugriff B→A abgewiesen (HTTP ${direkt.status} ${direkt.json?.type ?? ''})`);

const schreib = await B.call('PATCH', `/tablesdb/${DB}/tables/brands/rows/${A.brandId}`, { data: { label_name: 'gekapert' } });
if (schreib.status < 300) bad(`B konnte A's Zeile ÄNDERN (HTTP ${schreib.status})`);
else ok(`Schreibzugriff B→A abgewiesen (HTTP ${schreib.status} ${schreib.json?.type ?? ''})`);

// Gegenprobe: sieht der Server-Key beide? Sonst wäre der erste Test wertlos,
// weil dann vielleicht schlicht nichts in der Tabelle steht.
const alle = await admin('GET', `/tablesdb/${DB}/tables/brands/rows?queries[]=${limit}`);
const alleIds = (alle.json.rows ?? []).map((r) => r.$id);
if (alleIds.includes(A.brandId) && alleIds.includes(B.brandId)) ok(`Server-Key sieht beide Zeilen (${alle.json.total} gesamt) – der erste Test ist damit aussagekräftig`);
else bad(`Server-Key sieht nicht beide: ${JSON.stringify(alleIds)}`);

console.log('\nAufräumen:');
for (const k of [A, B]) {
  await admin('DELETE', `/tablesdb/${DB}/tables/brands/rows/${k.brandId}`);
  await admin('DELETE', `/teams/${k.teamId}`);
  await admin('DELETE', `/users/${k.userId}`);
}
const rest = await admin('GET', `/tablesdb/${DB}/tables/brands/rows?queries[]=${limit}`);
console.log(`  Testkonten entfernt, brands enthält jetzt ${rest.json.total} Zeile(n).`);

console.log(fehler ? `\n${fehler} FEHLER – Mandantentrennung nicht dicht.` : '\nMandantentrennung hält.');
process.exit(fehler ? 1 : 0);
