import _ from 'lodash';
import React from 'react';
import ReactDOM from 'react-dom';
import { SERVICES_IN_BETA } from 'constants/Services';

import BindPromo from 'components/BindPromo';

import OrganizationActions from 'actions/OrgSetup';

import Url from 'lib/Url';

import './index.css';

const BindPromoLayout = React.createClass({

    getInitialState() {
        return {
            available: false,
            hasOrg: false,
            serviceSlug: '',
            inProgress: false,
        };
    },

    componentDidMount() {
        this._startListenPong();

        this._postMessage('connect_resource_request', { name: window.name }, '*');
    },

    _onChangeSize() {
        if (!this._promo) {
            return;
        }

        const currentHeight = this._promo.offsetHeight;
        const currentWidth = this._promo.offsetWidth;

        if (this._height !== currentHeight || this._width !== currentWidth) {
            this._height = currentHeight;
            this._width = currentWidth;

            this._postSize();
        }
    },

    _postSize() {
        this._postMessage('connect_bind_promo_size', {
            size: {
                height: this._height,
                width: this._width,
            },
        });
    },

    _startListenPong() {
        this._stopListenPong();
        window.addEventListener('message', this._onWindowMessage, false);
    },

    _stopListenPong() {
        window.removeEventListener('message', this._onWindowMessage, false);
    },

    _createMessageData(type, data, name) {
        return _.assign({ message: type, name }, data);
    },

    _postMessage(type, data, origin = this._getOrigin()) {
        const name = window.name;
        const messageData = this._createMessageData(type, data, name);

        window.parent.postMessage(messageData, origin);
    },

    _onWindowMessage(windowEvent = {}) {
        const { data, origin } = windowEvent;

        if (!Url.isAllowedIframeOrigin(origin) || !data || data.message !== 'connect_resource_response') {
            return;
        }

        this._setOrigin(origin);

        this._stopListenPong();

        const requestData = {
            service: {
                slug: data.service_slug,
                resource: {
                    id: data.resource_id,
                    relations: data.relations,
                },
            },
        };

        Promise.all([
            OrganizationActions.getOrganizationsToBind(requestData),
            OrganizationActions.bindWithResource(requestData, { 'dry-run': 1 }),
        ])
            .then(([orgsToBind, canBindNewOrg]) => {
                let organizations = [];

                if (!orgsToBind.errors) {
                    organizations = orgsToBind.organizations;
                }

                const enabled = organizations.filter(({ binding_available: available }) => available).length !== 0 ||
                    !canBindNewOrg.errors;
                const serviceSlug = data.service_slug;
                const advCodes = {
                    person_is_already_in_some_org: true,
                };

                let type = 'normal';

                if (!enabled) {
                    const newOrgAdv = canBindNewOrg.errors && canBindNewOrg.originalError.code &&
                        advCodes[canBindNewOrg.originalError.code];

                    const orgsAdv = organizations.some(({ binding_available: available, reason }) =>
                        !available && advCodes[reason]);

                    if (serviceSlug === 'metrika' && (newOrgAdv || orgsAdv)) {
                        type = 'adv';
                    } else {
                        return this._onPromoUnavailable();
                    }
                }

                this.setState({
                    available: true,
                    serviceSlug,
                    hasOrg: organizations.length !== 0,
                    type,
                    origin,
                }, this._postSize);

                setInterval(this._onChangeSize, 300);
            })
            .catch(this._onPromoUnavailable);
    },

    _setOrigin(origin) {
        this._origin = origin;
    },

    _getOrigin() {
        return this._origin;
    },

    _setPromoRef(element) {
        if (!element) {
            return;
        }

        this._promo = ReactDOM.findDOMNode(element);

        this._onChangeSize();
    },

    _onPromoUnavailable() {
        this._postMessage('connect_bind_promo_unavailable');
    },

    _onConfirm() {
        this._postMessage('connect_bind_promo_confirm');
    },

    render() {
        const { available, hasOrg, serviceSlug, type } = this.state;

        if (!available) {
            return null;
        }

        return (
            <BindPromo
                ref={this._setPromoRef}
                onConfirm={this._onConfirm}
                serviceSlug={serviceSlug}
                hasOrg={hasOrg}
                type={type}
                isBeta={SERVICES_IN_BETA.indexOf(serviceSlug) !== -1}
            />
        );
    },

});

export default BindPromoLayout;
