import React from 'react';
import { RadioButton, Button } from 'lego-on-react';
import block from 'bem-cn';
import SpinOverlay from 'components2/SpinOverlay';
import { ConfigStore } from 'lib2/stores';
import notify from 'lib2/notify';
import fetchDomainOwnership from 'lib2/fetchDomainOwnership';
import directory from 'api2/directory';
import metrika from 'api2/metrika';
import { i18n, formatDate } from 'i18n2';
import './index.css';

const b = block('domain-verification');

const STATUS_CHECK_PERIOD = 15000;

const DefaultWeight = {
    'webmaster.meta_tag': 40,
    'webmaster.html_file': 30,
    'webmaster.dns': 20,
    'webmaster.whois': 10,
};

function byWeight(x, y) {
    let wx = x.weight || DefaultWeight[x.method] || 0;
    let wy = y.weight || DefaultWeight[y.method] || 0;

    if (wx === wy) {
        return 0;
    }

    return wx < wy ? 1 : -1;
}

export default class DomainVerification extends React.PureComponent {
    constructor(props) {
        super(props);

        this.state = {};

        this._updateState = this._updateState.bind(this);
        this._onMethodChange = this._onMethodChange.bind(this);
        this._startCheck = this._startCheck.bind(this);
        this._trackStatus = this._trackStatus.bind(this);
    }

    componentDidMount() {
        this._updateState(this.props.domain);
    }

    componentDidUpdate({ domain: prevDomain }) {
        let { domain } = this.props;

        let updated = domain.name !== prevDomain.name ||
            (domain.methods && (prevDomain.methods !== domain.methods));

        if (updated) {
            this._updateState(domain);
        }
    }

    _updateState(domain) {
        let { methods, last_check: lastCheck } = domain;
        let selectedMethod;

        if (methods) {
            methods.sort(byWeight);
            selectedMethod = (lastCheck && lastCheck.method) || (methods[0] && methods[0].method);
        }

        if (!this._unmounted) {
            this.setState({ methods, selectedMethod, lastCheck });
        }

        if (domain.verification_status === 'in-progress') {
            this._trackStatus();
        }
    }

    componentWillUnmount() {
        clearTimeout(this._check);

        this._unmounted = true;
    }

    _onMethodChange({ target }) {
        let selectedMethod = target.value;

        metrika.send(
            'Подтверждение домена',
            'Выбор способа подтверждения',
            selectedMethod
        );

        this.setState({ selectedMethod });
    }

    _startCheck() {
        let { domain, onVerified } = this.props;
        let { selectedMethod } = this.state;

        clearTimeout(this._check);

        this.setState({ busy: true });

        metrika.send(
            'Подтверждение домена',
            'Проверить',
            'Клик',
            selectedMethod
        );

        directory
            .send('POST', `/v11/domains/${encodeURIComponent(domain.name)}/check-ownership/`, {
                body: JSON.stringify({
                    verification_type: selectedMethod,
                }),
            })
            .then(({ ok, body }) => {
                metrika.send(
                    'Подтверждение домена',
                    'Проверить',
                    ok ? 'Проверка запущена' : 'Ошибка при запуске',
                    selectedMethod
                );

                if (!ok) {
                    return notify(i18n('domain.status.not_confirmed.title'), 'error');
                }

                if (body.owned) {
                    notify(i18n('domain.status.confirmed.title'), 'success');

                    if (onVerified) {
                        onVerified();
                    }
                } else {
                    return this._trackStatus()
                        .then(status => {
                            if (status !== 'owned' && status !== 'in-progress') {
                                notify(i18n('domain.status.not_confirmed.title'), 'error');
                            }
                        });
                }
            })
            .finally(() => {
                if (!this._unmounted) {
                    this.setState({ busy: false });
                }
            });
    }

    _trackStatus() {
        let { domain, onVerified } = this.props;

        return new Promise(resolve => {
            clearTimeout(this._check);

            this._check = setTimeout(() => {
                fetchDomainOwnership(domain)
                    .then(updatedDomain => {
                        this._updateState(updatedDomain);

                        let status = updatedDomain.verification_status;

                        switch (status) {
                            case 'owned':
                                onVerified && onVerified();
                                break;
                            case 'in-progress':
                                this._trackStatus();
                                break;
                        }

                        resolve(status);
                    })
                    .catch(resolve);
            }, STATUS_CHECK_PERIOD);
        });
    }

    render() {
        let { cls, domain } = this.props;
        let { busy, methods, selectedMethod, lastCheck } = this.state;

        if (!methods) {
            return (
                <div className={b({}).mix(cls)}>
                    <SpinOverlay
                        progress
                        size="m"
                        position="center"
                    />
                </div>
            );
        }

        busy = busy || domain.verification_status === 'in-progress';

        let lastCheckStatus = lastCheck && (
            i18n(`domain.confirmation_methods.webmaster.error.${lastCheck.fail_type}`) ||
            i18n('domain.confirmation_methods.webmaster.error.unknown')
        );

        return (
            <div className={b({}).mix(cls)}>
                <div className={b('intro')}>
                    <p>{i18n('domain.status.not_confirmed.webmaster_description')}</p>
                    <p>{i18n('domain.status.not_confirmed.webmaster_warning')}</p>
                </div>
                <div className={b('method')}>
                    <RadioButton
                        cls={b('method-radio-group')}
                        theme="normal"
                        view="default"
                        tone="default"
                        size="m"
                        value={selectedMethod}
                        onChange={this._onMethodChange}
                    >
                        {methods.map(({ method }) => (
                            <RadioButton.Radio
                                cls={b('method-radio', { type: method.replace(/[\._]/g, '-') })}
                                value={method}
                                key={method}
                            >
                                {i18n(`domain.confirmation_methods.${method}.short_title`) || method}
                            </RadioButton.Radio>
                        ))}
                    </RadioButton>
                </div>
                {methods.map(item => item.method === selectedMethod && (
                    <div
                        className={b('description')}
                        dangerouslySetInnerHTML={{
                            __html: i18n(`domain.verification.${item.method}.text`, {
                                domain: domain.name,
                                preferred_host: domain.preferred_host || domain.name,
                                passport_url: ConfigStore.get('passport.session.confirmEmail'),
                                button_text: i18n('domain.action.check_ownership'),
                                ...item,
                            }),
                        }}
                        key={item.method}
                    />
                ))}
                <div className={b('actions')}>
                    <Button
                        cls={b('button', { type: 'check' })}
                        theme="action"
                        size="m"
                        text={i18n('domain.action.check_ownership')}
                        onClick={this._startCheck}
                        progress={busy}
                    />
                    {!busy && lastCheck && lastCheck.method === selectedMethod && (
                        <div className={b('last-check')}>
                            <div
                                className={b('last-check-date')}
                                dangerouslySetInnerHTML={{
                                    __html: i18n('domain.verification.last_check', {
                                        date: formatDate(lastCheck.date, 'date_time'),
                                    }),
                                }}
                            />
                            <div
                                className={b('last-check-status')}
                                dangerouslySetInnerHTML={{
                                    __html: i18n('domain.verification.status', {
                                        status: lastCheckStatus,
                                    }),
                                }}
                            />
                        </div>
                    )}
                </div>
            </div>
        );
    }
}
