/**
 * Tests for server/middleware/requireAuth.js
 *
 * requireAuth guards all authenticated API routes. Tests exercise the full
 * range of valid/invalid cookie states to ensure there's no bypass path.
 */

import requireAuth from '../../server/middleware/requireAuth.js';

// Build mock req/res/next objects
function makeReq({ signedCookie, plainCookie, cookieSecret } = {}) {
  // Set COOKIE_SECRET so signed path is taken when provided
  if (cookieSecret !== undefined) {
    process.env.COOKIE_SECRET = cookieSecret;
  } else {
    delete process.env.COOKIE_SECRET;
  }

  return {
    signedCookies: { emby_user: signedCookie },
    cookies: { emby_user: plainCookie }
  };
}

function makeRes() {
  const res = {
    statusCode: null,
    body: null,
    status(code) { this.statusCode = code; return this; },
    json(body) { this.body = body; return this; }
  };
  return res;
}

afterEach(() => {
  delete process.env.COOKIE_SECRET;
});

describe('requireAuth middleware', () => {
  describe('valid sessions', () => {
    it('calls next() with a valid signed cookie', () => {
      const payload = JSON.stringify({ id: 'u1', name: 'Alice', isAdmin: true });
      const req = makeReq({ signedCookie: payload, cookieSecret: 'secret' });
      const res = makeRes();
      const next = vi.fn();

      requireAuth(req, res, next);

      expect(next).toHaveBeenCalledOnce();
      expect(req.user).toMatchObject({ id: 'u1', name: 'Alice', isAdmin: true });
    });

    it('calls next() with a valid unsigned cookie (no COOKIE_SECRET)', () => {
      const payload = JSON.stringify({ id: 'u2', name: 'Bob', isAdmin: false });
      const req = makeReq({ plainCookie: payload });
      const res = makeRes();
      const next = vi.fn();

      requireAuth(req, res, next);

      expect(next).toHaveBeenCalledOnce();
      expect(req.user.id).toBe('u2');
    });

    it('coerces non-boolean isAdmin to boolean', () => {
      const payload = JSON.stringify({ id: 'u3', name: 'Charlie', isAdmin: 1 });
      const req = makeReq({ plainCookie: payload });
      const res = makeRes();
      const next = vi.fn();

      requireAuth(req, res, next);

      expect(next).toHaveBeenCalled();
      expect(req.user.isAdmin).toBe(true);
    });
  });

  describe('missing or invalid cookies', () => {
    it('returns 401 when no cookie is present', () => {
      const req = makeReq({});
      const res = makeRes();
      const next = vi.fn();

      requireAuth(req, res, next);

      expect(res.statusCode).toBe(401);
      expect(next).not.toHaveBeenCalled();
    });

    it('returns 401 when signed cookie value is false (tampered)', () => {
      // cookie-parser sets signed cookie to false when signature is invalid
      const req = makeReq({ signedCookie: false, cookieSecret: 'secret' });
      const res = makeRes();
      const next = vi.fn();

      requireAuth(req, res, next);

      expect(res.statusCode).toBe(401);
    });

    it('returns 401 for malformed JSON in cookie', () => {
      const req = makeReq({ plainCookie: 'not-json' });
      const res = makeRes();
      const next = vi.fn();

      requireAuth(req, res, next);

      expect(res.statusCode).toBe(401);
      expect(res.body.error).toBe('Invalid session');
    });

    it('returns 401 when id is missing', () => {
      const payload = JSON.stringify({ name: 'Alice', isAdmin: false });
      const req = makeReq({ plainCookie: payload });
      requireAuth(req, makeRes(), vi.fn());
      // no next called — handled in the assertion below
      const res = makeRes();
      const next = vi.fn();
      requireAuth(req, res, next);
      expect(res.statusCode).toBe(401);
      expect(next).not.toHaveBeenCalled();
    });

    it('returns 401 when name is missing', () => {
      const payload = JSON.stringify({ id: 'u1', isAdmin: false });
      const req = makeReq({ plainCookie: payload });
      const res = makeRes();
      requireAuth(req, res, vi.fn());
      expect(res.statusCode).toBe(401);
    });

    it('returns 401 when id is empty string', () => {
      const payload = JSON.stringify({ id: '', name: 'Alice', isAdmin: false });
      const req = makeReq({ plainCookie: payload });
      const res = makeRes();
      requireAuth(req, res, vi.fn());
      expect(res.statusCode).toBe(401);
    });
  });
});
