<style>
    .twofactor #setup-2fa,
    .twofactor #disable-2fa,
    .twofactor #output-2fa {
        display: none;
    }

    .twofactor.loaded .loading-indicator {
        display: none;
    }

    .twofactor.disabled #disable-2fa,
    .twofactor.enabled #setup-2fa {
        display: none;
    }

    .twofactor.disabled #setup-2fa,
    .twofactor.enabled #disable-2fa {
        display: block;
    }

    .twofactor #qr-2fa img {
        display: block;
        width: 256px;
        max-width: 100%;
        height: auto;
    }

    .twofactor #output-2fa.visible {
        display: block;
    }
</style>

<h2>Two Factor Authentication</h2>

<div class="twofactor">
    <div class="loading-indicator">Loading...</div>

    <form id="setup-2fa">
        <div class="form-group">
            <h3>Setup</h3>
            <p>After enabling two factor authentication, any login to the admin panel will require you to enter a time-limited 6-digit number from an authenticator app after entering your normal credentials.</p>
            <p>1. Scan the QR code or enter the secret into an authenticator app (e.g. Google Authenticator)</p>
            <div id="qr-2fa"></div>
        </div>

        <div class="form-group">
            <label for="otp">2. Enter the code displayed in the Authenticator app</label>
            <input type="text" id="setup-otp" class="form-control" placeholder="6-digit code" />
        </div>

        <input type="hidden" id="setup-secret" />

        <div class="form-group">
            <button id="setup-submit" disabled type="submit" class="btn">Enable two factor authentication</button>
        </div>
    </form>

    <form id="disable-2fa">
        <div class="form-group">
            <p>Two factor authentication is active.</p>
        </div>

        <button type="submit" class="btn btn-danger">Disable two factor authentication</button>
    </form>

    <div id="output-2fa" class="panel panel-danger">
        <div class="panel-body"></div>
    </div>
</div>

<script>
    var el = {
        disableForm: document.getElementById('disable-2fa'),
        output: document.getElementById('output-2fa'),
        setupForm: document.getElementById('setup-2fa'),
        setupInputOtp: document.getElementById('setup-otp'),
        setupInputSecret: document.getElementById('setup-secret'),
        setupQr: document.getElementById('qr-2fa'),
        setupSubmit: document.querySelector('#setup-2fa button[type="submit"]'),
        wrapper: document.querySelector('.twofactor')
    }

    function update_setup_disabled(evt) {
        var val = evt.target.value.trim();

        if (
            typeof val !== 'string' ||
            typeof el.setupInputSecret.value !== 'string' ||
            val.length !== 6 ||
            el.setupInputSecret.value.length !== 32 ||
            !(/^\+?\d+$/.test(val))
        ) {
            el.setupSubmit.setAttribute('disabled', '');
        } else {
            el.setupSubmit.removeAttribute('disabled');
        }
    }

    function render_setup(res) {
        function render_qr_code(encoded) {
            var img = document.createElement('img');
            img.src = encoded;

            var code = document.createElement('div');
            code.innerHTML = `Secret: ${res.secret}`;

            el.setupQr.appendChild(img);
            el.setupQr.appendChild(code);
        }

        el.setupInputOtp.addEventListener('input', update_setup_disabled);
        el.setupForm.addEventListener('submit', do_setup);

        el.setupInputSecret.setAttribute('value', res.secret);

        render_qr_code(res.qr_code);
        el.wrapper.classList.add('disabled');
    }

    function render_disable() {
        el.disableForm.addEventListener('submit', do_disable);
        el.wrapper.classList.add('enabled');
    }

    function hide_error() {
        el.output.querySelector('.panel-body').innerHTML = '';
        el.output.classList.remove('visible');
    }

    function render_error(msg) {
        el.output.querySelector('.panel-body').innerHTML = msg;
        el.output.classList.add('visible');
    }

    function reset_view() {
        el.wrapper.classList.remove('loaded', 'disabled', 'enabled');

        el.disableForm.removeEventListener('submit', do_disable);

        hide_error();

        el.setupForm.reset();
        el.setupForm.removeEventListener('submit', do_setup);

        el.setupInputSecret.setAttribute('value', '');
        el.setupInputOtp.removeEventListener('input', update_setup_disabled);

        el.setupSubmit.setAttribute('disabled', '');
        el.setupQr.innerHTML = '';
    }

    function show_two_factor_auth() {
        reset_view();

        api(
            '/two-factor-auth/status',
            'GET',
            {},
            function(res) {
                el.wrapper.classList.add('loaded');
                var isEnabled = res.status === 'on'
                return isEnabled ? render_disable(res) : render_setup(res);
            }
        );
    }

    function do_disable(evt) {
        evt.preventDefault();
        hide_error();

        api(
            '/two-factor-auth/disable',
            'POST',
            {},
            function() { show_two_factor_auth(); }
        );

        return false;
    }

    function do_setup(evt) {
        evt.preventDefault();
        hide_error();

        api(
            '/two-factor-auth/setup',
            'POST',
            {
                token: $(el.setupInputOtp).val(),
                secret: $(el.setupInputSecret).val()
            },
            function(res) { show_two_factor_auth(); },
            function(res) {
                var errorMessage = 'Something went wrong.';
                var parsed;

                try {
                    parsed = JSON.parse(res);
                } catch (err) {
                    return render_error(errorMessage);
                }

                var error = parsed && parsed.error
                    ? parsed.error
                    : null;

                if (error === 'token_mismatch') {
                    errorMessage = 'Code does not match.';
                } else if (error === 'bad_input') {
                    errorMessage = 'Received request with malformed data.';
                }

                render_error(errorMessage);
            }
        );

        return false;
    }
</script>