import React from 'react';
import _ from 'lodash';
import { Promise } from 'rsvp';
import Immutable from 'immutable';
import Metrika from 'lib/metrika';

import Scrollable from 'ui/Scrollable';
import AuthStore from 'stores/Auth';
import ConfigStore from 'stores/Config';
import SubscriptionStore from 'stores/Subscription';

import SubscriptionActions from 'actions/Subscription';
import subscriptionApi from 'api/subscription';

import storage from 'services/storage';
import naturalPersonValidator from 'validation/naturalPerson';
import legalPersonValidator from 'validation/legalPerson';
import FormMixin from 'lib/FormMixin';
import StoreMixin from 'lib/StoreMixin';

import { i18n } from 'lib/i18n';
import Url from 'lib/Url';

import Payment from 'components/Subscription/Payment';
import Form from 'ui/Form';
import EntityType from './EntityType';
import PersonId from './PersonId';
import NaturalPersonForm from './Forms/NaturalPerson';
import LegalPersonForm from './Forms/LegalPerson';

import './index.css';

const FormMap = {
    natural: NaturalPersonForm,
    legal: LegalPersonForm,
};

const ValidatorMap = {
    natural: naturalPersonValidator,
    legal: legalPersonValidator,
};

const NewPersonId = {
    person_id: 'new-person-id',
    first_name: i18n('subscription.new_person_id.name'),
};

function getStorageKey() {
    return `person_type.${AuthStore.getUserId()}`;
}

function getFormKey(entityType) {
    return `form.${entityType}_person.${AuthStore.getUserId()}`;
}

const Subscription = React.createClass({

    mixins: [FormMixin, StoreMixin],

    getStoreState() {
        const entityType = storage.session.getValue(getStorageKey()) || 'natural';
        const persons = SubscriptionStore.getPersons();

        return {
            entityType,
            personId: persons && persons.length ? String(persons[0].person_id) : NewPersonId.person_id,
            errors: new Immutable.Map(),
            storedValues: storage.session.getValue(getFormKey(entityType)),
            persons,
        };
    },

    componentDidMount() {
        this.subscribe([SubscriptionStore]);
    },

    componentWillUnmount() {
        storage.session.setValue(getStorageKey(), this.state.entityType);
        this._storeFormValues();
    },

    _handleEntityTypeChange(e) {
        this._storeFormValues();

        this.setState({
            entityType: e.target.value,
            errors: new Immutable.Map(),
            storedValues: storage.session.getValue(getFormKey(e.target.value)),
        });
    },

    _handlePersonIdChange({ target: { value } }) {
        if (this.isNewPersonId()) {
            this._storeFormValues();
        }

        const nextState = {
            personId: value,
        };

        if (value === NewPersonId.person_id) {
            nextState.storedValues = storage.session.getValue(getFormKey(this.state.entityType));
        }

        this.setState(nextState);
    },

    _storeFormValues() {
        const { entityType } = this.state;

        if (this.refs.form) {
            storage.session.setValue(getFormKey(entityType), this.refs.form.getInput());
        }
    },

    _renderHelp() {
        const content = i18n('subscription.form.help', {
            url: ConfigStore.getHelpUrl('ui.help.troubleshooting'),
        });

        return (
            <div
                className="subscription__help"
                dangerouslySetInnerHTML={{ __html: content }}
            />
        );
    },

    _handleSubmit(data) {
        const { entityType } = this.state;

        let entityValidator;

        // Если создаем нового плательщика, то надо провалидировать поля
        if (this.isNewPersonId()) {
            entityValidator = ValidatorMap[entityType];
        }

        if (this._use(entityValidator)._validate(data)) {
            this.setState({ busy: true });

            return this._submitData(data)
                .finally(() => {
                    this.setState({ busy: false });
                });
        }
    },

    _submitData(data) {
        const { personId, persons } = this.state;

        if (personId !== NewPersonId.person_id) {
            const person = _.find(persons, details => String(details.person_id) === personId);

            data = {
                person_id: person.person_id,
                person_type: person.type,
            };
        }

        return SubscriptionActions.createContract(data).then(response => {
            const isContractAlreadyAvailable =
                _.get(response, 'originalError.code') === 'organization_already_has_contract';

            if (response && response.errors && !isContractAlreadyAvailable) {
                this.setState({ errors: response.errors });

                return;
            }

            let source = Url.getQueryParam('source');
            let serviceSlug = source.split('.')[0];

            Metrika.reachGoal(`Paid${_.capitalize(serviceSlug)}`);

            return new Promise(resolve => {
                let counter = 0;

                let pollContract = () => {
                    subscriptionApi.getState()
                        .then(pollingData => {
                            if (_.get(pollingData, 'subscription.current.has_contract')) {
                                return resolve(true);
                            }
                        })
                        .catch(() => {
                            // ignore
                        })
                        .finally(() => {
                            if (counter++ > 100) {
                                return resolve(false);
                            }

                            setTimeout(pollContract, 3000);
                        });
                };

                pollContract();
            })
                .then(isContractCreated => {
                    if (!isContractCreated) {
                        return Url.open(Url.getLocation('/portal/home?has_contract=false'));
                    }

                    SubscriptionActions.toDetails();
                });
        });
    },

    isNewPersonId() {
        return this.state.personId === NewPersonId.person_id;
    },

    render() {
        const { entityType, isPaymentEnabled, busy, errors, storedValues, persons, personId } = this.state;
        const EntityForm = FormMap[entityType];
        const source = Url.getQueryParam('source');
        const hasPersons = persons && persons.length !== 0;

        return (
            <div className="subscription section">
                <Scrollable>
                    <div className="section-body">
                        <Form
                            ref="form"
                            className="subscription-form form"
                            onSubmit={this._handleSubmit}
                        >
                            <div className="subscription__title">
                                {i18n('subscription.form.title')}
                            </div>
                            <div className="subscription__description">
                                {i18n(`subscription.form.${source}.description`) ||
                                i18n('subscription.form.default.description')}
                            </div>
                            {hasPersons && (
                                <PersonId
                                    persons={persons.concat(NewPersonId)}
                                    value={personId}
                                    onChange={this._handlePersonIdChange}
                                />
                            )}
                            {this.isNewPersonId() && (
                                <EntityType
                                    val={entityType}
                                    onChange={this._handleEntityTypeChange}
                                />
                            )}
                            {this.isNewPersonId() && (
                                <EntityForm
                                    errors={errors}
                                    storedValues={storedValues}
                                />
                            )}
                            <Payment
                                enabled={isPaymentEnabled}
                                busy={busy}
                                errors={errors}
                            />
                        </Form>
                        {this._renderHelp()}
                    </div>
                </Scrollable>
            </div>
        );
    },

});

export default Subscription;
