// redux dependencies
import { connect } from 'react-redux'
import createReducer from 'lib/reducer';
import backendRequest from 'lib/backend';


// react component dependencies
import React, { Component } from 'react'
import { PortalLinks, PortalOption, Button } from 'lib/components';
import { defineMessages, injectIntl, FormattedDate } from 'react-intl'
import messages from './messages';

require("./notification.scss");


export const notificationKey = (objType = "objType", objId = "objId") => {
    return [objType, objId].join(":");
};


/* REDUX */
const initialState = {};
const emptyList = {
    list: {
        status: null,
        statuses: {},
        data: {}
    },
    options: {
        status: null,
        data: {}
    }
};

let _reducer = createReducer(initialState);

function registerComponent(unitId, objectType, objectId) {
    return {
        type: '@@notifications/REGISTER',
        payload: notificationKey(objectType, objectId),
        meta: {
            unitId,
            objectType,
            objectId
        }
    }
}


function unregisterComponent(unitId, objectType, objectId) {
    return {
        type: '@@notifications/UNREGISTER',
        payload: notificationKey(objectType, objectId),
        meta: {
            unitId,
            objectType,
            objectId
        }
    }
}


function fetchNotificationOptions(unitId, objectType, objectId) {
    return {
        type: '@@notifications/FETCH_OPTIONS',
        payload: backendRequest(`/api/${unitId}/notifications/${objectType}/${objectId}/services`),
        meta: {
            key: notificationKey(objectType, objectId),
            unitId,
            objectType,
            objectId
        }
    }
}



function fetchNotifications(unitId, objectType, objectId) {
    return {
        type: '@@notifications/FETCH',
        payload: backendRequest(`/api/${unitId}/notifications/${objectType}/${objectId}`),
        meta: {
            key: notificationKey(objectType, objectId),
            unitId,
            objectType,
            objectId
        }
    }
}

//TODO implement
function saveNotification(unitId, objectType, objectId, serviceId) {
    return {
        type: '@@notifications/SAVE',
        payload: backendRequest(`/api/${unitId}/notifications/${objectType}/${objectId}/${serviceId}`, "PUT"),
        meta: {
            key: notificationKey(objectType, objectId),
            unitId,
            objectType,
            objectId,
            serviceId
        }
    }
}

function deleteNotification(unitId, objectType, objectId, serviceId) {
    return {
        type: '@@notifications/DELETE',
        payload: backendRequest(`/api/${unitId}/notifications/${objectType}/${objectId}/${serviceId}`, "DELETE"),
        meta: {
            key: notificationKey(objectType, objectId),
            unitId,
            objectType,
            objectId,
            serviceId
        }
    }
}


_reducer.handleAction("@@notifications/REGISTER", (state, action) => state.updateIn([action.payload, "count"], val => isNaN(val) ? 1 : val + 1 ));
_reducer.handleAction("@@notifications/UNREGISTER", (state, action) => {
    let count = state.getIn([action.payload, "count"], 0);
    if (count < 2) {
        state = state.remove(action.payload);
    } else {
        state = state.updateIn([action.payload, "count"], val => val - 1);
    }
    return state;
} );



_reducer.handleAction("@@notifications/FETCH_PENDING", (state, action) => state.setIn([action.meta.key, "list", "status"], "pending") );
_reducer.handleAction("@@notifications/FETCH_FULFILLED", (state, action) => state.setIn([action.meta.key, "list", "status"], "success").setIn([action.meta.key, "list", "data"], action.payload.body) );
_reducer.handleAction("@@notifications/FETCH_REJECTED", (state, action) => state.setIn([action.meta.key, "list", "status"], "failure").deleteIn([action.meta.key, "list", "data"]) );


_reducer.handleAction("@@notifications/FETCH_OPTIONS_PENDING", (state, action) => state.setIn([action.meta.key, "options", "status"], "pending") );
_reducer.handleAction("@@notifications/FETCH_OPTIONS_FULFILLED", (state, action) => state.setIn([action.meta.key, "options", "status"], "success").setIn([action.meta.key, "options", "data"], action.payload.body) );
_reducer.handleAction("@@notifications/FETCH_OPTIONS_REJECTED", (state, action) => state.setIn([action.meta.key, "options", "status"], "failure").deleteIn([action.meta.key, "options", "data"]) );


function statusPath(action) {
    let path = [action.meta.key, "list", "statuses", action.meta.serviceId];
    console.warn(path);
    return path;
}

//CRUD
_reducer.handleAction("@@notifications/SAVE_PENDING", (state, action) => state.setIn(statusPath(action), "pending") );
_reducer.handleAction("@@notifications/SAVE_FULFILLED", (state, action) => state.setIn(statusPath(action), "success") );
_reducer.handleAction("@@notifications/SAVE_REJECTED", (state, action) => state.setIn(statusPath(action), "failure") );

_reducer.handleAction("@@notifications/DELETE_PENDING", (state, action) => state.setIn(statusPath(action), "pending") );
_reducer.handleAction("@@notifications/DELETE_FULFILLED", (state, action) => state.setIn(statusPath(action), "success") );
_reducer.handleAction("@@notifications/DELETE_REJECTED", (state, action) => state.setIn(statusPath(action), "failure") );



//export reducer
export const reducer = _reducer.export();


/* ******************************************* */
/* UI Components                               */
/* ******************************************* */


class Notifications extends Component {

    constructor(props) {
        super(props);

        this.renderRow = this.renderRow.bind(this);
        this.deleteRow = this.deleteRow.bind(this);
        this.renameRow = this.renameRow.bind(this);

        this.doAction = this.doAction.bind(this);

        this.state = { modal: null };
    }


    async deleteRow(id) {
        await this.props.deleteNotification(id);
        await this.props.fetchData();
    }


    async renameRow(item, name) {
        try {
            await this.props.renameNotification(item.id, name);
            this.setState({ modal: null, item: null });
        } catch (e) {
            console.error(e);
        }
        await this.props.fetchData();
    }

    componentWillReceiveProps() {
        //clearInfoMessages(this);
    }


    //TODO ensure data
    componentWillMount() {
        this.props.registerComponent();

        //refresh list?
        const { status } = this.props;
        if (status !== "pending") {
            this.props.fetchData();
            this.props.fetchNotificationOptions();
        }
    }
    

    componentWillUnmount() {
        this.props.unregisterComponent();
    }
    
    doAction(action, serviceId) {
        return async () => {
            await action(serviceId);
            await this.props.fetchData();
        }
    }

    renderRow(serviceId, data, statuses) {
        const { unitId, objectType, objectId, disabled, saveNotification, deleteNotification, imageUrls, intl } = this.props;
        
        let 
            title = (messages[`${serviceId}Title`] && intl.formatMessage(messages[`${serviceId}Title`])) || serviceId,
            description = (messages[`${serviceId}Description`] && intl.formatMessage(messages[`${serviceId}Description`])) || serviceId; 

        let button = null;
        if (data) {
            let d = data[serviceId];
            let loading = statuses && statuses[serviceId] == "pending";

            if (d && d.remoteId) {
                button = <Button loading={ loading } onPress={ this.doAction(deleteNotification, serviceId) } title={ loading ? String.fromCharCode(160) : intl.formatMessage(messages.disableButton) }/>;
            } else {
                button = <Button loading={ loading } onPress={ this.doAction(saveNotification, serviceId) } title={ loading ? String.fromCharCode(160) : intl.formatMessage(messages.enableButton) } />;
            }
        }

        let style = {
            width: "100%",
            height: "100%",
            backgroundSize: "100% 100%",
            backgroundPosition: "center center"
        };
        if (imageUrls && imageUrls[serviceId]) {
            style.backgroundImage = `url(${imageUrls[serviceId]})`;
        }

        return (
            <PortalOption 
                key={ serviceId }
                icon={ <div className="logo" style={ style }></div> }
                title={ title }
                description={ description }
                buttons={ button }
                />
        );
    }

    render() {
        let { 
            intl, 
            status, 
            error, 
            
            list,
            options,

            showList = true, 
            showDropzone = true,
            editable = true,
            disabled,
            unitId, 
            objectType, 
            objectId, 
            icon = ""

        } = this.props;

        let content = null;
        if (options && options.data && options.data.length) {
            content = (
                <PortalLinks>
                    { options.data.map((serviceId) => this.renderRow(serviceId, list.data, list.statuses)) }
                </PortalLinks>
            );
        }

        return (
            <div className={`${this.props.className||""}`}>
                { content }
            </div>
            );
    }
}


const mapStateToProps = (state, props) => {
    let s = state.getIn(["notification", notificationKey(props.objectType, props.objectId)]);
    if (!s) {
        return emptyList;
    }
    return s.toJS();
}



function mapDispatchToProps(dispatch, props) {
    return {
        registerComponent: () => dispatch(registerComponent(props.unitId, props.objectType, props.objectId)),
        unregisterComponent: () => dispatch(unregisterComponent(props.unitId, props.objectType, props.objectId)),
        saveNotification: (serviceId) => dispatch(saveNotification(props.unitId, props.objectType, props.objectId, serviceId)),
        fetchData: () => dispatch(fetchNotifications(props.unitId, props.objectType, props.objectId)),
        fetchNotificationOptions: () => dispatch(fetchNotificationOptions(props.unitId, props.objectType, props.objectId)),
        deleteNotification: (attachmentId) => dispatch(deleteNotification(props.unitId, props.objectType, props.objectId, attachmentId)),
        renameNotification: (attachmentId, name) => dispatch(renameNotification(props.unitId, props.objectType, props.objectId, attachmentId, name))
    };
}


Notifications = connect(mapStateToProps, mapDispatchToProps)(Notifications);

export default injectIntl(Notifications);
