import {
    equalTimePresetValues,
    getActiveAndOverdueMindrs
} from '../../core-utils.mjs.js';
import { createLogger } from '../../logger.mjs.js';
import {
    ACTION__CONNECTION_CLOSE,
    ACTION__CONNECTION_OPEN,
    ACTION__DIALOG_CLOSE,
    ACTION__DIALOG_OPEN,
    ACTION__HEARTBEAT,
    ACTION__LOCK_MINDR_FOR_EXECUTION,
    ACTION__MINDR_CREATE_OR_UPDATE,
    ACTION__MINDR_CREATE_OR_UPDATE_DRAFT,
    ACTION__MINDR_REMOVE,
    ACTION__MINDR_REMOVE_DRAFT,
    ACTION__PRESET_TIMESPAN_CREATE,
    ACTION__PRESET_TIMESPAN_REMOVE,
    ACTION__PRESET_TIMESPAN_UPDATE,
    ACTION__SETTINGS_UPDATE,
    ACTION__UNLOCK_MINDR
} from '../actions/actionTypes.mjs.js';
import { selectOpenConnections } from '../selectors/index.mjs.js';
import { createOrUpdateDraftReducer } from './createOrUpdateDraft.mjs.js';
import { createOrUpdateMindrReducer } from './createOrUpdateMindr.mjs.js';
import { removeMindrReducer } from './removeMindr.mjs.js';

const logger = createLogger('modules/store/reducers/root');

const rootReducer = (/** @type {MailmindrState} */ state, action) => {
    const { type, payload } = action;
    switch (type) {
        case ACTION__HEARTBEAT:
            const { mindrs: mindrList } = state;

            const { mindrs, overdue, active } = getActiveAndOverdueMindrs(
                mindrList
            );

            // 
            // 
            // 

            return { ...state, mindrs, active, overdue };
        case ACTION__CONNECTION_OPEN: {
            const { port } = payload;
            const openConnections = [...selectOpenConnections(state), port];

            logger.log(
                `open connections: ${openConnections.length}`,
                openConnections
            );

            return { ...state, openConnections };
        }
        case ACTION__CONNECTION_CLOSE: {
            const { port } = payload;
            const { name } = port;
            const { openConnections: connections } = state;

            const openConnections = connections.filter(
                connection => connection.name !== name
            );

            return { ...state, openConnections };
        }
        case ACTION__MINDR_CREATE_OR_UPDATE_DRAFT:
            return createOrUpdateDraftReducer(state, action);
        case ACTION__MINDR_CREATE_OR_UPDATE:
            return createOrUpdateMindrReducer(state, action);
        case ACTION__MINDR_REMOVE:
            return removeMindrReducer(state, action);
        case ACTION__MINDR_REMOVE_DRAFT: {
            const { /** @type {MindrDraft}*/ draft } = payload;
            const localState = {
                ...state,
                __drafts: state.__drafts.filter(
                    item =>
                        item.sender.id !== draft.sender.id &&
                        item.sender.windowId !== draft.sender.windowId
                )
            };
            return localState;
        }
        case ACTION__LOCK_MINDR_FOR_EXECUTION: {
            // 
            // 
            const { guid } = payload;

            const localState = {
                ...state,
                __inExecution: [...state.__inExecution, guid]
            };

            return localState;
        }
        case ACTION__UNLOCK_MINDR: {
            // 
            const { guid } = payload;

            const localState = {
                ...state,
                __inExecution: state.__inExecution.filter(item => item !== guid)
            };

            return localState;
        }
        case ACTION__SETTINGS_UPDATE: {
            const { name, value } = payload;

            const localState = {
                ...state,
                settings: { ...state.settings, [name]: value }
            };

            return localState;
        }
        case ACTION__PRESET_TIMESPAN_CREATE: {
            const { presets } = state;
            const { time } = presets;
            const { current } = payload;

            const localState = {
                ...state,
                presets: {
                    ...presets,
                    time: [...time, current]
                }
            };

            return localState;
        }
        case ACTION__PRESET_TIMESPAN_UPDATE: {
            const { presets } = state;
            const { time: timePresets } = presets;
            const { current, source } = payload;

            const time = timePresets.map(item =>
                equalTimePresetValues(item, source) ? current : item
            );

            logger.info(`new presets:`, time);

            const newState = {
                ...state,
                presets: {
                    ...presets,
                    time
                }
            };

            return newState;
        }
        case ACTION__PRESET_TIMESPAN_REMOVE: {
            const { presets } = state;
            const { time: timePresets } = presets;
            const { presets: toBeRemoved = [] } = payload;

            let time = [...timePresets];
            toBeRemoved.forEach(toBeRemovedPreset => {
                time = time.filter(
                    preset => !equalTimePresetValues(preset, toBeRemovedPreset)
                );
            });

            const newState = {
                ...state,
                presets: {
                    ...presets,
                    time
                }
            };

            return newState;
        }
        case ACTION__DIALOG_OPEN: {
            const newDialogDetails = payload;
            const openDialogs = [...state.openDialogs, newDialogDetails];

            return { ...state, openDialogs };
        }
        case ACTION__DIALOG_CLOSE: {
            const { dialogId } = payload;
            const { openDialogs: dialogs } = state;
            const dialogDetails = dialogs.find(
                dialogInfo => dialogId === dialogInfo.dialogId
            );

            if (dialogDetails) {
                const openDialogs = dialogs.filter(
                    openDialog => openDialog.dialogId !== dialogId
                );
                logger.info(`remaining open dialogs: ${openDialogs.length}`);
                return {
                    ...state,
                    openDialogs
                };
            } else {
                logger.warn(
                    `cannot find details for open dialog ID: '${dialogId}'`,
                    {
                        payload,
                        dialogId,
                        openDialogs: dialogs
                    }
                );
            }

            return state;
        }
        default:
            return state;
    }
};

export default rootReducer;
