import React from 'react';
import { Button, Link, Icon } from 'lego-on-react';
import block from 'bem-cn';
import PencilIcon from 'components/Icon/Pencil';
import TrashIcon from 'components/Icon/Trash';
import EditDnsRecordModal from 'components2/EditDnsRecordModal';
import SpinOverlay from 'components2/SpinOverlay';
import Table from 'components2/Table';
import Placeholder from 'components2/Placeholder';
import Modal from 'components2/Modal';
import getDnsRecordContent from 'lib2/getDnsRecordContent';
import getDnsRecordPriority from 'lib2/getDnsRecordPriority';
import hasPermission from 'lib2/hasPermission';
import onUrlHash from 'lib2/onUrlHash';
import { ConfigStore } from 'lib2/stores';
import notify from 'lib2/notify';
import withCsrfToken from 'lib2/withCsrfToken';
import dns from 'api2/dns';
import metrika from 'api2/metrika';
import { i18n } from 'i18n2';
import './index.css';

const b = block('dns-settings');
const { Thead, Tbody, Tr, Td } = Table;

function byType(x, y) {
    if (x.type === y.type) {
        return 0;
    }

    return x.type < y.type ? -1 : 1;
}

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

        this.state = {};

        this._update = this._update.bind(this);
        this._addRecord = this._addRecord.bind(this);
        this._editRecord = this._editRecord.bind(this);
        this._removeRecord = this._removeRecord.bind(this);

        this._onEditRecordSubmit = this._onEditRecordSubmit.bind(this);
        this._onEditRecordCancel = this._onEditRecordCancel.bind(this);

        this._cancelRecordRemoval = this._cancelRecordRemoval.bind(this);
    }

    componentDidMount() {
        this._hashListener = onUrlHash('#add-dns-record', () => this.setState({ editRecordModalOpen: true }));

        this._update();
    }

    componentWillUnmount() {
        this._unmounted = true;
        this._hashListener.remove();
    }

    _update() {
        let { domain } = this.props;
        let canonicalName = `${domain.name}.`;

        this.setState({ busy: true });

        return dns
            .send('GET', `/domains/${encodeURIComponent(canonicalName)}/`)
            .then(({ ok }) => {
                // если домена нет в днс-хостинге, пытаемся включить его
                if (!ok) {
                    return dns
                        .send('POST', withCsrfToken('/domains/'), {
                            body: JSON.stringify({ name: canonicalName }),
                        });
                }
            })
            .then(() => {
                return dns
                    .send('GET', `/domains/${encodeURIComponent(canonicalName)}/records/`, {
                        query: {
                            offset: 0,
                            size: 5000,
                        },
                    })
                    .then(({ ok, body }) => {
                        if (this._unmounted || !ok || !Array.isArray(body.items)) {
                            return;
                        }

                        this.setState({
                            records: body.items && body.items.sort(byType),
                        });
                    });
            })
            .finally(() => {
                if (!this._unmounted) {
                    this.setState({
                        inited: true,
                        busy: false,
                    });
                }
            });
    }

    _removeRecord(record) {
        let { domain } = this.props;
        let canonicalName = encodeURIComponent(`${domain.name}.`);

        this.setState({ busyRemoving: true });

        metrika.send(
            'Редактор DNS',
            'Удалить запись',
            'Удалить'
        );

        dns
            .send('DELETE', withCsrfToken(`/domains/${canonicalName}/records/${encodeURIComponent(record.id)}/`))
            .then(({ ok }) => {
                metrika.send(
                    'Редактор DNS',
                    'Удалить запись',
                    ok ? 'Успешно' : 'Ошибка'
                );

                if (ok) {
                    notify(i18n('dns_record.status.removed'), 'success');

                    this._update();
                } else {
                    notify(i18n('dns_record.status.failed_to_remove'), 'error');
                }
            })
            .finally(() => {
                if (!this._unmounted) {
                    this.setState({
                        busyRemoving: false,
                        removeRecordModalOpen: false,
                    });
                }
            });
    }

    _confirmRecordRemoval(record) {
        metrika.send(
            'Редактор DNS',
            'Удалить запись',
            'Уверены?'
        );

        this.setState({
            removeRecordModalOpen: true,
            removedRecord: record,
        });
    }

    _cancelRecordRemoval() {
        metrika.send(
            'Редактор DNS',
            'Удалить запись',
            'Отмена'
        );

        this.setState({
            removeRecordModalOpen: false,
        });
    }

    _editRecord(record) {
        metrika.send(
            'Редактор DNS',
            'Обновить запись',
            'Начало'
        );

        this.setState({
            editRecordModalOpen: true,
            editedRecord: record,
        });
    }

    _addRecord() {
        this.setState({
            editRecordModalOpen: true,
            editedRecord: null,
        });
    }

    _onEditRecordSubmit() {
        this._update();

        this.setState({
            editRecordModalOpen: false,
        });
    }

    _onEditRecordCancel() {
        this.setState({
            editRecordModalOpen: false,
        });
    }

    render() {
        let { cls, domain } = this.props;
        let {
            inited,
            busy,
            records = [],
            editedRecord,
            editRecordModalOpen,
            removedRecord,
            removeRecordModalOpen,
            busyRemoving,
        } = this.state;

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

        if (domain.tech) {
            return (
                <div
                    className={b({ unavailable: true }).mix(cls)}
                    dangerouslySetInnerHTML={{
                        __html: i18n('dns_settings.not_editable.domain_must_be_natural', {
                            domain: domain.name,
                        }),
                    }}
                />
            );
        }

        let canEdit = domain.owned && !domain.tech && hasPermission('edit_dns');

        return (
            <div className={b({ empty: records.length === 0 }).mix(cls)}>
                {canEdit && (
                    <React.Fragment>
                        <div className={b('intro')}>
                            {i18n('dns_settings.description')}
                        </div>
                        <div
                            className={b('warning')}
                            dangerouslySetInnerHTML={{
                                __html: i18n('dns_settings.warning', {
                                    delegate_domain_help_url: ConfigStore.get('ui.help.delegate_domain'),
                                }),
                            }}
                        />
                    </React.Fragment>
                )}
                <div className={b('table-container')}>
                    <Table cls={b('table')}>
                        <Thead>
                            <Tr cls={b('thead-tr')}>
                                <Td>{i18n('dns_record.host')}</Td>
                                <Td>{i18n('dns_record.type')}</Td>
                                <Td>{i18n('dns_record.content')}</Td>
                                <Td>{i18n('dns_record.priority')}</Td>
                                <Td>{i18n('dns_record.ttl')}</Td>
                                <Td />
                            </Tr>
                        </Thead>
                        <Tbody>
                            {records.map(record => (
                                <Tr
                                    cls={b('tbody-tr')}
                                    key={record.id}
                                >
                                    <Td cls={b('record-name')}>{record.name}</Td>
                                    <Td cls={b('record-type')}>{record.type}</Td>
                                    <Td cls={b('record-content')}>{getDnsRecordContent(record)}</Td>
                                    <Td cls={b('record-priority')}>{getDnsRecordPriority(record)}</Td>
                                    <Td cls={b('record-ttl')}>{record.ttl}</Td>
                                    <Td cls={b('record-actions')}>
                                        <Button
                                            cls={b('record-action', { type: 'edit' })}
                                            title={i18n('dns_record.action.edit')}
                                            onClick={() => this._editRecord(record)}
                                            theme="normal"
                                            view="clear"
                                        >
                                            <Icon glyph="yes"><PencilIcon /></Icon>
                                        </Button>
                                        <Button
                                            cls={b('record-action', { type: 'remove' })}
                                            title={i18n('dns_record.action.remove')}
                                            onClick={() => this._confirmRecordRemoval(record)}
                                            theme="normal"
                                            view="clear"
                                        >
                                            <Icon glyph="yes"><TrashIcon /></Icon>
                                        </Button>
                                    </Td>
                                </Tr>
                            ))}
                        </Tbody>
                    </Table>
                    <SpinOverlay
                        progress={busy}
                        size="m"
                        position="center"
                        spinDelay={1500}
                    />
                </div>
                <Placeholder
                    cls={b('placeholder')}
                    description={i18n('dns_settings.no_records')}
                />
                {canEdit && (
                    <div className={b('actions')}>
                        <Button
                            cls={b('button', { type: 'add-record' })}
                            text={i18n('dns_settings.add_record')}
                            onClick={this._addRecord}
                            theme="action"
                            size="m"
                        />
                        <Link
                            cls={b('link', { type: 'help' })}
                            text={i18n('dns_settings.help')}
                            url={ConfigStore.get('ui.help.dns_editor')}
                            theme="normal"
                        />
                        <EditDnsRecordModal
                            domain={domain}
                            record={editedRecord}
                            visible={editRecordModalOpen}
                            onSubmit={this._onEditRecordSubmit}
                            onCancel={this._onEditRecordCancel}
                        />
                        <Modal
                            cls={b('remove-record-modal')}
                            visible={removeRecordModalOpen}
                        >
                            <Modal.Title>
                                {i18n('dns_record.title.confirm_removal')}
                            </Modal.Title>
                            <Modal.CloseButton onClick={this._cancelRecordRemoval} />
                            <Modal.Body>
                                {i18n('dns_record.message.confirm_removal')}
                            </Modal.Body>
                            <Modal.ConfirmActions
                                onConfirm={() => this._removeRecord(removedRecord)}
                                onCancel={this._cancelRecordRemoval}
                                confirmCaption={i18n('common.action.remove')}
                            />
                            <Modal.Busy visible={busyRemoving} />
                        </Modal>
                    </div>
                )}
            </div>
        );
    }
}
