import supertest from "supertest";

import User from "../src/auth/models/User.js";
import UserEmail from "../src/auth/models/UserEmail.js";
import UserPasswordComponent from "../src/auth/password/UserPasswordComponent.js";
import useApp from "./_app.js";
import {authAppProvider, followMagicLinkFromMail, testLogout} from "./_authentication_common.js";
import {popEmail} from "./_mail_server.js";

const app = useApp(authAppProvider(false));

let agent: supertest.SuperTest<supertest.Test>;

beforeAll(() => {
    agent = supertest(app().getExpressApp());
});

test('Approval Mode', () => {
    expect(User.isApprovalMode()).toStrictEqual(false);
});

describe('Register with username and password (password)', () => {
    test('Must be disabled', async () => {
        const res = await agent.get('/csrf').expect(200);
        const cookies = res.get('Set-Cookie');
        const csrf = res.text;

        // Register user
        await agent.post('/auth/register')
            .set('Cookie', cookies)
            .send({
                csrf: csrf,
                auth_method: 'password',
                identifier: 'entrapta',
                password: 'darla_is_cute',
                password_confirmation: 'darla_is_cute',
                terms: 'on',
            })
            .expect(500);
    });
});

describe('Register with email (magic_link)', () => {
    test('General case', async () => {
        const res = await agent.get('/csrf').expect(200);
        const cookies = res.get('Set-Cookie');
        const csrf = res.text;

        await agent.post('/auth/register')
            .set('Cookie', cookies)
            .send({
                csrf: csrf,
                auth_method: 'magic_link',
                identifier: 'glimmer@example.org',
            })
            .expect(302)
            .expect('Location', '/magic/lobby');

        await followMagicLinkFromMail(agent, cookies);

        await testLogout(agent, cookies, csrf);

        // Verify saved user
        const email = await UserEmail.select()
            .with('user')
            .where('email', 'glimmer@example.org')
            .first();
        const user = email?.user.getOrFail();

        expect(user).toBeDefined();

        expect(email).toBeDefined();
        expect(email?.email).toStrictEqual('glimmer@example.org');

        await expect(user?.as(UserPasswordComponent).verifyPassword('')).resolves.toStrictEqual(false);
    });

    test('Cannot register taken email', async () => {
        const res = await agent.get('/csrf').expect(200);
        const cookies = res.get('Set-Cookie');
        const csrf = res.text;

        await agent.post('/auth/register')
            .set('Cookie', cookies)
            .send({
                csrf: csrf,
                auth_method: 'magic_link',
                identifier: 'bow@example.org',
                name: 'bow',
            })
            .expect(302)
            .expect('Location', '/magic/lobby');

        await followMagicLinkFromMail(agent, cookies);

        // Verify saved user
        const userEmail = await UserEmail.select()
            .with('user')
            .where('email', 'bow@example.org')
            .first();
        const user = userEmail?.user.getOrFail();

        expect(user).toBeDefined();

        // Attempt register with another mail but same username
        const res2 = await agent.get('/csrf').expect(200);

        await agent.post('/auth/register')
            .set('Cookie', res2.get('Set-Cookie'))
            .send({
                csrf: res2.text,
                auth_method: 'magic_link',
                identifier: 'bow@example.org',
                name: 'bow2',
            })
            .expect(400);

        expect(await popEmail()).toBeNull();
    });
});