import { expect, vi, describe, it, beforeEach } from 'vitest'
import MockRequest from '../helpers/MockRequest.mjs'
import MockResponse from '../helpers/MockResponse.mjs'
import EntityConfigs from '../../../../app/src/Features/UserMembership/UserMembershipEntityConfigs.mjs'
import Errors from '../../../../app/src/Features/Errors/Errors.js'
import UserMembershipErrors from '../../../../app/src/Features/UserMembership/UserMembershipErrors.mjs'

const modulePath =
  '../../../../app/src/Features/UserMembership/UserMembershipController.mjs'

vi.mock(
  '../../../../app/src/Features/UserMembership/UserMembershipErrors.mjs',
  () =>
    vi.importActual(
      '../../../../app/src/Features/UserMembership/UserMembershipErrors.mjs'
    )
)

vi.mock('../../../../app/src/Features/Errors/Errors.js', () =>
  vi.importActual('../../../../app/src/Features/Errors/Errors.js')
)

describe('UserMembershipController', () => {
  let recurlySubscriptionId

  beforeEach(async ctx => {
    recurlySubscriptionId = 'mock-recurly-subscription-id'
    ctx.req = new MockRequest(vi)
    ctx.req.params.id = 'mock-entity-id'
    ctx.req.ip = '1.2.3.4'
    ctx.user = { _id: 'mock-user-id' }
    ctx.newUser = { _id: 'mock-new-user-id', email: 'new-user-email@foo.bar' }
    ctx.subscription = {
      _id: 'mock-subscription-id',
      admin_id: 'mock-admin-id',
      manager_ids: ['mock-admin-id'],
      planCode: 'group_professional',
      recurlySubscription_id: recurlySubscriptionId,
      fetchV1Data: vi.fn(callback => callback(null, ctx.subscription)),
    }
    ctx.institution = {
      _id: 'mock-institution-id',
      v1Id: 123,
      fetchV1Data: vi.fn(callback => {
        const institution = { ...ctx.institution }
        institution.name = 'Test Institution Name'
        callback(null, institution)
      }),
      managerIds: ['mock-member-id-1'],
    }
    ctx.users = [
      {
        _id: 'mock-member-id-1',
        email: 'mock-email-1@foo.com',
        last_logged_in_at: '2020-08-09T12:43:11.467Z',
        last_active_at: '2021-08-09T12:43:11.467Z',
      },
      {
        _id: 'mock-member-id-2',
        email: 'mock-email-2@foo.com',
        last_logged_in_at: '2020-05-20T10:41:11.407Z',
        last_active_at: '2021-05-20T10:41:11.407Z',
      },
      {
        _id: 'mock-member-id-3',
        email: 'mock-email-3@foo.com',
        last_logged_in_at: '2021-08-10T10:41:11.407Z',
        last_active_at: '2021-08-20T10:41:11.407Z',
        enrollment: {
          managedBy: 'some-other-subscription-id',
          enrolledAt: '2021-05-20T10:41:11.407Z',
          sso: undefined,
        },
      },
      {
        _id: 'mock-member-id-4',
        email: 'mock-email-4@foo.com',
        last_logged_in_at: '2021-01-01T10:41:11.407Z',
        last_active_at: '2021-01-02T10:41:11.407Z',
        enrollment: {
          managedBy: 'mock-subscription-id',
          enrolledAt: '2021-01-02T10:41:11.407Z',
          sso: undefined,
        },
      },
      {
        _id: 'mock-member-id-5',
        email: 'mock-email-5@foo.com',
        last_logged_in_at: '2023-01-01T10:41:11.407Z',
        last_active_at: '2023-01-02T10:41:11.407Z',
        enrollment: {
          sso: [{ groupId: ctx.subscription._id }],
        },
      },
      {
        _id: 'mock-member-id-6',
        email: 'mock-email-6@foo.com',
        last_logged_in_at: '2024-01-01T10:41:11.407Z',
        last_active_at: '2024-01-02T10:41:11.407Z',
        enrollment: {
          managedBy: 'mock-subscription-id',
          enrolledAt: '2024-01-02T10:41:11.407Z',
          sso: [{ groupId: ctx.subscription._id }],
        },
      },
    ]

    ctx.Settings = {
      managedUsers: {
        enabled: false,
      },
      plans: [
        {
          planCode: 'personal',
          name: 'Personal',
          price_in_cents: 0,
          features: {
            collaborators: -1,
            dropbox: true,
            github: true,
            gitBridge: true,
            versioning: true,
            compileTimeout: 180,
            compileGroup: 'standard',
            references: true,
            trackChanges: true,
          },
        },
      ],
    }

    ctx.SessionManager = {
      getSessionUser: vi.fn().mockReturnValue(ctx.user),
      getLoggedInUserId: vi.fn().mockReturnValue(ctx.user._id),
    }
    ctx.SSOConfig = {
      findById: vi.fn().mockReturnValue({
        exec: vi.fn().mockResolvedValue({ enabled: true }),
      }),
    }
    ctx.UserMembershipHandler = {
      getEntity: vi.fn((_entity, _options, callback) =>
        callback(null, ctx.subscription)
      ),
      createEntity: vi.fn((_entity, _options, callback) =>
        callback(null, ctx.institution)
      ),
      getUsers: vi.fn((_entity, _options, callback) =>
        callback(null, ctx.users)
      ),
      addUser: vi.fn((_entity, _options, _email, callback) =>
        callback(null, ctx.newUser)
      ),
      removeUser: vi.fn((_entity, _options, _userId, callback) =>
        callback(null)
      ),
      promises: {
        getUsers: vi.fn().mockResolvedValue(ctx.users),
        addUser: vi.fn().mockResolvedValue(ctx.newUser),
        removeUser: vi.fn().mockResolvedValue(),
        createEntity: vi.fn().mockResolvedValue(ctx.institution),
      },
    }
    ctx.SplitTestHandler = {
      promises: {
        getAssignment: vi.fn().mockResolvedValue({ variant: 'default' }),
      },
      getAssignment: vi.fn((_testName, _userId, callback) =>
        callback(null, { variant: 'default' })
      ),
    }
    ctx.RecurlyClient = {
      promises: {
        getSubscription: vi.fn().mockResolvedValue({
          id: recurlySubscriptionId,
        }),
      },
    }

    ctx.PlansLocator = {
      findLocalPlanInSettings: vi.fn().mockReturnValue({
        planCode: 'group_professional',
        canUseFlexibleLicensing: true,
      }),
    }

    vi.doMock(
      '../../../../app/src/Features/Authentication/SessionManager',
      () => ({
        default: ctx.SessionManager,
      })
    )

    vi.doMock(
      '../../../../app/src/Features/SplitTests/SplitTestHandler',
      () => ({
        default: ctx.SplitTestHandler,
      })
    )

    vi.doMock(
      '../../../../app/src/Features/UserMembership/UserMembershipHandler',
      () => ({
        default: ctx.UserMembershipHandler,
      })
    )

    vi.doMock(
      '../../../../app/src/Features/Subscription/RecurlyClient',
      () => ({
        default: ctx.RecurlyClient,
      })
    )

    vi.doMock(
      '../../../../app/src/Features/Subscription/PlansLocator.mjs',
      () => ({
        default: ctx.PlansLocator,
      })
    )

    vi.doMock('@overleaf/settings', () => ({
      default: ctx.Settings,
    }))

    vi.doMock('../../../../app/src/models/SSOConfig', () => ({
      SSOConfig: ctx.SSOConfig,
    }))

    ctx.Modules = {
      promises: {
        hooks: {
          fire: vi.fn(),
        },
      },
    }
    vi.doMock('../../../../app/src/infrastructure/Modules.mjs', () => ({
      default: ctx.Modules,
    }))

    ctx.UserMembershipController = (await import(modulePath)).default
  })

  describe('index', () => {
    beforeEach(ctx => {
      ctx.req.user = ctx.user
      ctx.req.entity = ctx.subscription
      ctx.req.entityConfig = EntityConfigs.group
      ctx.Modules.promises.hooks.fire.mockResolvedValue([])
    })

    it('get users', async ({
      UserMembershipController,
      req,
      UserMembershipHandler,
      subscription,
    }) => {
      expect.assertions(1)
      await UserMembershipController.manageGroupMembers(req, {
        render: () => {
          expect(UserMembershipHandler.promises.getUsers).toHaveBeenCalledWith(
            subscription,
            {
              modelName: 'Subscription',
              baseQuery: { groupPlan: true },
              fields: {
                access: 'manager_ids',
                membership: 'member_ids',
                name: 'teamName',
                primaryKey: '_id',
                read: ['invited_emails', 'teamInvites', 'member_ids'],
                write: null,
              },
              hasMembersLimit: true,
              readOnly: true,
            }
          )
        },
      })
    })

    it('render group view', async ({
      UserMembershipController,
      req,
      subscription,
      users,
    }) => {
      expect.assertions(4)
      subscription.managedUsersEnabled = false
      await UserMembershipController.manageGroupMembers(req, {
        render: (viewPath, viewParams) => {
          expect(viewPath).to.equal('user_membership/group-members-react')
          expect(viewParams.users).to.deep.equal(users)
          expect(viewParams.groupSize).to.equal(subscription.membersLimit)
          expect(viewParams.managedUsersActive).to.equal(false)
        },
      })
    })

    it('render group view with managed users', async ({
      UserMembershipController,
      req,
      subscription,
      users,
    }) => {
      expect.assertions(5)
      subscription.managedUsersEnabled = true
      await UserMembershipController.manageGroupMembers(req, {
        render: (viewPath, viewParams) => {
          expect(viewPath).to.equal('user_membership/group-members-react')
          expect(viewParams.users).to.deep.equal(users)
          expect(viewParams.groupSize).to.equal(subscription.membersLimit)
          expect(viewParams.managedUsersActive).to.equal(true)
          expect(viewParams.isUserGroupManager).to.equal(false)
        },
      })
    })

    describe('canUseAddSeatsFeature', () => {
      beforeEach(ctx => {
        ctx.subscription.admin_id = 'mock-admin-id'
        ctx.SessionManager.getLoggedInUserId.mockReturnValue('mock-admin-id')
      })

      it('should be true when all conditions are met', async ({
        UserMembershipController,
        req,
      }) => {
        expect.assertions(1)
        await UserMembershipController.manageGroupMembers(req, {
          render: (viewPath, viewParams) => {
            expect(viewParams.canUseAddSeatsFeature).to.equal(true)
          },
        })
      })

      it('should be false when plan does not support flexible licensing', async ({
        UserMembershipController,
        req,
        PlansLocator,
      }) => {
        expect.assertions(1)
        PlansLocator.findLocalPlanInSettings.mockReturnValue({
          planCode: 'group_professional',
          canUseFlexibleLicensing: false,
        })
        await UserMembershipController.manageGroupMembers(req, {
          render: (viewPath, viewParams) => {
            expect(viewParams.canUseAddSeatsFeature).to.equal(false)
          },
        })
      })

      it('should be false when user is not admin', async ({
        UserMembershipController,
        req,
        SessionManager,
      }) => {
        expect.assertions(1)
        SessionManager.getLoggedInUserId.mockReturnValue('mock-user-id')
        await UserMembershipController.manageGroupMembers(req, {
          render: (viewPath, viewParams) => {
            expect(viewParams.canUseAddSeatsFeature).to.equal(false)
          },
        })
      })

      it('should be false when recurly subscription does not exist', async ({
        UserMembershipController,
        req,
        subscription,
      }) => {
        expect.assertions(1)
        subscription.recurlySubscription_id = null
        await UserMembershipController.manageGroupMembers(req, {
          render: (viewPath, viewParams) => {
            expect(viewParams.canUseAddSeatsFeature).to.equal(false)
          },
        })
      })

      it('should be true when recurly subscription has pending changes', async ({
        UserMembershipController,
        req,
        RecurlyClient,
      }) => {
        expect.assertions(1)
        RecurlyClient.promises.getSubscription.mockResolvedValue({
          id: recurlySubscriptionId,
          pendingChange: {},
        })
        await UserMembershipController.manageGroupMembers(req, {
          render: (viewPath, viewParams) => {
            expect(viewParams.canUseAddSeatsFeature).to.equal(true)
          },
        })
      })

      it('should be false when fetching recurly subscription fails', async ({
        UserMembershipController,
        req,
        RecurlyClient,
      }) => {
        expect.assertions(1)
        RecurlyClient.promises.getSubscription.mockRejectedValue(
          new Error('Recurly error')
        )
        await UserMembershipController.manageGroupMembers(req, {
          render: (viewPath, viewParams) => {
            expect(viewParams.canUseAddSeatsFeature).to.equal(false)
          },
        })
      })

      it('should be false when plan is not found', async ({
        UserMembershipController,
        req,
        PlansLocator,
      }) => {
        expect.assertions(1)
        PlansLocator.findLocalPlanInSettings.mockReturnValue(null)
        await UserMembershipController.manageGroupMembers(req, {
          render: (viewPath, viewParams) => {
            expect(viewParams.canUseAddSeatsFeature).to.equal(false)
          },
        })
      })
    })

    it('render group managers view', async ({
      UserMembershipController,
      req,
      user,
    }) => {
      expect.assertions(2)
      req.user = user
      req.entityConfig = EntityConfigs.groupManagers
      await UserMembershipController.manageGroupManagers(req, {
        render: (viewPath, viewParams) => {
          expect(viewPath).to.equal('user_membership/group-managers-react')
          expect(viewParams.groupSize).to.equal(undefined)
        },
      })
    })

    it('render institution view', async ({
      UserMembershipController,
      req,
      user,
      institution,
    }) => {
      expect.assertions(3)
      req.user = user
      req.entity = institution
      req.entityConfig = EntityConfigs.institution
      await UserMembershipController.manageInstitutionManagers(req, {
        render: (viewPath, viewParams) => {
          expect(viewPath).to.equal(
            'user_membership/institution-managers-react'
          )
          expect(viewParams.name).to.equal('Test Institution Name')
          expect(viewParams.groupSize).to.equal(undefined)
        },
      })
    })
  })

  describe('add', () => {
    beforeEach(ctx => {
      ctx.req.body.email = ctx.newUser.email
      ctx.req.entity = ctx.subscription
      ctx.req.entityConfig = EntityConfigs.groupManagers
    })

    it('add user', async ({
      UserMembershipController,
      req,
      UserMembershipHandler,
      subscription,
      newUser,
    }) => {
      expect.assertions(1)
      await UserMembershipController.add(req, {
        json: () => {
          expect(UserMembershipHandler.promises.addUser).toHaveBeenCalledWith(
            subscription,
            {
              modelName: 'Subscription',
              baseQuery: { groupPlan: true },
              fields: {
                access: 'manager_ids',
                membership: 'member_ids',
                name: 'teamName',
                primaryKey: '_id',
                read: ['manager_ids'],
                write: 'manager_ids',
              },
            },
            newUser.email,
            { initiatorId: 'mock-user-id', ipAddress: '1.2.3.4' }
          )
        },
      })
    })

    it('return user object', async ({
      UserMembershipController,
      req,
      newUser,
    }) => {
      expect.assertions(1)
      await UserMembershipController.add(req, {
        json: payload => {
          expect(payload.user).to.equal(newUser)
        },
      })
    })

    it('handle readOnly entity', async ({ UserMembershipController, req }) => {
      expect.assertions(2)
      req.entityConfig = EntityConfigs.group
      await UserMembershipController.add(req, null, error => {
        expect(error).to.exist
        expect(error).to.be.an.instanceof(Errors.NotFoundError)
      })
    })

    it('handle user already added', async ({
      UserMembershipController,
      req,
      UserMembershipHandler,
    }) => {
      expect.assertions(1)
      UserMembershipHandler.promises.addUser.mockRejectedValue(
        new UserMembershipErrors.UserAlreadyAddedError()
      )
      await UserMembershipController.add(
        req,
        {
          status: () => ({
            json: payload => {
              expect(payload.error.code).to.equal('user_already_added')
            },
          }),
        },

        () => {}
      )
    })

    it('handle user not found', async ({
      UserMembershipController,
      req,
      UserMembershipHandler,
    }) => {
      expect.assertions(1)
      UserMembershipHandler.promises.addUser.mockRejectedValue(
        new UserMembershipErrors.UserNotFoundError()
      )
      await UserMembershipController.add(req, {
        status: () => ({
          json: payload => {
            expect(payload.error.code).to.equal('user_not_found')
          },
        }),
      })
    })

    it('handle invalid email', async ({ UserMembershipController, req }) => {
      expect.assertions(1)
      req.body.email = 'not_valid_email'
      await UserMembershipController.add(req, {
        status: () => ({
          json: payload => {
            expect(payload.error.code).to.equal('invalid_email')
          },
        }),
      })
    })
  })

  describe('remove', () => {
    beforeEach(ctx => {
      ctx.req.params.userId = ctx.newUser._id
      ctx.req.entity = ctx.subscription
      ctx.req.entityConfig = EntityConfigs.groupManagers
    })

    it('remove user', async ({
      UserMembershipController,
      req,
      UserMembershipHandler,
      subscription,
      newUser,
    }) => {
      expect.assertions(1)
      await UserMembershipController.remove(req, {
        sendStatus: () => {
          expect(
            UserMembershipHandler.promises.removeUser
          ).toHaveBeenCalledWith(
            subscription,
            {
              modelName: 'Subscription',

              baseQuery: {
                groupPlan: true,
              },
              fields: {
                access: 'manager_ids',
                membership: 'member_ids',
                name: 'teamName',
                primaryKey: '_id',
                read: ['manager_ids'],
                write: 'manager_ids',
              },
            },
            newUser._id,
            { initiatorId: 'mock-user-id', ipAddress: '1.2.3.4' }
          )
        },
      })
    })

    it('handle readOnly entity', async ({ UserMembershipController, req }) => {
      expect.assertions(2)
      req.entityConfig = EntityConfigs.group
      await UserMembershipController.remove(req, null, error => {
        expect(error).to.exist
        expect(error).to.be.an.instanceof(Errors.NotFoundError)
      })
    })

    it('prevent self removal', async ({
      UserMembershipController,
      req,
      user,
    }) => {
      expect.assertions(1)
      req.params.userId = user._id
      await UserMembershipController.remove(req, {
        status: () => ({
          json: payload => {
            expect(payload.error.code).to.equal('managers_cannot_remove_self')
          },
        }),
      })
    })

    it('prevent admin removal', async ({
      UserMembershipController,
      req,
      UserMembershipHandler,
    }) => {
      expect.assertions(1)
      UserMembershipHandler.promises.removeUser.mockRejectedValue(
        new UserMembershipErrors.UserIsManagerError()
      )
      await UserMembershipController.remove(req, {
        status: () => ({
          json: payload => {
            expect(payload.error.code).to.equal('managers_cannot_remove_admin')
          },
        }),
      })
    })
  })

  describe('exportCsv', () => {
    beforeEach(ctx => {
      ctx.req.entity = ctx.subscription
      ctx.req.entityConfig = EntityConfigs.groupManagers
      ctx.res = new MockResponse(vi)
      ctx.UserMembershipController.exportCsv(ctx.req, ctx.res)
    })

    it('get users', ({ UserMembershipHandler, subscription }) => {
      expect(UserMembershipHandler.promises.getUsers).toHaveBeenCalledWith(
        subscription,
        {
          modelName: 'Subscription',
          baseQuery: { groupPlan: true },
          fields: {
            access: 'manager_ids',
            membership: 'member_ids',
            name: 'teamName',
            primaryKey: '_id',
            read: ['manager_ids'],
            write: 'manager_ids',
          },
        }
      )
    })

    it('should set the correct content type on the request', ({ res }) => {
      expect(res.contentType).toHaveBeenCalledWith('text/csv; charset=utf-8')
    })

    it('should name the exported csv file', ({ res }) => {
      expect(res.header).toHaveBeenCalledWith(
        'Content-Disposition',
        'attachment; filename="Group.csv"'
      )
    })

    it('should export the correct csv', ({ res }) => {
      expect(res.send).toHaveBeenCalledWith(
        '"email","last_logged_in_at","last_active_at"\n"mock-email-1@foo.com","2020-08-09T12:43:11.467Z","2021-08-09T12:43:11.467Z"\n"mock-email-2@foo.com","2020-05-20T10:41:11.407Z","2021-05-20T10:41:11.407Z"\n"mock-email-3@foo.com","2021-08-10T10:41:11.407Z","2021-08-20T10:41:11.407Z"\n"mock-email-4@foo.com","2021-01-01T10:41:11.407Z","2021-01-02T10:41:11.407Z"\n"mock-email-5@foo.com","2023-01-01T10:41:11.407Z","2023-01-02T10:41:11.407Z"\n"mock-email-6@foo.com","2024-01-01T10:41:11.407Z","2024-01-02T10:41:11.407Z"'
      )
    })
  })

  describe('exportCsv when group is managed', () => {
    beforeEach(ctx => {
      ctx.req.entity = Object.assign(
        { managedUsersEnabled: true },
        ctx.subscription
      )
      ctx.req.entityConfig = EntityConfigs.groupManagers
      ctx.res = new MockResponse(vi)
      ctx.UserMembershipController.exportCsv(ctx.req, ctx.res)
    })

    it('should export the correct csv', ({ res }) => {
      expect(res.send).toHaveBeenCalledWith(
        '"email","last_logged_in_at","last_active_at","managed"\n"mock-email-1@foo.com","2020-08-09T12:43:11.467Z","2021-08-09T12:43:11.467Z",false\n"mock-email-2@foo.com","2020-05-20T10:41:11.407Z","2021-05-20T10:41:11.407Z",false\n"mock-email-3@foo.com","2021-08-10T10:41:11.407Z","2021-08-20T10:41:11.407Z",false\n"mock-email-4@foo.com","2021-01-01T10:41:11.407Z","2021-01-02T10:41:11.407Z",true\n"mock-email-5@foo.com","2023-01-01T10:41:11.407Z","2023-01-02T10:41:11.407Z",false\n"mock-email-6@foo.com","2024-01-01T10:41:11.407Z","2024-01-02T10:41:11.407Z",true'
      )
    })
  })

  describe('exportCsv when group has SSO', () => {
    beforeEach(ctx => {
      ctx.req.entity = Object.assign(
        { ssoConfig: 'sso-config-id' },
        ctx.subscription
      )
      ctx.req.entityConfig = EntityConfigs.groupManagers
      ctx.Modules.promises.hooks.fire.mockResolvedValue([true])
      ctx.res = new MockResponse(vi)
      ctx.UserMembershipController.exportCsv(ctx.req, ctx.res)
    })

    it('should export the correct csv', ({ res }) => {
      expect(res.send).toHaveBeenCalledWith(
        '"email","last_logged_in_at","last_active_at","sso"\n"mock-email-1@foo.com","2020-08-09T12:43:11.467Z","2021-08-09T12:43:11.467Z",false\n"mock-email-2@foo.com","2020-05-20T10:41:11.407Z","2021-05-20T10:41:11.407Z",false\n"mock-email-3@foo.com","2021-08-10T10:41:11.407Z","2021-08-20T10:41:11.407Z",false\n"mock-email-4@foo.com","2021-01-01T10:41:11.407Z","2021-01-02T10:41:11.407Z",false\n"mock-email-5@foo.com","2023-01-01T10:41:11.407Z","2023-01-02T10:41:11.407Z",true\n"mock-email-6@foo.com","2024-01-01T10:41:11.407Z","2024-01-02T10:41:11.407Z",true'
      )
    })
  })

  describe('exportCsv when group has SSO and managed users enabled', () => {
    beforeEach(ctx => {
      ctx.req.entity = Object.assign(
        { managedUsersEnabled: true },
        { ssoConfig: 'sso-config-id' },
        ctx.subscription
      )
      ctx.req.entityConfig = EntityConfigs.groupManagers
      ctx.Modules.promises.hooks.fire.mockResolvedValue([true])
      ctx.res = new MockResponse(vi)
      ctx.UserMembershipController.exportCsv(ctx.req, ctx.res)
    })

    it('should export the correct csv', ({ res }) => {
      expect(res.send).toHaveBeenCalledWith(
        '"email","last_logged_in_at","last_active_at","managed","sso"\n"mock-email-1@foo.com","2020-08-09T12:43:11.467Z","2021-08-09T12:43:11.467Z",false,false\n"mock-email-2@foo.com","2020-05-20T10:41:11.407Z","2021-05-20T10:41:11.407Z",false,false\n"mock-email-3@foo.com","2021-08-10T10:41:11.407Z","2021-08-20T10:41:11.407Z",false,false\n"mock-email-4@foo.com","2021-01-01T10:41:11.407Z","2021-01-02T10:41:11.407Z",true,false\n"mock-email-5@foo.com","2023-01-01T10:41:11.407Z","2023-01-02T10:41:11.407Z",false,true\n"mock-email-6@foo.com","2024-01-01T10:41:11.407Z","2024-01-02T10:41:11.407Z",true,true'
      )
    })
  })

  describe('new', () => {
    beforeEach(ctx => {
      ctx.req.params.name = 'publisher'
      ctx.req.params.id = 'abc'
    })

    it('renders view', async ({ UserMembershipController, req }) => {
      expect.assertions(2)
      await UserMembershipController.new(req, {
        render: (viewPath, data) => {
          expect(data.entityName).to.eq('publisher')
          expect(data.entityId).to.eq('abc')
        },
      })
    })
  })

  describe('create', () => {
    beforeEach(ctx => {
      ctx.req.params.name = 'institution'
      ctx.req.entityConfig = EntityConfigs.institution
      ctx.req.params.id = 123
    })

    it('creates institution', async ({
      UserMembershipController,
      req,
      UserMembershipHandler,
    }) => {
      expect.assertions(2)
      await UserMembershipController.create(req, {
        redirect: path => {
          expect(path).to.eq(EntityConfigs.institution.pathsFor(123).index)
          expect(
            UserMembershipHandler.promises.createEntity
          ).toHaveBeenCalledWith(123, {
            fields: {
              access: 'managerIds',
              membership: 'member_ids',
              name: 'name',
              primaryKey: 'v1Id',
              read: ['managerIds'],
              write: 'managerIds',
            },
            modelName: 'Institution',
            pathsFor: EntityConfigs.institution.pathsFor,
          })
        },
      })
    })
  })
})
