const {agentProvider, fixtureManager, matchers} = require('../../utils/e2e-framework');
const {anyContentVersion, anyEtag, anyErrorId, anyObjectId, anyISODate, stringMatching, anyContentLength} = matchers;

const webhookMatcher = {
    id: anyObjectId,
    api_version: stringMatching(/v\d+\.\d+/),
    integration_id: anyObjectId,
    created_at: anyISODate,
    updated_at: anyISODate
};

describe('Webhooks API', function () {
    let agent;
    let createdWebhookId;
    let webhookData;

    beforeAll(async function () {
        agent = await agentProvider.getAdminAPIAgent();
        await fixtureManager.init('integrations');
        await agent.loginAsOwner();

        // create a webhook linked to a real integration
        webhookData = {
            event: 'test.create',
            target_url: 'http://example.com/webhooks/test/extra/1',
            name: 'test',
            secret: 'thisissecret',
            integration_id: fixtureManager.get('integrations', 0).id
        };
    });

    it('Can create a webhook', async function () {
        const {body} = await agent.post('/webhooks/')
            .body({webhooks: [webhookData]})
            .expectStatus(201)
            .matchHeaderSnapshot({
                // Note: No location header as there is no read method for webhooks
                etag: anyEtag,
                'content-version': anyContentVersion,
                'content-length': anyContentLength

            })
            .matchBodySnapshot({
                webhooks: [webhookMatcher]
            });

        // Store an id for use in future tests. Not the best pattern but does keep the tests readable.
        createdWebhookId = body.webhooks[0].id;
    });

    it('Fails nicely when adding a duplicate webhook', async function () {
        await agent.post('/webhooks/')
            .body({webhooks: [webhookData]})
            .expectStatus(422)
            .matchHeaderSnapshot({
                'content-version': anyContentVersion,
                etag: anyEtag
            })
            .matchBodySnapshot({
                errors: [{
                    id: anyErrorId
                }]
            });
    });

    it('Fails nicely when creating an orphaned webhook', async function () {
        await agent
            .post('/webhooks/')
            .body({webhooks: [{
                event: 'test.create',
                target_url: 'http://example.com/webhooks/test/extra/10',
                name: 'test',
                secret: 'thisissecret',
                integration_id: `fake-integration`
            }]})
            .expectStatus(422)
            .matchHeaderSnapshot({
                'content-version': anyContentVersion,
                etag: anyEtag
            })
            .matchBodySnapshot({
                errors: [{
                    id: anyErrorId
                }]
            });
    });

    it('Can edit a webhook', async function () {
        await agent.put(`/webhooks/${createdWebhookId}/`)
            .body({
                webhooks: [{
                    name: 'Edit Test',
                    event: 'member.added',
                    target_url: 'https://example.com/new-member',
                    integration_id: 'ignore_me'
                }]
            })
            .expectStatus(200)
            .matchHeaderSnapshot({
                etag: anyEtag,
                'content-version': anyContentVersion,
                'content-length': anyContentLength
            })
            .matchBodySnapshot({
                webhooks: [webhookMatcher]
            });
    });

    it('Cannot edit a non-existent webhook', async function () {
        await agent.put('/webhooks/abcd1234abcd1234abcd1234/')
            .body({
                webhooks: [{
                    name: 'Edit Test',
                    event: 'member.added',
                    target_url: 'https://example.com/new-member',
                    integration_id: 'ignore_me'
                }]
            })
            .expectStatus(404)
            .matchBodySnapshot({
                errors: [{
                    id: anyErrorId
                }]
            })
            .matchHeaderSnapshot({
                'content-version': anyContentVersion,
                etag: anyEtag
            });
    });

    it('Can delete a webhook', async function () {
        await agent
            .delete(`/webhooks/${createdWebhookId}/`)
            .expectStatus(204)
            .expectEmptyBody()
            .matchHeaderSnapshot({
                'content-version': anyContentVersion,
                etag: anyEtag
            });
    });

    it('Cannot delete a non-existent webhook', async function () {
        await agent
            .delete('/webhooks/abcd1234abcd1234abcd1234/')
            .expectStatus(404)
            .matchBodySnapshot({
                errors: [{
                    id: anyErrorId
                }]
            })
            .matchHeaderSnapshot({
                'content-version': anyContentVersion,
                etag: anyEtag
            });
    });
});
