<!--
  - Copyright (c) 2022.
  - Author Peter Placzek (tada5hi)
  - For the full copyright and license information,
  - view the LICENSE file that was distributed with this source code.
  -->

<script>
import ChatMessage from "../message/ChatMessage";

import ChatRoomForm from "./ChatRoomForm";
import ChatMessages from "@/components/chat/message/ChatMessages";
import ChatConnectionStatus from "@/components/chat/connection/ChatConnectionStatus";
import ChatConnection from "@/components/chat/connection/ChatConnection";
import ChatEncryptionStatus from "@/components/security/EncryptionStatus";
import ChatEncryption from "@/components/contact/ContactItemEncryption";

import {getters} from '@/modules/security/store';
import {ChatRoomType} from "@/domains/chat-room/utils";
import {getRoomMembers} from "@/domains/chat-room/api";
import {
    createAndShareRoomKeyToContacts, getChatRoomKey,
    searchAndShareChatRoomKeyRequest,
    useChatRoomKeyStorage
} from "@/domains/chat-room/encryption";

export default {
    components: {
        ChatEncryption,
        ChatEncryptionStatus, ChatConnection, ChatConnectionStatus, ChatMessages, ChatRoomForm, ChatMessage},
    props: {
        room: {
            type: Object
        }
    },
    computed: {
        onlineUsers() {
            return this.$store.getters["chat/roomMembersOnline"](this.room.id)
        },
        encryptionActivated() {
            return !!this.room.encryption;
        },
        encryptionEnabled() {
            if(!!this.room.contactId) {
                return getters.isContactEncrypted(this.room.contactId);
            } else {
                return getters.isRoomEncrypted(this.room.id);
            }
        },

        userId() {
            return this.$store.getters['auth/userId'];
        },

        isContactType() {
            return this.room.type === ChatRoomType.PRIVATE;
        },
        isGroupType() {
            return this.room.type === ChatRoomType.GROUP;
        },
        isChannelType() {
            return this.room.type === ChatRoomType.CHANNEL;
        },

        selfMember() {
            return typeof this.room.members !== 'undefined' ? this.room.members.filter(member => member.userId === this.userId)[0] : undefined;
        },
        relatedMember() {
            return this.room.members.filter(member => member.userId !== this.userId)[0];
        },
        name() {
            if(this.isChannelType || this.isGroupType) {
                return this.room.name;
            }

            const member = this.relatedMember;

            if(typeof member === 'undefined') {
                return 'Unbekannter Kontakt';
            }

            return member.user.name;
        },
    },
    data() {
        return {
            message: false,

            socketStatus: {
                busy: false,
                connecting: false,
                disconnecting: false,
                connected: false,
                error: undefined
            },

            messageEditContent: '',
            messageEditId: undefined
        }
    },
    created() {
        this.$chat.socket.onAny(this.socketHandler);
    },
    beforeDestroy() {
        this.disconnect().then(r => r);
        this.$chat.socket.offAny(this.socketHandler);
    },
    mounted() {
        this.connect().then(this.initEncryption);
    },
    methods: {
        async getMemberByUserId(userId) {
            if(this.selfMember) return;

            const {data: members} = await getRoomMembers(this.room.id, {page: {limit: 1}, filter: {userId}});

            if(members.length !== 1) {
                return undefined;
            }

            return members[0];
        },
        async initEncryption() {
            if(this.room.type !== ChatRoomType.GROUP || !this.room.encryption) return;

            const roomKeyStorage = await getChatRoomKey(this.room.id);
            if(typeof roomKeyStorage === 'undefined') {
                const member = await this.getMemberByUserId(this.userId)

                if(typeof member === 'undefined') {
                    return;
                }

                if(member.creator) {
                    await createAndShareRoomKeyToContacts(this.room.id);
                } else {
                    await searchAndShareChatRoomKeyRequest(this.room.id);
                }
            }
        },
        //------------------------------------------------------------------
        // Form Events
        //------------------------------------------------------------------

        handleMessageEditCommand(message) {
            if(typeof message === 'undefined') {
                this.messageEditId = undefined;
                this.messageEditContent = '';
            } else {
                this.messageEditId = message.id;
                this.messageEditContent = message.content;
            }
        },


        handleFormErrorMessage(message) {
            this.$bvToast.toast(message, {
                variant: 'warning'
            })
        },

        handleFormEditCancelCommand() {
            this.messageEditId = undefined;
        },
        handleFormCreatedEvent(message) {
            this.$refs['chatMessages'].push(message);
        },
        handleFormUpdatedEvent(message) {
            this.messageEditId = undefined;
            this.messageEditContent = '';

            this.$refs['chatMessages'].replace(message);
        },

        //------------------------------------------------------------------
        // Socket - Initialisation + Event/Action handling
        //------------------------------------------------------------------

        async disconnect() {
            try {
                this.socketStatus.disconnecting = true;
                this.socketStatus.connected = false;
                this.socketStatus.error = undefined;

                try {
                    await this.$chat.leaveRoom(this.room.id);

                    this.socketStatus.connected = false;
                }  catch (e) {
                    this.socketStatus.error = e.message;
                }

                this.socketStatus.disconnecting = false;
            } catch (e) {
                this.socketStatus.error = e.message;
            }
        },

        async connect() {
            try {
                this.socketStatus.connecting = true;
                this.socketStatus.connected = false;
                this.socketStatus.error = undefined;

                try {
                    await this.$chat.joinRoom({
                        id: this.room.id,
                        contactId: this.room.contactId
                    });

                    this.socketStatus.connected = true;

                }  catch (e) {
                    this.socketStatus.error = e.message;
                }

                this.socketStatus.connecting = false;
            } catch (e) {
                this.socketStatus.error = e.message;
            }
        },

        socketHandler(event, data) {
            switch (event) {
                case 'connectionClose':
                    this.handleSocketConnectionCloseEvent(data);
                    break;
                case 'reconnect':
                    this.handleSocketReconnectEvent();
                    break;
            }
        },

        handleSocketConnectionCloseEvent(data) {
            if(data.id !== this.room.id) return;

            this.socketStatus.connected = false;
            this.socketStatus.connecting = false;
            this.socketStatus.disconnecting = false;
        },
        handleSocketReconnectEvent() {
            this.socketStatus.connected = true;
            this.socketStatus.error = undefined;
            this.socketStatus.connecting = false;
            this.socketStatus.disconnecting = false;
        },

        //------------------------------------------------------------------

        handleSocketStatusUpdated(socketStatus) {
            this.socketStatus = socketStatus;
        },

        //----------------------------------------------------

        showConnectionModal() {
            this.$refs['connectionModal'].show();
        }
    }
}
</script>
<template>
    <div class="chat-room">
        <div class="room-title d-flex flex-row flex-nowrap mb-1">
            <div class="flex">
                <h4 class="d-inline">
                    {{name}}
                </h4>
            </div>

            <div class="flex ml-auto">
                <chat-connection-status
                    :socketStatus="socketStatus"
                    @updated="handleSocketStatusUpdated"
                    @clicked="showConnectionModal"
                />
                <chat-encryption-status
                    v-if="encryptionActivated"
                    :encrypted="encryptionEnabled"
                    :only-icon="true"
                />
                <button class="btn btn-xs btn-dark">
                    {{onlineUsers.length}} <i class="fa fa-users"></i>
                </button>
                <button class="btn btn-dark btn-xs">
                    <i class="fa fa-cogs"></i>
                </button>
            </div>
        </div>

        <div v-if="message" class="alert alert-sm" :class="{'alert-info': !message.isError, 'alert-warning': message.isError}">
            {{ message.data }}
        </div>

        <div class="message-box">
            <chat-messages
                v-if="socketStatus.connected"
                ref="chatMessages"
                :room="room"
                @edit="handleMessageEditCommand"
            />
        </div>

        <div v-if="socketStatus.error" class="alert alert alert-warning">
            {{ socketStatus.error }}
        </div>

        <div class="mt-2">
            <chat-room-form
                :room-connected="socketStatus.connected"
                :room="room"
                :message-edit-id="messageEditId"
                :message-edit-content="messageEditContent"
                @error="handleFormErrorMessage"
                @added="handleFormCreatedEvent"
                @edited="handleFormUpdatedEvent"
                @editCancel="handleFormEditCancelCommand"
            />
        </div>

        <b-modal
            size="lg"
            ref="connectionModal"
            button-size="sm"
            title-html="<i class='fas fa-sync'></i> Verbindung"
            :no-close-on-backdrop="true"
            :no-close-on-esc="true"
            :cancel-title="'Abbrechen'"
            :cancel-disabled="true"
        >
            <chat-connection ref="connection" :room="room" :socket-status-property="socketStatus" @updated="handleSocketStatusUpdated"/>
        </b-modal>
    </div>
</template>
<style>
.chat-room {
    display: flex;
    flex: 1;
    flex-direction: column;
    height: 100%;
}

.message-box {
    /*
    height: -moz-calc(100% - (34px + 34px));
    height: -webkit-calc(100% - (34px + 34px));
    height: calc(100% - (34px + 34px));
     */

    height: calc(100% - (35px + 35px));
}

@media (max-width: 768px) {
    .message-box {
        height: calc(100% - (35px + 35px + 30px));
    }
}
</style>
