import { Component } from '../../../lib/vues6/vues6.js'
import { session } from '../../service/Session.service.js'
import { password_service } from '../../service/Password.service.js'
import { auth_api } from '../../service/AuthApi.service.js'
import { location_service } from '../../service/Location.service.js'
import { message_service } from '../../service/Message.service.js'
import { utility } from '../../service/Utility.service.js'
import { profile_service } from '../../service/Profile.service.js'

const template = `
<div class="coreid-profile-container mb-5 offset-0 col-md-8 offset-md-2 col-xl-6 offset-xl-3">
    <div class="card">
        <div class="card-body">
            <div class="row">
                <div class="col-8 offset-2 col-sm-4 offset-sm-0">
                    <img src="/api/v1/profile/me/photo" :alt="t['profile.profile_photo']" ref="photo" class="img-fluid">
                    <div class="overlay">
                        <button class="btn btn-outline-light" @click="on_profile_change_click">{{ t['common.change'] }}</button>
                    </div>
                </div>
                <div class="col-sm-8 offset-sm-0 col-12 text-sm-left text-center pad-top">
                    <div class="card-title"><h3>{{ profile_first }} {{ profile_last }}</h3></div>
                    <div class="card-subtitle mb-2 text-muted">{{ profile_tagline }}</div>
                </div>
            </div>
        </div>
        <ul class="list-group list-group-flush">
            <li class="list-group-item">
                <h4>{{ t['profile.basic_profile'] }}</h4>
                <div class="row">
                    <div class="col-12 col-md-6 form-group">
                        <label for="coreid-profile-first-input">{{ t['register.first_name'] }}</label>
                        <input
                            type="text"
                            class="form-control"
                            id="coreid-profile-first-input"
                            :placeholder="t['profile.placeholder_first']"
                            v-model="profile_first"
                            @keyup="on_key_up($event)"
                        >
                    </div>
                    <div class="col-12 col-md-6 form-group">
                        <label for="coreid-profile-last-input">{{ t['register.last_name'] }}</label>
                        <input
                            type="text"
                            class="form-control"
                            id="coreid-profile-last-input"
                            :placeholder="t['profile.placeholder_last']"
                            v-model="profile_last"
                            @keyup="on_key_up($event)"
                        >
                    </div>
                </div>
                <div class="row">
                    <div class="col-12 form-group">
                        <label for="coreid-profile-email-input">{{ t['register.email'] }}</label>
                        <input
                            type="email"
                            class="form-control"
                            id="coreid-profile-email-input"
                            :placeholder="t['profile.placeholder_email'] "
                            v-model="profile_email"
                            ref="email_input"
                            @keyup="on_key_up($event)"
                        >
                    </div>
                </div>
                <div class="row">
                    <div class="col-12 form-group">
                        <label for="coreid-profile-tag-input">{{ t['profile.tagline'] }}</label>
                        <input
                            type="text"
                            class="form-control"
                            id="coreid-profile-tag-input"
                            v-model="profile_tagline"
                            @keyup="on_key_up($event)"
                        >
                    </div>
                </div>
                <div class="row">
                    <h4 style="margin-left: 15px">{{ t['profile.advanced_header'] }}</h4>
                    <div class="col-12 form-group">
                        <label for="coreid-profile-shell-input">{{ t['profile.advanced_shell'] }}</label>
                        <input
                            type="text"
                            class="form-control"
                            id="coreid-profile-shell-input"
                            v-model="profile_shell"
                            @keyup="on_key_up($event)"
                            placeholder="/bin/bash"
                        >
                    </div>
                </div>
            </li>
            <li class="list-group-item text-right font-italic text-muted">
                {{ form_message }}
            </li>
            <li class="list-group-item" v-if="!user_id || user_id === 'me'">
                <h4>{{ t['password.password'] }}</h4>
                <p class="font-italic" v-if="last_reset">{{ t['profile.pw_last_reset'].replace('LAST_RESET', last_reset) }}</p>
                <button
                    type="button"
                    class="btn btn-primary btn-sm"
                    @click="change_password"
                >{{ t['password.change'] }}</button>
            </li>
            <li class="list-group-item" v-if="ready && !has_mfa && (!user_id || user_id === 'me')">
                <h4>{{ t['mfa.mfa'] }}</h4>
                <p>{{ t['profile.mfa_1'].replace(/APP_NAME/g, app_name) }}</p>
                <p>{{ t['profile.mfa_2'].replace(/APP_NAME/g, app_name) }}</p>
                <button class="btn btn-success btn-sm" type="button" @click="enable_mfa">{{ t['mfa.enable'] }}</button>
            </li>
            <li class="list-group-item" v-if="has_mfa && (!user_id || user_id === 'me')">
                <h4>{{ t['mfa.mfa'] }}</h4>
                <p class="font-italic">{{ t['profile.mfa_enabled_on'].replace('MFA_ENABLED', mfa_enable_date) }}</p>
                <button
                    class="btn btn-danger btn-sm"
                    type="button"
                    @click="disable_mfa"
                >{{ t['mfa.disable'] }}</button>
                
                <h6 class="pad-top">{{ t['profile.app_pws'] }}</h6>
                <p>{{ t['profile.app_pw_1'].replace('APP_NAME', app_name) }}</p>
                <p>{{ t['profile.app_pw_2'] }}</p>
                <p>{{ t['profile.app_pw_3'] }}</p>
                
                <p class="font-italic text-muted" v-if="app_passwords.length > 0">{{ t['profile.app_pw_remaining.'+(app_passwords.length === 1 ? 'one' : 'many')].replace('NUM_PWS', app_passwords.length) }}</p>
                <ul class="list-group mb-4" v-if="app_passwords.length > 0">
                    <li class="list-group-item" v-for="pw of app_passwords">
                        <div class="row">
                            <div class="col-9">
                                {{ pw.name }}
                                <br><span class="text-muted font-italic">{{ t['profile.issued'] }} {{ pw.created }}</span>
                            </div>
                            <div class="col-3 my-auto">
                                <button
                                    class="btn btn-sm btn-danger"
                                    type="button"
                                    @click="deactivate_app_password($event, pw)"
                                >{{ t['common.deactivate'] }}</button>
                            </div>
                        </div>
                    </li>
                </ul>
                
                <button class="btn btn-sm btn-primary" @click="on_click_generate_app_password">{{ t['profile.gen_new'] }}</button>
                
                <h6 class="pad-top">{{ t['profile.recovery_codes'] }}</h6>
                <p>{{ t['profile.recovery_1'] }}</p>
                <span v-if="!has_mfa_recovery">
                    <p class="font-italic">{{ t['profile.no_recovery'] }}</p>
                    <button class="btn btn-sm btn-success" @click="on_mfa_recovery_generate">{{ t['profile.generate_recovery'] }}</button>
                </span>
                <span v-if="has_mfa_recovery">
                    <p class="font-italic">{{ t['profile.recovery_gen_on'].replace('MFA_RECOVERY', mfa_recovery_date) }} {{ t['profile.codes_remaining.'+(mfa_recovery_codes === 1 ? 'one' : 'many')].replace('NUM_CODES', mfa_recovery_codes) }}</p>
                    <button class="btn btn-sm btn-success" @click="on_mfa_recovery_generate">{{ t['profile.regenerate_recovery'] }}</button>
                </span>
            </li>
            <li class="list-group-item" v-if="notify_loaded">
                <h4>{{ t['profile.notifications'] }}</h4>
                <p v-html="t['profile.notify_explainer_1'].replace(/APP_NAME/g, app_name)"></p>
                <p>{{ t['profile.notify_explainer_2'].replace(/APP_NAME/g, app_name) }}</p>
                <div class="row">
                    <div class="col-12 form-group">
                        <input
                            type="text"
                            class="form-control"
                            :placeholder="t['profile.example_gateway_url']"
                            id="coreid-profile-notify-gateway-url"
                            v-model="notify_gateway_url"
                        >
                    </div>
                    <div class="col-12 form-group">
                        <input
                            type="text"
                            class="form-control"
                            :placeholder="t['profile.app_key']"
                            id="coreid-profile-notify-app-key"
                            v-model="notify_app_key"
                        >
                    </div>
                    <div class="col-12 mt-2">
                        <button class="btn btn-sm btn-primary" @click="on_notifications_save">{{ t['profile.save_notify'] }}</button>
                        <button
                            class="btn btn-sm btn-secondary"
                            v-if="notify_app_key && notify_gateway_url && notify_enabled"
                            @click="send_test_notification"
                        >{{ t['profile.test_notify'] }}</button>
                    </div>
                </div>
            </li>
        </ul>
    </div>
    <coreid-form-app-password
        v-if="!user_id || user_id === 'me'"
        ref="app_password_modal"
        @modal-success="load_app_passwords"
    ></coreid-form-app-password>
    <coreid-profile-photo-uploader
        ref="profile_photo_uploader"
        :user-id="user_id"
        @upload="on_profile_photo_upload"
    ></coreid-profile-photo-uploader>
</div>
`

export default class EditProfileComponent extends Component {
    static get selector() { return 'coreid-profile-edit' }
    static get template() { return template }
    static get props() { return ['user_id'] }

    constructor() {
        super()

        this.profile_first = ''
        this.profile_last = ''
        this.profile_email = ''
        this.profile_tagline = ''
        this.profile_shell = ''
        this.last_reset = ''
        this.mfa_enable_date = ''

        this.has_mfa_recovery = false
        this.mfa_recovery_date = ''
        this.mfa_recovery_codes = 0

        this.form_message = 'No changes.'

        this.has_mfa = false
        this.ready = false

        this.notify_gateway_url = ''
        this.notify_app_key = ''
        this.notify_enabled = false
        this.notify_created_on = ''
        this.notify_loaded = false

        this.app_passwords = []
        this.app_name = ''
        this.t = {}
    }

    on_key_up = ($event) => {}

    async vue_on_create() {
        this.t = await T(
            'profile.profile_photo',
            'common.change',
            'profile.basic_profile',
            'register.first_name',
            'profile.placeholder_first',
            'register.last_name',
            'profile.placeholder_last',
            'register.email',
            'profile.placeholder_email',
            'profile.tagline',
            'password.password',
            'password.change',
            'profile.pw_last_reset',
            'mfa.mfa',
            'profile.mfa_enabled_on',
            'mfa.disable',
            'profile.app_pws',
            'profile.issued',
            'common.deactivate',
            'profile.app_pw_remaining.one',
            'profile.app_pw_remaining.many',
            'profile.gen_new',
            'profile.recovery_codes',
            'profile.recovery_1',
            'profile.no_recovery',
            'profile.generate_recovery',
            'profile.recovery_gen_on',
            'profile.codes_remaining.one',
            'profile.codes_remaining.many',
            'profile.regenerate_recovery',
            'profile.app_pw_1',
            'profile.app_pw_2',
            'profile.app_pw_3',
            'profile.mfa_1',
            'profile.mfa_2',
            'mfa.enable',
            'profile.notifications',
            'profile.notify_explainer_1',
            'profile.notify_explainer_2',
            'profile.app_key',
            'profile.example_gateway_url',
            'profile.save_notify',
            'profile.test_notify',
            'profile.advanced_header',
            'profile.advanced_shell'
        )

        this.app_name = session.get('app.name')
        this.load().then(() => {
            this.ready = true
        })

        const save = utility.debounce(this.save_form.bind(this))
        this.on_key_up = () => {
            this.form_message = 'Saving...'
            save()
        }
    }

    get_submit_data() {
        return {
            first_name: this.profile_first,
            last_name: this.profile_last,
            email: this.profile_email,
            tagline: this.profile_tagline,
            login_shell: this.profile_shell,
            user_id: this.user_id || 'me',
        }
    }

    on_profile_change_click() {
        this.$refs.profile_photo_uploader.show()
    }

    async on_profile_photo_upload() {
        this.$refs.profile_photo_uploader.close()
        let src = this.$refs.photo.src
        if ( src.indexOf('?') > 0 ) src = src.split('?')[0]
        this.$refs.photo.src = `${src}?i=${(new Date).getTime()}`
    }

    valid_email() {
        return this.$refs.email_input.validity.valid
    }

    async save_form($event) {
        const submit_data = this.get_submit_data()
        try {
            if ( !this.valid_email() ) {
                this.form_message = 'Invalid e-mail address.'
            } else {
                await profile_service.update_profile(submit_data)
                this.form_message = 'All changes saved.'
            }
        } catch(e) {
            this.form_message = 'Unknown error occurred while saving.'
        }
    }

    populate_from_session() {
        this.profile_first = session.get('user.first_name')
        this.profile_last = session.get('user.last_name')
        this.profile_email = session.get('user.email')
        this.profile_tagline = session.get('user.tagline')
    }

    async load() {
        const result = await profile_service.get_profile(this.user_id || 'me')
        if ( !result ) throw new Error('Unable to load profile!')

        this.profile_first = result.first_name
        this.profile_last = result.last_name
        this.profile_email = result.email
        this.profile_tagline = result.tagline
        this.profile_shell = result.login_shell

        const notify_config = await profile_service.get_notify(this.user_id || 'me')
        if ( !notify_config || !notify_config.has_config ) {
            this.notify_app_key = ''
            this.notify_enabled = false
            this.notify_created_on = ''
            this.notify_gateway_url = ''
        } else if ( notify_config && notify_config.has_config ) {
            this.notify_app_key = notify_config.config.application_key
            this.notify_enabled = notify_config.config.active
            this.notify_created_on = notify_config.config.created_on
            this.notify_gateway_url = notify_config.config.gateway_url
        }
        this.notify_loaded = true

        if ( !this.user_id || this.user_id === 'me' ) {
            const reset = (await password_service.get_resets()).reverse()[0]
            if (reset && reset.reset_on) {
                this.last_reset = (new Date(reset.reset_on)).toLocaleDateString()
            }

            const mfa = await auth_api.has_mfa()
            this.has_mfa = mfa && mfa.mfa_enabled
            if (this.has_mfa) {
                this.mfa_enable_date = (new Date(mfa.mfa_enable_date)).toLocaleDateString()

                const result = await auth_api.has_mfa_recovery()
                if ( result && result.has_recovery ) {
                    this.has_mfa_recovery = true
                    this.mfa_recovery_date = (new Date(result.generated)).toLocaleDateString()
                    this.mfa_recovery_codes = result.remaining_codes
                }
            }

            await this.load_app_passwords()
        }
    }

    async load_app_passwords() {
        let app_pws = await auth_api.app_passwords()
        if ( !Array.isArray(app_pws) ) app_pws = []
        this.app_passwords = app_pws.map(x => {
            if ( x.expires ) x.expires = (new Date(x.expires)).toLocaleDateString()
            if ( x.created ) x.created = (new Date(x.created)).toLocaleDateString()
            return x
        })
    }

    disable_mfa() {
        location_service.redirect('/auth/mfa/disable')
    }

    enable_mfa() {
        location_service.redirect('/auth/mfa/setup')
    }

    change_password() {
        location_service.redirect('/password/reset')
    }

    on_click_generate_app_password() {
        this.$refs.app_password_modal.trigger()
    }

    async deactivate_app_password($event, pw) {
        message_service.modal({
            title: 'Deactivate app password?',
            message: `You are about to deactivate the app password for ${pw.name}. If you do this, ${pw.name} will no longer be able to sign-in on your behalf. Continue?`,
            buttons: [
                {
                    text: 'Cancel',
                    type: 'close',
                },
                {
                    text: 'Deactivate',
                    type: 'close',
                    class: ['btn', 'btn-danger'],
                    on_click: async () => {
                        await auth_api.delete_app_password(pw.uuid)
                        await this.load_app_passwords()
                    },
                },
            ],
        })
    }

    async on_mfa_recovery_generate($event) {
        if ( !this.has_mfa ) return
        if ( !this.has_mfa_recovery ) {
            await this.generate_mfa_recovery()
        } else {
            message_service.modal({
                title: 'Are you sure?',
                message: 'There are already MFA recovery codes associated with your account. If you re-generate them, you will be unable to use the old ones. Continue?',
                buttons: [
                    {
                        text: 'Cancel',
                        type: 'close',
                    },
                    {
                        text: 'Re-generate',
                        type: 'close',
                        class: ['btn', 'btn-warning'],
                        on_click: async () => {
                            await this.generate_mfa_recovery()
                        },
                    },
                ],
            })
        }
    }

    async generate_mfa_recovery() {
        const codes = await auth_api.generate_mfa_recovery()
        if ( codes ) {
            this.display_mfa_recovery_modal(codes)
        } else {
            message_service.alert({
                type: 'error',
                message: 'An unknown error occurred while attempting to generate MFA recovery codes.'
            })
        }

        await this.load()
    }

    display_mfa_recovery_modal(codes) {
        const code_display = codes.map(x => `<li><code>${x}</code></li>`).join('\n')
        message_service.modal({
            title: 'MFA Recovery Codes',
            message: `We've generated recovery codes for your account. You can use these to recover access to your account in the event that you lose your MFA device.
            <br><br>
            Be sure to put these somewhere safe. After you close this modal, they will disappear:
            <br><br>
            <ul>
                ${code_display}
            </ul>`,
            buttons: [
                {
                    text: 'Close',
                    type: 'close',
                },
            ],
        })
    }

    async on_notifications_save() {
        const data = {
            user_id: this.user_id || 'me',
            app_key: this.notify_app_key,
            gateway_url: this.notify_gateway_url,
        }

        await profile_service.update_notify(data)
        await this.load()
    }

    async send_test_notification() {
        await profile_service.test_notify({ user_id: this.user_id || 'me' })
    }
}

