'use strict';

// Batch 5: "erase my data" wipes the requesting user's financial data only — never
// another user's, never the account/auth — and re-seeds default categories.
const test = require('node:test');
const assert = require('node:assert/strict');
const os = require('node:os');
const path = require('node:path');
const fs = require('node:fs');

const dbPath = path.join(os.tmpdir(), `bill-tracker-erase-${process.pid}.sqlite`);
process.env.DB_PATH = dbPath;

const { getDb, closeDb } = require('../db/database');
const { eraseUserData } = require('../services/userDataService');

function makeUser(db, name) {
  return db.prepare("INSERT INTO users (username, password_hash, role, active) VALUES (?, 'hash', 'user', 1)").run(name).lastInsertRowid;
}
function seedFinancialData(db, userId, label) {
  const catId = db.prepare("INSERT INTO categories (user_id, name) VALUES (?, ?)").run(userId, `${label}-cat`).lastInsertRowid;
  const billId = db.prepare("INSERT INTO bills (user_id, name, category_id, due_day, expected_amount, active) VALUES (?, ?, ?, 1, 5000, 1)").run(userId, `${label}-bill`, catId).lastInsertRowid;
  db.prepare("INSERT INTO payments (bill_id, amount, paid_date, payment_source) VALUES (?, 5000, '2026-06-01', 'manual')").run(billId);
  const dsId = db.prepare("INSERT INTO data_sources (user_id, type, provider, name, status) VALUES (?, 'file_import', 'csv', 'CSV Import', 'active')").run(userId).lastInsertRowid;
  db.prepare("INSERT INTO transactions (user_id, data_source_id, source_type, provider_transaction_id, amount, match_status, ignored) VALUES (?, ?, 'file_import', ?, -5000, 'unmatched', 0)").run(userId, dsId, `${label}-tx`);
  return { billId, catId, dsId };
}
const countFinancial = (db, userId) => ({
  bills: db.prepare('SELECT COUNT(*) n FROM bills WHERE user_id=?').get(userId).n,
  payments: db.prepare('SELECT COUNT(*) n FROM payments p JOIN bills b ON b.id=p.bill_id WHERE b.user_id=?').get(userId).n,
  transactions: db.prepare('SELECT COUNT(*) n FROM transactions WHERE user_id=?').get(userId).n,
  data_sources: db.prepare('SELECT COUNT(*) n FROM data_sources WHERE user_id=?').get(userId).n,
  categories: db.prepare('SELECT COUNT(*) n FROM categories WHERE user_id=?').get(userId).n,
});

let db, userA, userB;
test.before(() => {
  db = getDb();
  db.pragma('foreign_keys = ON');
  userA = makeUser(db, 'erase-a');
  userB = makeUser(db, 'erase-b');
  seedFinancialData(db, userA, 'a');
  seedFinancialData(db, userB, 'b');
  // a session + a webauthn credential for user A to prove auth is preserved
  db.prepare("INSERT INTO sessions (id, user_id, expires_at) VALUES ('sess-a', ?, datetime('now','+1 day'))").run(userA);
});
test.after(() => {
  closeDb();
  for (const s of ['', '-wal', '-shm']) { try { fs.unlinkSync(dbPath + s); } catch {} }
});

test('erase wipes the requesting user\'s financial data', () => {
  const before = countFinancial(db, userA);
  assert.ok(before.bills > 0 && before.payments > 0 && before.transactions > 0 && before.data_sources > 0);

  const result = eraseUserData(db, userA);
  assert.ok(result.erased > 0);

  const after = countFinancial(db, userA);
  assert.equal(after.bills, 0);
  assert.equal(after.payments, 0, 'bill-child payments cascade/removed');
  assert.equal(after.transactions, 0);
  assert.equal(after.data_sources, 0);
});

test('erase re-seeds default categories (app stays usable)', () => {
  const cats = db.prepare('SELECT COUNT(*) n FROM categories WHERE user_id=?').get(userA).n;
  assert.ok(cats > 0, 'default categories re-seeded after wipe');
});

test('erase never touches another user\'s data', () => {
  const b = countFinancial(db, userB);
  assert.ok(b.bills > 0 && b.payments > 0 && b.transactions > 0 && b.data_sources > 0, 'user B untouched');
});

test('erase preserves the account and auth (session, user row)', () => {
  assert.ok(db.prepare('SELECT 1 FROM users WHERE id=?').get(userA), 'account preserved');
  assert.ok(db.prepare("SELECT 1 FROM sessions WHERE id='sess-a'").get(), 'session preserved');
});

test('erase is audited to import_history', () => {
  const row = db.prepare("SELECT file_type, source_filename FROM import_history WHERE user_id=? ORDER BY id DESC LIMIT 1").get(userA);
  assert.equal(row.file_type, 'erase-data');
  assert.equal(row.source_filename, 'erase-my-data');
});
