/**
 * APIS-014 — No-auth branding admin passthrough posture.
 *
 * Branding upload/delete are guarded by an injected `adminGuard` RequestHandler.
 * The mount contract (MountBrandingOptions.adminGuard doc) is:
 *   "Admin-only middleware. When auth is disabled, pass a passthrough."
 *
 * The server wires this guard differently per deployment:
 *   - authActive=true  → adminGuard = requireAdmin (non-admin blocked 401/403)
 *   - authActive=false → adminGuard = passthrough  (no admin concept exists)
 *
 * This file documents + asserts that intended posture at the mount level:
 *   1. Passthrough guard (no-auth) → upload/delete reach the handler (open).
 *   2. Denying guard (auth, non-admin) → 403, handler NOT reached.
 *   3. Allowing guard (auth, admin)   → handler reached.
 *
 * Authorization model (confirmed intended, 2026-06-25): no-auth mode assumes a
 * trusted single-tenant deployment with no admin concept, so branding
 * upload/delete being open then is by design — acceptable, not a hole (same
 * passthrough model as admin-api). These tests pin that contract: open under
 * passthrough, blocked (403) the moment a real admin guard is wired.
 */
import { afterEach, describe, expect, it, vi } from 'vitest';
import express, { type RequestHandler } from 'express';
import request from 'supertest';
import { mkdtempSync, rmSync } from 'node:fs';
import { join } from 'node:path';
import { tmpdir } from 'node:os';
import { ConfigManager } from '../config-manager.js';
import { mountBrandingApi } from './branding-api.js';

/** A 1x1 transparent PNG, base64. Small valid favicon payload. */
const PNG_1x1 =
  'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==';

function makeApp(adminGuard: RequestHandler) {
  const dir = mkdtempSync(join(tmpdir(), 'maestro-branding-noauth-'));
  // Minimal valid config so ConfigManager loads.
  const cm = new ConfigManager(join(dir, 'config.yaml'));
  const app = express();
  mountBrandingApi(app, cm, { brandingDir: join(dir, 'branding'), adminGuard });
  return { app, dir };
}

// Passthrough = the no-auth wiring the server uses when authActive=false.
const passthrough: RequestHandler = (_req, _res, next) => next();
// Denying guard = requireAdmin rejecting a non-admin.
const deny403: RequestHandler = (_req, res) => { res.status(403).json({ error: 'forbidden' }); };

describe('APIS-014 branding adminGuard no-auth posture', () => {
  let dir = '';
  afterEach(() => {
    if (dir) { rmSync(dir, { recursive: true, force: true }); dir = ''; }
    vi.restoreAllMocks();
  });

  it('by design: passthrough guard (no-auth, trusted deployment) lets anyone upload branding', async () => {
    const a = makeApp(passthrough); dir = a.dir;
    const res = await request(a.app)
      .post('/api/branding/upload')
      .send({ kind: 'favicon', filename: 'fav.png', contentBase64: PNG_1x1 });
    // Reaches the real handler (no auth) → 200 success, not a 401/403.
    expect(res.status).toBe(200);
    expect(res.body.ok).toBe(true);
  });

  it('by design: passthrough guard (no-auth, trusted deployment) lets anyone delete branding', async () => {
    const a = makeApp(passthrough); dir = a.dir;
    const res = await request(a.app)
      .delete('/api/branding/upload')
      .send({ kind: 'favicon' });
    // Reaches the handler; not blocked by auth. (200 or 400 depending on body
    // validation, but crucially NOT 401/403.)
    expect(res.status).not.toBe(401);
    expect(res.status).not.toBe(403);
  });

  it('denying guard (auth, non-admin) → 403 and the upload handler is NOT reached', async () => {
    const a = makeApp(deny403); dir = a.dir;
    const res = await request(a.app)
      .post('/api/branding/upload')
      .send({ kind: 'favicon', filename: 'fav.png', contentBase64: PNG_1x1 });
    expect(res.status).toBe(403);
    expect(res.body).toEqual({ error: 'forbidden' });
  });

  it('denying guard (auth, non-admin) → 403 on delete too', async () => {
    const a = makeApp(deny403); dir = a.dir;
    const res = await request(a.app).delete('/api/branding/upload').send({ kind: 'favicon' });
    expect(res.status).toBe(403);
  });

  it('allowing guard (auth, admin) reaches the upload handler', async () => {
    // Admin guard that calls next() — equivalent to requireAdmin passing.
    const allow: RequestHandler = (_req, _res, next) => next();
    const a = makeApp(allow); dir = a.dir;
    const res = await request(a.app)
      .post('/api/branding/upload')
      .send({ kind: 'favicon', filename: 'fav.png', contentBase64: PNG_1x1 });
    expect(res.status).toBe(200);
    expect(res.body.ok).toBe(true);
  });

  it('public GET /api/branding stays open regardless of guard (login page needs it)', async () => {
    const a = makeApp(deny403); dir = a.dir;
    const res = await request(a.app).get('/api/branding');
    expect(res.status).toBe(200);
    expect(res.body).toHaveProperty('appName');
  });
});
