/**
 * persistSessionCookie() middleware — unit tests.
 *
 * Tests the two critical behavioral properties:
 *   A (persist path):  when oidcAuthJwt is set on context, the response includes an
 *                      oidc-auth Set-Cookie with Max-Age, SameSite=Lax, HttpOnly, Secure.
 *   B (guard path):    when oidcAuthJwt is NOT set, no oidc-auth Set-Cookie is emitted
 *                      (the no-resurrection security guard).
 *
 * Does NOT call @hono/oidc-auth — sets the context variable directly to keep this a
 * pure unit test that runs without MariaDB or any external service.
 */

import { describe, it, expect, afterEach } from 'vitest';
import { Hono } from 'hono';
import { persistSessionCookie } from '../../src/auth/persistSessionCookie.js';

// Read the cookie name the same way the implementation does so the test stays correct
// if OIDC_COOKIE_NAME is overridden in the environment.
const COOKIE_NAME = process.env.OIDC_COOKIE_NAME ?? 'oidc-auth';

afterEach(() => {
  // Nothing to restore: these tests do not mutate process.env.
});

describe('persistSessionCookie middleware', () => {
  describe('Test A — persist path (oidcAuthJwt truthy)', () => {
    it('emits an oidc-auth Set-Cookie with Max-Age, SameSite=Lax, HttpOnly, and Secure', async () => {
      const app = new Hono();

      // Simulate what @hono/oidc-auth does: set a signed session JWT on context.
      app.use('/api/*', async (c, next) => {
        c.set('oidcAuthJwt' as never, 'header.payload.sig');
        await next();
      });

      app.use('/api/*', persistSessionCookie());

      app.get('/api/test', (c) => c.json({ ok: true }));

      const res = await app.request('/api/test');
      expect(res.status).toBe(200);

      const setCookieHeader = res.headers.get('set-cookie');
      expect(setCookieHeader).not.toBeNull();

      // Cookie name must appear in the Set-Cookie value.
      expect(setCookieHeader).toContain(COOKIE_NAME);

      // Max-Age must be present (persistent cookie, not session-scoped).
      expect(setCookieHeader?.toLowerCase()).toContain('max-age');

      // SameSite=Lax must be present.
      expect(setCookieHeader?.toLowerCase()).toContain('samesite=lax');

      // HttpOnly must be present.
      expect(setCookieHeader?.toLowerCase()).toContain('httponly');

      // Secure must be present.
      expect(setCookieHeader?.toLowerCase()).toContain('secure');
    });

    it('re-issues the same JWT value the library provided (no re-signing)', async () => {
      const dummyJwt = 'header.payload.sig';
      const app = new Hono();

      app.use('/api/*', async (c, next) => {
        c.set('oidcAuthJwt' as never, dummyJwt);
        await next();
      });

      app.use('/api/*', persistSessionCookie());
      app.get('/api/test', (c) => c.json({ ok: true }));

      const res = await app.request('/api/test');
      const setCookieHeader = res.headers.get('set-cookie') ?? '';

      // The cookie value must contain the exact JWT string (URL-encoded = is fine but
      // the JWT characters must all appear).
      expect(setCookieHeader).toContain(dummyJwt);
    });
  });

  describe('Test B — guard path (oidcAuthJwt falsy / absent)', () => {
    it('emits NO oidc-auth Set-Cookie when oidcAuthJwt is not set (no resurrection)', async () => {
      const app = new Hono();

      // Do NOT set oidcAuthJwt — simulates a logged-out or unauthenticated request.
      app.use('/api/*', persistSessionCookie());
      app.get('/api/test', (c) => c.json({ ok: true }));

      const res = await app.request('/api/test');
      expect(res.status).toBe(200);

      const setCookieHeader = res.headers.get('set-cookie');

      // Either no Set-Cookie header at all, or it must not contain the oidc-auth cookie.
      const hasOidcCookie = setCookieHeader !== null && setCookieHeader.includes(COOKIE_NAME);
      expect(hasOidcCookie).toBe(false);
    });

    it('emits NO Set-Cookie when oidcAuthJwt is explicitly set to empty string', async () => {
      const app = new Hono();

      app.use('/api/*', async (c, next) => {
        c.set('oidcAuthJwt' as never, '');
        await next();
      });

      app.use('/api/*', persistSessionCookie());
      app.get('/api/test', (c) => c.json({ ok: true }));

      const res = await app.request('/api/test');
      const setCookieHeader = res.headers.get('set-cookie');

      const hasOidcCookie = setCookieHeader !== null && setCookieHeader.includes(COOKIE_NAME);
      expect(hasOidcCookie).toBe(false);
    });
  });
});
