const test = require('node:test');
const assert = require('node:assert/strict');
const fs = require('node:fs');
const os = require('node:os');
const path = require('node:path');

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

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

function createUser(db, suffix) {
  return db.prepare(`
    INSERT INTO users (username, password_hash, role, active, created_at, updated_at)
    VALUES (?, 'x', 'user', 1, datetime('now'), datetime('now'))
  `).run(`profile-user-${suffix}`).lastInsertRowid;
}

function callProfileRoute(method, { userId, body = {} }) {
  const profileRouter = require('../routes/profile');
  const layer = profileRouter.stack.find(item => item.route?.path === '/' && item.route.methods[method]);
  assert.ok(layer, `route ${method.toUpperCase()} / should exist`);
  const handler = layer.route.stack[0].handle;

  return new Promise((resolve, reject) => {
    const req = {
      body,
      ip: '127.0.0.1',
      user: { id: userId, role: 'user' },
      get(header) {
        return header === 'user-agent' ? 'node:test' : undefined;
      },
    };
    const res = {
      statusCode: 200,
      status(code) {
        this.statusCode = code;
        return this;
      },
      json(data) {
        resolve({ status: this.statusCode, data });
      },
    };
    try {
      handler(req, res);
    } catch (err) {
      reject(err);
    }
  });
}

test.after(() => {
  closeDb();
  for (const suffix of ['', '-wal', '-shm']) {
    fs.rmSync(`${dbPath}${suffix}`, { force: true });
  }
});

test('profile name is persisted and returned consistently', async () => {
  const db = getDb();
  const userId = createUser(db, 'name');

  const saved = await callProfileRoute('patch', {
    userId,
    body: { name: 'Kasper Example' },
  });

  assert.equal(saved.status, 200);
  assert.equal(saved.data.profile.display_name, 'Kasper Example');
  assert.equal(saved.data.profile.displayName, 'Kasper Example');
  assert.equal(saved.data.profile.name, 'Kasper Example');

  const row = db.prepare('SELECT * FROM users WHERE id = ?').get(userId);
  assert.equal(row.display_name, 'Kasper Example');
  assert.deepEqual(
    {
      display_name: publicUser(row).display_name,
      displayName: publicUser(row).displayName,
      name: publicUser(row).name,
    },
    {
      display_name: 'Kasper Example',
      displayName: 'Kasper Example',
      name: 'Kasper Example',
    },
  );

  const loaded = await callProfileRoute('get', { userId });
  assert.equal(loaded.status, 200);
  assert.equal(loaded.data.display_name, 'Kasper Example');
  assert.equal(loaded.data.displayName, 'Kasper Example');
  assert.equal(loaded.data.name, 'Kasper Example');
});

test('clearing profile name falls back to username for display', async () => {
  const db = getDb();
  const userId = createUser(db, 'clear');

  const cleared = await callProfileRoute('patch', {
    userId,
    body: { displayName: '   ' },
  });

  const username = db.prepare('SELECT username FROM users WHERE id = ?').get(userId).username;

  assert.equal(cleared.status, 200);
  assert.equal(cleared.data.profile.display_name, null);
  assert.equal(cleared.data.profile.displayName, null);
  assert.equal(cleared.data.profile.name, username);
});
