import React from 'react';
import { block } from 'bem-cn';
import { TextInput, Button, Spin } from 'lego-on-react';
import { i18n } from 'i18n2';
import common from 'i18n2/common';

import notify from 'lib2/notify';
import openFile from 'lib2/openFile';
import openUrl from 'lib2/openUrl';

import directory from 'api2/directory';
import directoryBinary from 'api2/directoryBinary';
import metrika from 'api2/metrika';

import RubleIcon from 'components/Icon/Ruble';
import Form from 'components2/Form';
import SpinOverlay from 'components2/SpinOverlay';
import PaymentModal from 'components2/PaymentModal';

import './index.css';

const b = block('payment');

function getAmountError(amount) {
    if (!amount) {
        return i18n('subscription_validation.payment.amount_undefined');
    }

    if (typeof amount === 'string') {
        amount = Number(amount);
    }

    if (Number.isNaN(amount)) {
        return i18n('subscription_validation.payment.invalid_amount');
    }

    if (amount <= 0) {
        return i18n('subscription_validation.payment.non-positive_amount');
    }
}

function pad(val) {
    return common.pad(val, 2);
}

function getInvoiceFilename(date) {
    return `connect_${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}` +
        `_${pad(date.getHours())}-${pad(date.getMinutes())}-${pad(date.getSeconds())}.pdf`;
}

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

        this.state = {
            amount: this.props.amount || undefined,
        };

        this._onPayClick = this._onPayClick.bind(this);
        this._onInvoiceClick = this._onInvoiceClick.bind(this);
        this._onAmountChange = this._onAmountChange.bind(this);
        this._onPaymentCancel = this._onPaymentCancel.bind(this);
        this._onPaymentSuccess = this._onPaymentSuccess.bind(this);
        this._onPaymentFailure = this._onPaymentFailure.bind(this);
    }

    componentDidUpdate() {
        const { amount } = this.props;

        if (amount && this.state.amount === undefined) {
            this.setState({ amount });
        }
    }

    componentWillUnmount() {
        this._unmounted = true;
    }

    _onPayClick() {
        const { amount } = this.state;
        const error = getAmountError(amount);

        this.setState({
            amountError: error,
        });

        if (error) {
            return;
        }

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

        metrika.send(
            'Текущий баланс',
            'Пополнить',
            window.location.pathname
        );

        directory.send('POST', '/v11/subscription/trust/pay/', {
            body: JSON.stringify({
                amount: Number(amount),
            }),
        })
            .then(({ body, ok }) => {
                if (!ok) {
                    metrika.send(
                        'Текущий баланс',
                        'Пополнить',
                        'Ошибка',
                        body.code
                    );

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

                    return this.setState({
                        amountError: i18n(`backend_errors.${body.code}`) || i18n('common.status.failed'),
                    });
                }

                metrika.send(
                    'Текущий баланс',
                    'Пополнить',
                    'Показана форма оплаты Траста'
                );

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

    _onInvoiceClick() {
        const { amount } = this.state;
        const error = getAmountError(amount);

        this.setState({
            amountError: error,
        });

        if (error) {
            return;
        }

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

        metrika.send(
            'Текущий баланс',
            'Выставить счёт',
            window.location.pathname
        );

        directoryBinary.send('POST', '/subscription/invoice/', {
            body: JSON.stringify({
                amount: Number(amount),
            }),
        })
            .then(({ ok, body }) => {
                if (!ok) {
                    metrika.send(
                        'Текущий баланс',
                        'Выставить счёт',
                        'Ошибка',
                        body.code
                    );

                    return this.setState({
                        amountError: i18n(`backend_errors.${body.code}`) || i18n('common.status.failed'),
                    });
                }

                metrika.send(
                    'Текущий баланс',
                    'Выставить счёт',
                    'Получен файл со счётом'
                );

                this.setState({
                    amount: '',
                });

                openFile(body, 'application/pdf', getInvoiceFilename(new Date()));
            })
            .finally(() => {
                if (!this._unmounted) {
                    this.setState({
                        busy: false,
                    });
                }
            });
    }

    _onAmountChange(amount) {
        this.setState({
            amount,
            amountError: null,
        });
    }

    _onPaymentCancel() {
        metrika.send(
            'Текущий баланс',
            'Пополнить',
            'Отмена оплаты'
        );

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

    _onPaymentFailure(message) {
        metrika.send(
            'Текущий баланс',
            'Пополнить',
            'Ошибка при оплате'
        );

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

        if (message) {
            notify(i18n(`subscription.balance.message.${message}`), 'error');
        }
    }

    _onPaymentSuccess(message) {
        metrika.send(
            'Текущий баланс',
            'Пополнить',
            'Успешная оплата'
        );

        this.setState({
            amount: '',
            paymentUrl: null,
        });

        this.props.onSuccess();

        if (message) {
            notify(i18n(`subscription.balance.message.${message}`), 'success');
        }
    }

    _initInput(element) {
        if (element) {
            element.focus();
        }
    }

    render() {
        const { cls, personType } = this.props;
        const { amount, amountError, paymentUrl, busy } = this.state;
        const isLegal = personType === 'legal';

        return (
            <div className={b({}).mix(cls)}>
                <Form
                    cls={b('form')}
                    onSubmit={this._onPayClick}
                >
                    <Form.Field>
                        <TextInput
                            theme="normal"
                            size="m"
                            cls={b('amount-input')}
                            text={amount}
                            ref={this._initInput}
                            hasClear
                            autoComplete={false}
                            onChange={this._onAmountChange}
                            iconRight={<RubleIcon cls={b('amount-icon')} height="55%" />}
                        />
                        <Button
                            cls={b('button', { role: 'submit' })}
                            text={i18n('subscription.balance.make_payment')}
                            onClick={this._onPayClick}
                            theme="action"
                            disabled={busy}
                            size="m"
                        />
                        {isLegal && (
                            <Button
                                cls={b('button', { role: 'invoice' })}
                                text={i18n('subscription.balance.get_invoice')}
                                onClick={this._onInvoiceClick}
                                disabled={busy}
                                theme="normal"
                                size="m"
                            />
                        )}
                    </Form.Field>
                    {amountError && (
                        <Form.Error cls={b('error')}>
                            {amountError}
                        </Form.Error>
                    )}
                    <SpinOverlay
                        progress={busy}
                        spinVisible={false}
                    />
                </Form>
                <Spin
                    cls={b('spin')}
                    size="xs"
                    progress={busy}
                />
                <PaymentModal
                    cls={b('modal')}
                    paymentUrl={paymentUrl}
                    onCancel={this._onPaymentCancel}
                    onSuccess={this._onPaymentSuccess}
                    onFailure={this._onPaymentFailure}
                />
            </div>
        );
    }
}
