import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

/**
 * Exports a new Vuex store. Responsible for API access and maintaining a cache
 * of requested and pushed Websocket data.
 **/
export default new Vuex.Store({
    state: {
        ws_connected: false,
        notifications: [],
        scan_cache: {}
    },
    actions: {
        /**
         * Queries the API for all scans for the given target, then commits the
         * result to the store.
         **/
        getScansByTarget({ commit }, target){
            return fetch('/api/v1/scans/' + target)
                .then(resp => resp.json())
                .then(json => {
                    commit("SET_TARGET_SCANS", { target, data: json.data });
                });
        },
        /**
         * Requests a scan from the API. On response, commits the new scan to
         * the store.
         **/
        performScan({ commit }, target) {
            return fetch('/api/v1/scans', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify({ "target": target })
            }).then(async resp => {
                let scan = await resp.json()
                commit("UPDATE_SCAN", { scan });
                return scan;
            });
        }
    },
    mutations: {
        /**
         * Sets the state of the scan cache for a given target.
         **/
        "SET_TARGET_SCANS"(state, { target, data }) {
            Vue.set(state.scan_cache, target, data)
        },
        /**
         * Upserts a scan in the scan cache store.
         **/
        "UPDATE_SCAN"(state, { scan }) {
            let target = scan.target;
            if (!state.scan_cache[target]) {
                Vue.set(state.scan_cache, target, [scan])
            } else {
                let matchedItem = state.scan_cache[target]
                    .find(item => item.id == scan.id);

                if (matchedItem)
                    Object.keys(scan).forEach(key => {
                        Vue.set(matchedItem, key, scan[key])
                    });
                else
                    state.scan_cache[target].unshift(scan);
            }
        },
        /**
         * Listens to all 'message' Websocket events for scan progress data
         * in order to update the scan cache and notification queue.
         **/
        "SOCKET_message"(state, scan) {
            // Update progress queue
            let matchedItem = state.notifications.find(item => item.id == scan.id);
            if (matchedItem)
                Object.keys(scan).forEach(key => {
                    Vue.set(matchedItem, key, scan[key])
                });
            else
                state.notifications.push(scan);

            // Update scan cache
            this.commit("UPDATE_SCAN", { scan });
        },
        /**
         * Listens for Websocket connect events. This is used for the green /
         * red 'O' in the Overseer logo. Green = connected, Red = disconnected.
         **/
        "SOCKET_connect"(state) {
            state.ws_connected = true
        },
        /**
         * Listens for Websocket connect events. This is used for the green /
         * red 'O' in the Overseer logo. Green = connected, Red = disconnected.
         **/
        "SOCKET_disconnect"(state) {
            state.ws_connected = false
        },
    },
})
