import React from 'react';
import { Spin } from 'lego-on-react';
import Polling from '@connect/polling';
import { i18n } from 'i18n2';

import { directory, directoryWithoutOrg } from 'api2/directory';
import metrika from 'api2/metrika';

import Modal from 'components2/Modal';
import TrustPaymentForm from 'components2/TrustPaymentForm';

import openUrl from 'lib2/openUrl';
import getOrganization from 'lib2/getOrganization';
import fetchServices from 'lib2/fetchServices';

import { b } from './const';
import { BalanceHint } from './BalanceHint.jsx';

import './index.css';

const ServicesContainer = React.memo(({ warnText, services }) => {
    return (
        <div className={b('services-containter')}>
            <div className={b('services-warn')} dangerouslySetInnerHTML={{ __html: warnText }} />
            {services.map(service => (
                <div className={b('service')} key={service.slug}>
                    <div
                        className={b('service-icon')}
                        style={{ backgroundImage: `url(${service.icon})` }}
                    />
                    <div className={b('service-name')}>{service.name}</div>
                </div>
            ))}
        </div>
    );
});

// только для .ru и .com
const currentYandexDomain = (() => {
    const array = window.location.hostname.split('.');

    return [array.pop(), array.pop()].reverse().join('.');
})();

const DATA_REMOVED_SERVICES = ['wiki', 'tracker'/* 'mail' */];
const DATA_UNBIND_SERVICES = ['metrika', 'webmaster', 'direct', 'disk', 'forms', 'calendar', 'yandexsprav'];

/** @type {React.PureComponent<IRemoveOrgModalProps, IRemoveOrgModalState>} */
export default class RemoveOrgModal extends React.PureComponent {
    /** @param {IRemoveOrgModalProps} props */
    constructor(props) {
        super(props);

        this.state = {
            busy: props.visible, // see componentDidMount
            error: false,
            removing: false,
            firstLoad: true,
        };

        this.onCancel = this.onCancel.bind(this);
        this.onRemoveClick = this.onRemoveClick.bind(this);
        this.onPaymentSuccess = this.onPaymentSuccess.bind(this);
        this.onPaymentFailure = this.onPaymentFailure.bind(this);

        this.DebtPolling = new Polling(() => {
            this._sendDebtRequest()
                .then(({ ok, body }) => {
                    if (this._unmounted) {
                        this.DebtPolling.stop();

                        return;
                    }

                    if (ok && this.state.debtData.balance !== body.balance) {
                        this._updateDebtState(body);
                        this.setState({ busy: false });

                        this.DebtPolling.stop();
                    }
                });
        });
    }

    componentDidMount() {
        this.state.busy && this._init(); // see constructor
    }

    componentWillUnmount() {
        this._unmounted = true;
    }

    componentDidUpdate() {
        if (this.props.visible && !this._inited) { // lazy init
            this.setState({ busy: true });
            this._init();
        }
    }

    onRemoveClick() {
        if (this.state.debtData.debt > 0) {
            return this._payDebt();
        }

        this._remove();
    }

    _init() {
        if (this._unmounted || this._inited) return;

        this._inited = true;

        return Promise.all([
            fetchServices()
                .then(({ ok, body }) => {
                    if (ok && !this._unmounted) {
                        /** @type {Object[]} */
                        const actualServices = body.filter(service => service.enabled && service.ready);

                        const dataRemovedServices = actualServices
                            .filter(service => DATA_REMOVED_SERVICES.includes(service.slug));
                        const dataUnbindServices = actualServices
                            .filter(service => DATA_UNBIND_SERVICES.includes(service.slug));

                        this.setState({ dataRemovedServices, dataUnbindServices });
                    }
                }),
            this._requestDebtData(),
        ]).finally(() => !this._unmounted && this.setState({ busy: false, firstLoad: false }));
    }

    _payDebt() {
        this.setState({ busy: true });

        metrika.send(
            'Удаление организации',
            'Погасить задолженность',
            window.location.pathname,
        );

        directory
            .send('POST', '/v11/subscription/trust/pay/', {
                body: JSON.stringify({
                    amount: this.state.debtData.debt,
                }),
            })
            .then(({ body, ok }) => {
                if (!ok) {
                    const { code } = body;

                    metrika.send(
                        'Удаление организации',
                        'Погасить задолженность',
                        'Ошибка',
                        code,
                    );

                    if (code === 'no_active_person_found') {
                        return openUrl(`/portal/balance/contract?source=balance&reason=${code}`);
                    }

                    !this._unmounted && this.setState({ error: code || true });

                    return;
                }

                metrika.send(
                    'Удаление организации',
                    'Погасить задолженность',
                    'Показана форма оплаты Траста',
                );

                !this._unmounted && this.setState({
                    paymentUrl: body.payment_url,
                });
            })
            .finally(() => {
                if (!this._unmounted) {
                    this.setState({
                        busy: false,
                    });
                }
            });
    }

    _remove() {
        if (this._unmounted) return;

        metrika.send(
            'Удаление организации',
            'Удалить',
        );

        this.setState({ busy: true });

        return directory
            .send('DELETE', `/v11/organizations/${getOrganization().id}/delete/`)
            .then(({ ok, body }) => {
                this.setState({ error: !ok });

                if (ok) {
                    const taskId = body.task_id;

                    !this._unmounted && this._startRemovePolling(taskId);

                    metrika.send(
                        'Удаление организации',
                        'Удалить',
                        'Запущен процесс удаления',
                        taskId,
                    );
                } else {
                    metrika.send(
                        'Удаление организации',
                        'Удалить',
                        'Ошибка',
                        body.code,
                    );
                }
            })
            .catch(() => !this._unmounted && this.setState({ error: true }))
            .finally(() => !this._unmounted && this.setState({ busy: false }));
    }

    _startRemovePolling(taskId) {
        if (this._unmounted || !taskId) return;

        this.setState({ removing: true });

        const pollContract = () => {
            // ходим за статусом удаления организации без x-org-id,
            // чтобы не получить 403 после того, как организация удалится
            return directoryWithoutOrg
                .send('GET', `/v11/organizations/${getOrganization().id}/delete/`, {
                    query: {
                        task_id: taskId,
                    },
                })
                .then(res => {
                    if (this._unmounted) return;

                    if (res.ok) {
                        switch (res.body.status) {
                            case 'success':
                                return openUrl('/', '_self');
                            case 'failed':
                                return this.setState({ removing: false, error: true });
                        }
                    }

                    setTimeout(pollContract, 2000);
                });
        };

        pollContract();
    }

    /** @returns {Promise<?>} */
    _sendDebtRequest() {
        return directory.send('GET', `/v11/organizations/${getOrganization().id}/debt/`);
    }

    _requestDebtData() {
        return this._sendDebtRequest()
            .then(({ ok, body }) => {
                if (this._unmounted) return;

                if (!ok) {
                    this.setState({ error: true });

                    return;
                }

                this._updateDebtState(body);
            });
    }

    _updateDebtState(debtBody) {
        const {
            debt,
            balance,
            after_payment: summaryBalance,
            current_month_price: monthPrice,
        } = debtBody;

        /** @type {IDebtData} */
        const debtData = {
            debt,
            balance,
            monthPrice,
            summaryBalance,
        };

        this.setState({
            debtData,
        });

        return debtData;
    }

    onPaymentSuccess() {
        this.setState({
            busy: true,
            paymentUrl: null,
            afterPayment: true,
        });

        this.DebtPolling.start();
    }

    onPaymentFailure() {
        this.setState({
            error: true,
            paymentUrl: null,
        });
    }

    onCancel() {
        const { onCancel } = this.props;

        this.state.paymentUrl && this.setState({ paymentUrl: null });

        onCancel && onCancel();
    }

    render() {
        const { onCancel } = this;
        const { visible } = this.props;
        const {
            busy,
            firstLoad,
            removing,
            paymentUrl,
            error,
            debtData,
            dataRemovedServices,
            // dataUnbindServices,
            afterPayment,
        } = this.state;

        if (firstLoad) {
            return (
                <Modal cls={b({ view: 'first-load' })} visible={visible}>
                    <Modal.Busy visible />
                </Modal>
            );
        }

        if (paymentUrl) {
            return (
                <Modal
                    cls={b({ view: 'payment' })}
                    visible={visible}
                >
                    <Modal.Title>
                        {i18n('subscription.balance.payment.title') /* Пополнение баланса */}
                    </Modal.Title>
                    <Modal.CloseButton onClick={onCancel} />
                    <Modal.Body>
                        <div className={b('iframe')}>
                            <TrustPaymentForm
                                paymentUrl={paymentUrl}
                                onSuccess={this.onPaymentSuccess}
                                onFailure={this.onPaymentFailure}
                            />
                        </div>
                    </Modal.Body>
                    <Modal.Busy visible={busy} />
                </Modal>
            );
        }

        if (removing) {
            return (
                <Modal
                    cls={b({ view: 'removing' })}
                    visible={visible}
                >
                    <Modal.Title>
                        {i18n('organization_remove.title.removing') /* Удаление организации... */}
                    </Modal.Title>
                    <Modal.Body>
                        <div className={b('removing-text')}>
                            {i18n('organization_remove.waiting_removing') /* Пожалуйста, подождите. Удаление может занять несколько минут. */}
                        </div>
                        <Spin
                            progress
                            size="l"
                            view="default"
                            tone="default"
                            cls={b('removing-spinner')}
                        />
                    </Modal.Body>
                </Modal>
            );
        }

        const hasDebt = debtData && debtData.debt > 0;
        const canRemove = !hasDebt;
        const masterDomain = getOrganization().domains.master;

        let errorText = null;
        const defaultErrorText = i18n('organization_remove.error', {
            delay: 15, /* Произошла ошибка. Повторите попытку через ** минут. */
        });

        if (typeof error === 'string') {
            errorText = i18n(`backend_errors.${error}`) || defaultErrorText;
        } else if (error) {
            errorText = defaultErrorText;
        }

        return (
            <Modal
                cls={b({ view: 'common' })}
                visible={visible}
            >
                <Modal.Title>
                    {i18n('organization_remove.title.remove') /* Удаление организации */}
                </Modal.Title>
                <Modal.CloseButton onClick={onCancel} />
                <Modal.Body>
                    {errorText && (
                        <div className={b('error-box')}>
                            {errorText}
                        </div>
                    )}
                    {debtData && (
                        <BalanceHint
                            key={String(visible)}
                            repaid={afterPayment}
                            debt={debtData.debt}
                            balance={debtData.balance}
                            monthPrice={debtData.monthPrice}
                            summaryBalance={debtData.summaryBalance}
                        />
                    )}
                    {Boolean(canRemove && masterDomain) && (
                        <React.Fragment>
                            <div
                                className={b('domain-warn')}
                                dangerouslySetInnerHTML={{ __html: i18n('organization_remove.warning.domain', {
                                    domain: masterDomain, // Аккаунты на домене Х будут удалены...
                                }) }}
                            />
                            <div className={b('separator')} />
                        </React.Fragment>
                    )}
                    {Boolean(canRemove && dataRemovedServices && dataRemovedServices.length) && (
                        <React.Fragment>
                            <ServicesContainer
                                warnText={i18n('organization_remove.warning.data_remove_services', {
                                    domain: currentYandexDomain, // Аккаунты на домене yandex.ru будут отключены от...
                                })}
                                services={dataRemovedServices}
                            />
                            <div className={b('separator')} />
                        </React.Fragment>
                    )}
                    {/* Boolean(canRemove && dataUnbindServices && dataUnbindServices.length) && (
                        <React.Fragment>
                            <ServicesContainer
                                // Данные в следующих сервисах удалены не будут...
                                warnText={i18n('organization_remove.warning.data_unbind_services')}
                                services={dataUnbindServices}
                            />
                            <div className={b('separator')} />
                        </React.Fragment>
                    ) */}
                    {canRemove && (
                        <div className={b('remove-warn')}>
                            {i18n('organization_remove.warning.org') /* Удаленную организацию нельзя восстановить */}
                        </div>
                    )}
                </Modal.Body>
                <Modal.Busy visible={busy} />
                <Modal.ConfirmActions
                    side="left"
                    onConfirm={this.onRemoveClick}
                    onCancel={onCancel}
                    confirmCaption={i18n(hasDebt ?
                        'organization_remove.actions.pay_of_debt' : // Погасить задолженность
                        'organization_remove.actions.remove' // Удалить
                    )}
                />
            </Modal>
        );
    }
}

/**
 * @typedef {Object} IRemoveOrgModalProps
 * @property {Boolean} visible
 * @property {() => void} onCancel
 */

/**
 * @typedef {Object} IRemoveOrgModalState
 * @property {Boolean} busy
 * @property {Boolean | String} error
 * @property {Boolean} firstLoad
 * @property {Boolean} removing - означает, что запущен процеес удаления организации
 * @property {IDebtData} [debtData]
 * @property {Boolean} [afterPayment] - указывает, что обновление баланса произошло после оплаты
 * @property {Object[]} [services] - сервисы, из которых удалится информация при удалении организации
 * @property {Object[]} [dataRemovedServices]
 * @property {Object[]} [dataUnbindServices]
 * @property {String} [paymentUrl] - урл для попапа траста, когда он есть – показываем попап оплаты первоочерёдно
 */

/**
 * @typedef IDebtData
 * @property {Number} balance - баланс организации
 * @property {Number} monthPrice - плата за потребление услуг в текущем месяце
 * @property {Number} debt - долг, сумма, которую нужно оплатить до удаления организации (monthPrice - balance)
 * @property {Number} summaryBalance - итоговый баланс (balance - monthPrice)
 */
