import _ from 'lodash';
import PropTypes from 'prop-types';
import React from 'react';
import Select from 'react-bem-components/lib/Select';
import FormMixin from 'lib/FormMixin';
import { i18n } from 'lib/i18n';
import Metrika from 'lib/metrika';

import DnsActions from 'actions/Dns';
import DnsStore from 'stores/Dns';

import Form from 'ui/Form';
import Button from 'lego-ui/Button';
import Input from 'ui/Input';

import FieldSchema from './fields';

const RECORD_TYPES = [
    'A',
    'CNAME',
    'AAAA',
    'TXT',
    'NS',
    'MX',
    'SRV',
].map(x => ({ val: x, text: x }));

const ButtonActionMap = {
    create: 'common.action.create',
    edit: 'common.action.update',
};

const StatusMap = {
    create: {
        success: 'dns_record.status.created',
        failure: 'dns_record.status.failed_to_create',
    },
    edit: {
        success: 'dns_record.status.updated',
        failure: 'dns_record.status.failed_to_update',
    },
};

const Edit = React.createClass({

    mixins: [FormMixin],

    getInitialState() {
        // по аналогии с реализацией api dns-хостинга:
        // если в props указан id записи, редактируем запись с этим id;
        // если не указан id, создаём новую запись
        // (сервер сгененерит для неё id после сохранения)
        const mode = this.props.recordId ? 'edit' : 'create';

        let { recordType } = this.props;

        if (mode === 'create' && !recordType) {
            recordType = RECORD_TYPES[0].val;
        }

        return {
            mode,
            recordType,
        };
    },

    _getRecord() {
        const { recordId } = this.props;

        if (recordId) {
            const record = DnsStore.get(recordId);

            if (record) {
                return record.toJS();
            }
        }
    },

    _getErrors() {
        const { errors } = this.state;

        return errors ? errors.toJS() : {};
    },

    _handleSubmit(data) {
        const { recordType, mode } = this.state;
        const errors = this._checkInput(data);

        if (errors) {
            return this._setErrors(errors);
        }

        this._preprocessInput(data);

        Metrika.send('DNS', 'Форма редактирования', 'Сохранить');

        this.setState({ busy: true });

        this._submit(DnsActions.submitRecord(this.props.domain, data), {
            success: i18n(StatusMap[mode].success, { type: recordType }),
            failure: i18n(StatusMap[mode].failure, { type: recordType }),
        })
            .then(() => {
                this.setState({ busy: false });
            });
    },

    _checkInput(data) {
        const { recordType } = this.state;
        const errors = {};

        if (data.type === 'SRV' && !data.name) {
            errors.name = i18n('dns_validation.empty');
        }

        if (!data.ttl) {
            errors.ttl = i18n('dns_validation.empty');
        } else if (!/^\d+$/.test(data.ttl)) {
            errors.ttl = i18n('dns_validation.must_be_number');
        }

        (FieldSchema[recordType] || []).forEach(item => {
            const { name, type } = item;
            const value = _.get(data, ['rdata', name]);

            let message;

            if (value === '') {
                message = i18n('dns_validation.empty');
            } else if (type === 'number' && !/^\d+$/.test(value)) {
                message = i18n('dns_validation.must_be_number');
            }

            if (message) {
                _.set(errors, ['rdata', name], message);
            }
        });

        return Object.keys(errors).length === 0 ? null : errors;
    },

    _preprocessInput(data) {
        const { recordType } = this.state;

        if (!FieldSchema[recordType] || !data || !data.rdata) {
            return data;
        }

        if (data.ttl === '') {
            delete data.ttl;
        } else {
            data.ttl = Number(data.ttl);
        }

        FieldSchema[recordType].forEach(item => {
            const { name, type, toServerFormat } = item;

            if (type === 'number') {
                data.rdata[name] = Number(data.rdata[name]);
            }

            if (toServerFormat) {
                data.rdata[name] = toServerFormat(data.rdata[name]);
            }
        });

        return data;
    },

    _handleTypeChange(payload) {
        this.setState({
            recordType: payload.value,
        });
    },

    _renderFields() {
        const { recordType } = this.state;

        if (!FieldSchema[recordType]) {
            return;
        }

        const record = this._getRecord() || {};
        const { rdata = {} } = record;

        const errors = this._getErrors();
        const fields = {};

        ['name', 'ttl'].forEach(key => {
            fields[key] = (
                <Form.Item
                    label={i18n(`dns_record.${key}`)}
                    key={key}
                    required={key === 'ttl' || (recordType === 'SRV' && key === 'name')}
                    errors={errors[key]}
                >
                    <Input
                        name={key}
                        val={record[key]}
                        hasClear
                        size="l"
                        autoComplete={false}
                        width="available"
                    />
                </Form.Item>
            );
        });

        return [
            fields.name,
            // стандартные RDATA-поля DNS-записи
            ...FieldSchema[recordType].map(item => {
                const { name, toClientString } = item;
                let value = rdata[name];

                if (toClientString) {
                    value = toClientString(value);
                }

                return (
                    <Form.Item
                        label={item.label_content || i18n(`dns_record.${item.label_key || name}`)}
                        key={name}
                        required
                        errors={errors.rdata && errors.rdata[name]}
                    >
                        <Input
                            name={`rdata[${name}]`}
                            val={value}
                            hasClear
                            size="l"
                            autoComplete={false}
                            width="available"
                        />
                    </Form.Item>
                );
            }),
            fields.ttl,
        ];
    },

    render() {
        const { props, state } = this;
        const components = {};

        const errors = this._getErrors();

        const title = i18n(`dns_record.${state.mode}`, {
            domain: props.domain,
            type: state.recordType,
        });

        if (props.recordId) {
            components.recordId = (
                <input
                    type="hidden"
                    name="id"
                    value={props.recordId}
                />
            );
        }

        // если создаём новую запись и тип создаваемой записи не предустановлен
        // через props, показываем селект для выбора типа записи
        if (state.mode === 'create' && !props.recordType) {
            components.recordType = (
                <Form.Item
                    label={i18n('dns_record.type')}
                    required
                >
                    <Select
                        name="type"
                        mode="radio"
                        options={RECORD_TYPES}
                        width="available"
                        size="l"
                        onChange={this._handleTypeChange}
                    />
                </Form.Item>
            );
        } else {
            components.recordType = (
                <input
                    type="hidden"
                    name="type"
                    value={state.recordType}
                />
            );
        }

        return (
            <Form
                className="dns-form form"
                onSubmit={this._handleSubmit}
                autoComplete={false}
            >
                <Form.Title>{title}</Form.Title>
                {components.recordId}
                {components.recordType}
                {this._renderFields()}
                <Form.Error
                    value={errors._common}
                    mod="standalone"
                />
                <Form.Buttons mod="aligned">
                    <Button
                        text={i18n(ButtonActionMap[state.mode])}
                        view="action"
                        type="submit"
                        disabled={state.busy}
                    />
                    <Button
                        text={i18n('common.action.cancel')}
                        onClick={props.onCancel}
                    />
                </Form.Buttons>
            </Form>
        );
    },

});

Edit.propTypes = {
    recordId: PropTypes.string,
    recordType: PropTypes.string,
    onCancel: PropTypes.func,
};

export default Edit;
