const mongoose = require('mongoose');
const { MongoMemoryServer } = require('mongodb-memory-server');
const { SystemRoles, PrincipalType } = require('librechat-data-provider');
const { SystemCapabilities } = require('@librechat/data-schemas');

jest.mock('@librechat/data-schemas', () => ({
  ...jest.requireActual('@librechat/data-schemas'),
  logger: { error: jest.fn(), warn: jest.fn(), debug: jest.fn(), info: jest.fn() },
}));

jest.mock('~/cache', () => ({
  getLogStores: jest.fn(() => ({
    get: jest.fn(),
    set: jest.fn(),
  })),
}));

const { User, SystemGrant } = require('~/db/models');
const canDeleteAccount = require('./canDeleteAccount');

let mongoServer;

beforeAll(async () => {
  mongoServer = await MongoMemoryServer.create();
  await mongoose.connect(mongoServer.getUri());
});

afterAll(async () => {
  await mongoose.disconnect();
  await mongoServer.stop();
});

beforeEach(async () => {
  await mongoose.connection.dropDatabase();
  delete process.env.ALLOW_ACCOUNT_DELETION;
});

const makeRes = () => {
  const send = jest.fn();
  const status = jest.fn().mockReturnValue({ send });
  return { status, send };
};

describe('canDeleteAccount', () => {
  describe('ALLOW_ACCOUNT_DELETION=true (default)', () => {
    it('calls next without hitting the DB', async () => {
      process.env.ALLOW_ACCOUNT_DELETION = 'true';
      const next = jest.fn();
      const req = { user: { id: 'user-1', role: SystemRoles.USER } };

      await canDeleteAccount(req, makeRes(), next);

      expect(next).toHaveBeenCalled();
    });

    it('skips capability check entirely when deletion is allowed', async () => {
      process.env.ALLOW_ACCOUNT_DELETION = 'true';
      const next = jest.fn();
      const req = { user: { id: 'user-1', role: SystemRoles.USER } };

      await canDeleteAccount(req, makeRes(), next);

      expect(next).toHaveBeenCalled();
      const grantCount = await SystemGrant.countDocuments();
      expect(grantCount).toBe(0);
    });
  });

  describe('ALLOW_ACCOUNT_DELETION=false', () => {
    beforeEach(() => {
      process.env.ALLOW_ACCOUNT_DELETION = 'false';
    });

    it('allows admin with ACCESS_ADMIN grant (real DB check)', async () => {
      const admin = await User.create({
        name: 'Admin',
        email: 'admin@test.com',
        password: 'password123',
        provider: 'local',
        role: SystemRoles.ADMIN,
      });

      await SystemGrant.create({
        principalType: PrincipalType.ROLE,
        principalId: SystemRoles.ADMIN,
        capability: SystemCapabilities.ACCESS_ADMIN,
        grantedAt: new Date(),
      });

      const next = jest.fn();
      const req = { user: { id: admin._id.toString(), role: SystemRoles.ADMIN } };

      await canDeleteAccount(req, makeRes(), next);

      expect(next).toHaveBeenCalled();
    });

    it('blocks regular user without ACCESS_ADMIN grant', async () => {
      const user = await User.create({
        name: 'Regular',
        email: 'user@test.com',
        password: 'password123',
        provider: 'local',
        role: SystemRoles.USER,
      });

      const next = jest.fn();
      const res = makeRes();
      const req = { user: { id: user._id.toString(), role: SystemRoles.USER } };

      await canDeleteAccount(req, res, next);

      expect(next).not.toHaveBeenCalled();
      expect(res.status).toHaveBeenCalledWith(403);
    });

    it('blocks admin role WITHOUT the ACCESS_ADMIN grant', async () => {
      const admin = await User.create({
        name: 'Admin No Grant',
        email: 'admin2@test.com',
        password: 'password123',
        provider: 'local',
        role: SystemRoles.ADMIN,
      });

      const next = jest.fn();
      const res = makeRes();
      const req = { user: { id: admin._id.toString(), role: SystemRoles.ADMIN } };

      await canDeleteAccount(req, res, next);

      expect(next).not.toHaveBeenCalled();
      expect(res.status).toHaveBeenCalledWith(403);
    });

    it('allows user-level grant (not just role-level)', async () => {
      const user = await User.create({
        name: 'Privileged User',
        email: 'priv@test.com',
        password: 'password123',
        provider: 'local',
        role: SystemRoles.USER,
      });

      await SystemGrant.create({
        principalType: PrincipalType.USER,
        principalId: user._id,
        capability: SystemCapabilities.ACCESS_ADMIN,
        grantedAt: new Date(),
      });

      const next = jest.fn();
      const req = { user: { id: user._id.toString(), role: SystemRoles.USER } };

      await canDeleteAccount(req, makeRes(), next);

      expect(next).toHaveBeenCalled();
    });

    it('blocks when user is undefined — does not throw', async () => {
      const next = jest.fn();
      const res = makeRes();

      await canDeleteAccount({ user: undefined }, res, next);

      expect(next).not.toHaveBeenCalled();
      expect(res.status).toHaveBeenCalledWith(403);
    });

    it('blocks when user is null — does not throw', async () => {
      const next = jest.fn();
      const res = makeRes();

      await canDeleteAccount({ user: null }, res, next);

      expect(next).not.toHaveBeenCalled();
      expect(res.status).toHaveBeenCalledWith(403);
    });
  });
});
