import React, { Component } from 'react';
import PropTypes from 'prop-types';

import { connect } from 'react-redux';
import { prepareEntity, fetchEntity, saveEntity, deleteEntity, selector } from './redux.js';
import { download } from 'lib/backend';
import backendRequest from 'lib/backend';

import InvoiceItems from 'components/InvoiceItems';
import PaymentAccountList from 'components/PaymentAccountList';
import CustomerList from 'components/CustomerList';
import EntityStatus from 'components/EntityStatus';
import ExchangeRateFormFields, { exchangeRateFields, validateExchangeRate } from 'components/ExchangeRateFormFields';
import InvoiceEmailForm from 'components/InvoiceEmailForm';
import { AbstractForm, Title, ActivityIndicator, DetailButtons, Button, DetailTitle, Modal, ModalTitle, ModalContent, ModalButtonBar, ToolbarButton, Toolbar, ToolbarSection, ToolbarButtons, Alert, OptionalSection, LabeledValue, Tabs, Tab, ErrorBubble } from 'lib/components';
import { periodCheckDecorator } from 'containers/Params';

import form from 'lib/form';
import validator from 'lib/validator';
import { formatMoney, formatNumber, formatDate } from 'lib/i18n';

import icons from 'constants/icons';
import images from 'constants/images';
import Attachments from 'lib/attachment';
import Notifications from 'lib/notification';
import Tags from 'lib/tag';
import TemplateSelector from 'components/TemplateSelector';
import PaymentMethods from 'components/PaymentMethods';
import Toast from 'components/Toast';

import { calculateInvoice } from 'utils/calc';
import { fromJS } from 'immutable';

import { injectIntl } from 'react-intl';
import messages from './messages.js';
import commonMessages from '../../messages.js';

import barcodes from 'lib/barcodes';
import FileSaver, { saveAs } from 'file-saver';

import './style.scss';


const STATUSES = [ "DRAFT", "ISSUED", "PAID", "CANCELLED" ];

const PAYMENT_TYPES = [ "BANK_TRANSFER" ];


class InvoiceForm extends AbstractForm {


    constructor(props) {
        super(props);

        this.fetchCustomers = this.fetchCustomers.bind(this);
        this.getData = this.getData.bind(this);

        this.state = {
            accountsModal: false
        };
    }


    getData() {
        return this.props.data;
    }

    async fetchCustomers() {
        let unitId = this.props.unitId;
        let customers = [];
        try {
            let response = await backendRequest(`/api/${unitId}/customers`, "GET");
            customers = response.body;
        } catch(e) {
            console.error(e);
        }
        return customers;
    }


    renderAccountsModal() {
        let { accountsModal } = this.state;
        if (!accountsModal) {
            return null;
        }

        let { onChangeHandler } = this.props;

        return (
            <Modal show={ accountsModal } onClose={ () => this.setState({ accountsModal: false }) }>
                <h3>Select account</h3>
                <PaymentAccountList 
                    items={ this.props.unit.paymentAccounts || [] }
                    onSelected={ (account) => {
                        this.props.setValues(null, {
                            paymentAccount: account.accountNumber,
                            paymentIban: account.iban
                        });
                        this.setState({ accountsModal: false });
                    } }
                    />
            </Modal>
        );
    }


    renderSubjectFields(prefix, disabled, intl) {
        let fieldProps = { disabled };
        let fields = [];
        return (
            <div className="row row-margin-10">
                <div className="col-xs-12">
                    { this.renderField(`${prefix}Name`, intl.formatMessage(messages.customerName), fieldProps) }
                </div>
                <div className="col-xs-12">
                    { this.renderTextArea(`${prefix}Address`, intl.formatMessage(messages.customerAddress), fieldProps) }
                </div>
                <div className="col-xs-6">
                    { this.renderField(`${prefix}IdNumber`, intl.formatMessage(messages.customerIdNumber), fieldProps) }
                </div>
                <div className="col-xs-6">
                    { this.renderField(`${prefix}TaxNumber`, intl.formatMessage(messages.customerTaxNumber), fieldProps) }
                </div>
            </div>
        );
    }


    renderPaymentFields(disabled, intl) {
        let fieldProps = { disabled };
        let paymentTypes = [];
        for (let i = 0; i < PAYMENT_TYPES.length; i++) {
            paymentTypes.push({ value: PAYMENT_TYPES[i], label: PAYMENT_TYPES[i] });
        }
        return (
            <div className="pv10">
                <div className="form-field">
                    { this.renderToggleButtons("paymentType", "Payment Type", paymentTypes) }
                </div>
                { this.renderField("paymentAccount", intl.formatMessage({ id: "invoice.entity.paymentAccount" }), fieldProps) }
                { this.renderField("paymentIban", intl.formatMessage({ id: "invoice.entity.paymentIban" }), fieldProps) }
                { this.renderTextArea("paymentNote", intl.formatMessage({ id: "invoice.entity.paymentNote" }), fieldProps) }
                <div>
                    <button type="button" onClick={ () => this.setState({ accountsModal: true }) }>Select account</button>
                </div>
            </div>
        );
    }


    renderDateFields(disabled, intl) {
        let fieldProps = { disabled };
        return (
            <div className="mb20">
                {/* this.renderDateField("createdDate", "", fieldProps) */}
                { this.renderDateField("invoiceDate", intl.formatMessage(messages.invoiceDate), fieldProps) }
                { this.renderDateField("dueDate", intl.formatMessage(messages.dueDate), fieldProps) }
            </div>
        );
    }


    renderReferenceFields(disabled, intl) {
        let fieldProps = { disabled };
        return (
            <div>
            </div>
        );
    }


    renderNotesFields(disabled, intl) {
        let fieldProps = { disabled };
        return (
            <div className="box p10">
            </div>
        );
    }


    renderSummary(intl, valueOf, currencySymbol, i18n) {
        let tax = valueOf("tax");
        let taxDivs = [];
        if (tax) {
            //t.get("base")
            tax.forEach(t => taxDivs.push(<LabeledValue key={ t.get("taxType") } value={ formatMoney(t.get("tax"), currencySymbol, i18n) } label={ t.get("taxType") } />));
        }

        return (
            <div className="box p10 right">
                <div className="row row-margin-10">
                    <LabeledValue label="Total" value={ formatMoney(valueOf("totalAmount", 0), currencySymbol, i18n) } />
                    { taxDivs }
                    <LabeledValue label="Total Payable" value={ formatMoney(valueOf("totalPayable", 0), currencySymbol, i18n) } size="big" />
                </div>
            </div>
        );
    }


    render() {
        let { valueOf, onChangeHandler, i18n, invoiceId, attachments, taxTemplates, disabled, intl, unitId, unitCurrency, unitCurrencySymbol, errors, unit, data } = this.props;
        let exchangeRateEnabled = valueOf("enableExchangeRate", false);
        let currencySymbol = valueOf("currencySymbol", "");
        let edit = !!invoiceId;
        let fieldProps = {
            disabled: disabled
        };

        //TODO move somewhere else
        let previewData = {
            ...data
        };
        let paymentMethods = valueOf("paymentMethods");
        if (Array.isArray(paymentMethods)) {
            for (let i = 0; i < paymentMethods.length; i++) {
                let pm = paymentMethods[i];
                if (pm.type == "BANK_TRANSFER") {
                    
                }
            }
        }

        return (
            <div className={ this.props.className }>

                <Tabs className="mb20">
                    <Tab title={ intl.formatMessage(messages.tabInvoice) } className="container-max-900 form">
                        <div className="p10 mb20">

                            <div className="form">
                                <div className="row row-margin-10">
                                    <div className="col-sm-5 p10">
                                        { this.renderField("idNumber", intl.formatMessage(messages.invoiceNumber), { disabled, className: "big", required: true }) }
                                    </div>
                                </div>
                                <div className="row row-margin-10">
                                    <div className="col-sm-5 p10">
                                        { this.renderSelectModal("customer", intl.formatMessage(messages.customer), {
                                            disabled,
                                            fetchData: this.fetchCustomers,
                                            readInputValue: (v) => v ? v.name : "",
                                            renderList: (items, onChange, hide) => <CustomerList items={ items } onDetailClick={ (id, customer) => {
                                                this.props.setValues(null, {
                                                    customer: customer,
                                                    customerName: customer.name,
                                                    customerIdNumber: customer.idNumber,
                                                    customerTaxNumber: customer.taxNumber,
                                                    customerAddress: customer.address
                                                });
                                                hide();
                                            }  }/>
                                        }) }
                                        { this.renderSubjectFields("customer", disabled, intl) }
                                    </div>
                                    <div className="col-sm-2"/>

                                    <div className="col-sm-5 p10">
                                        { this.renderDateFields(disabled, intl) }
                                        <EntityStatus
                                            className="pv10"
                                            status={ valueOf("status") }
                                            dueDate={ valueOf("dueDate") }
                                            onStatusChange={ onChangeHandler("status", s => s) }
                                            paymentDate={ valueOf("paymentDate") }
                                            onPaymentDateChange={ onChangeHandler("paymentDate", s => s) }
                                            i18n={ i18n }
                                            />
                                    </div>
                                </div>
                            </div>

                            {/* TODO payment methods */}
                        </div>

                        <div className="p10 mb20">
                            <div className="pv10">
                                <InvoiceItems 
                                    className="table"
                                    items={ valueOf('items') }
                                    currencySymbol={ valueOf('currencySymbol', '') }
                                    onChange={ onChangeHandler('items', items => items, (items, values) => {
                                        //TODO use immutable to prevent to/from JS
                                        let invoice = calculateInvoice(values.toJS());
                                        return values.set("totalAmount", invoice.totalAmount).set("totalPayable", invoice.totalPayable).set("tax", fromJS(invoice.tax));
                                    }) }
                                    notificationsKey={ [ "invoiceDetail", "items", "form" ] }
                                    i18n={ i18n }
                                    taxTemplates={ taxTemplates }
                                    disabled={ disabled }
                                    />
                            </div>
                        </div>

                        <div className="p10 mb10">
                            <OptionalSection 
                                checked={ valueOf("includeNote") } 
                                onStatusChange={ onChangeHandler("includeNote", v => v) }
                                title={ intl.formatMessage(messages.note) }
                                disabled={ disabled }
                                >
                                { this.renderTextArea("note", null, fieldProps) }
                            </OptionalSection>
                        </div>

                        {/* tax summary + summary */}
                        <div className="row row-margin-10 form mb10">
                            <div className="row row-margin-10">
                                <div className="col-sm-6 p10">
                                </div>
                                <div className="col-sm-6 p10">
                                    { this.renderSummary(intl, valueOf, currencySymbol, i18n) }
                                </div>
                            </div>
                        </div>

                        <div className="p10 mb20">
                            {/* thank you note */}
                            <OptionalSection 
                                checked={ valueOf("includeThankYouNote") } 
                                onStatusChange={ onChangeHandler("includeThankYouNote", v => v) }
                                title={ intl.formatMessage(messages.thankYouMessage) }
                                disabled={ disabled }
                                >
                                { this.renderField("thankYouNote", null, fieldProps) }
                            </OptionalSection>
                        </div>
                    </Tab>

                    <Tab title={ intl.formatMessage(messages.tabExchangeRate) } className="container-max-900 form pv10" titleDecorator={ <ErrorBubble errors={ errors } fields={ exchangeRateFields } /> }>
                        <ExchangeRateFormFields form={ this } fieldProps={ fieldProps } intl={ intl } valueOf={ valueOf } onChangeHandler={ onChangeHandler } disabled={ disabled } unitCurrency={ unitCurrency } unitCurrencySymbol={ unitCurrencySymbol} />
                    </Tab>

                    <Tab title={ intl.formatMessage(messages.tabPaymentMethods) } className="container-max-900 form">
                        <PaymentMethods 
                            items={ valueOf("paymentMethods") } 
                            onChange={ this.props.onChangeHandler("paymentMethods", items => items) }
                            disabled={ disabled }
                            templates={ unit.paymentMethods }
                            />
                    </Tab>

                    <Tab title={ intl.formatMessage(messages.tabCustomization) } className="container-max-900 form">
                        <TemplateSelector 
                            unit={ unit } 
                            template={ valueOf("template") } 
                            onChangeTemplate={ onChangeHandler("template", v => v) }
                            templateLang={ valueOf("templateLang") }
                            defaultLang={ unit.locale }
                            onChangeLanguage={ onChangeHandler("templateLang", v => v) }
                            unitId={ unitId }
                            previewData={ valueOf() }
                            />
                    </Tab>

                    <Tab title={ intl.formatMessage(messages.tabNotifications) } className="container-max-900 form" disabled={ !invoiceId }>
                        <Notifications 
                            className="pv10"
                            unitId={ unitId } 
                            objectType="invoice" 
                            objectId={ invoiceId }
                            disabled={ !invoiceId }
                            imageUrls={ { google: images.googleCalendarLogo } }
                            />
                    </Tab>
                    <Tab title={ intl.formatMessage(messages.tabAttachments) } className="container-max-900 form" disabled={ !invoiceId }>
                        <Attachments 
                            className="pv10"
                            unitId={ unitId } 
                            objectType="invoice" 
                            objectId={ invoiceId }
                            disabled={ disabled || !invoiceId }
                            />
                    </Tab>
                </Tabs>

                { this.renderAccountsModal() }
            </div>
        );
    }

}

InvoiceForm = form(injectIntl(InvoiceForm), {
    onValidationFailed: Toast.validationFailed,
    validate: (invoice, error) => {
        let valid = true;
        if (!validator.required(invoice.idNumber)) {
            valid = false;
            error({ field: "idNumber",  code: "common.validation.requiredField" });
        }

        if (!validateExchangeRate(invoice, error)) {
            valid = false;
        }

        //state related validations
        switch(invoice.status) {
            case 'ISSUED':
            case 'PAID':

                if (!validator.required(invoice.currency)) {
                    valid = false;
                    error({ field: "currency",  code: "common.validation.requiredField" });
                }
                if (!validator.required(invoice.currency)) {
                    valid = false;
                    error({ field: "currency",  code: "common.validation.requiredField" });
                }

                break;
        }

        return valid;
    }
});





class InvoiceDetail extends Component {

    constructor(props) {
        super(props);

        this.handleBack = this.handleBack.bind(this);
        this.handleDelete = this.handleDelete.bind(this);
        this.handleSave = this.handleSave.bind(this);
        this.handleClone = this.handleClone.bind(this);

        this.handlePreview = this.handlePreview.bind(this);
        this.handlePdfDownload = this.handlePdfDownload.bind(this);
        this.prepareEmail = this.prepareEmail.bind(this);
        this.handleSendEmail = this.handleSendEmail.bind(this);

        this.state = {
            preview: false
        };
    }


    componentWillMount() {
        let id = this.props.params.invoiceId;
        if (id) {
            this.props.fetchEntity(this.props.unitId, id);
        } else {
            this.props.prepareEntity(this.props.unit);
        }
    } 


    handleBack() {
        let { onBack, backPath, route } = this.props;
        if (typeof onBack === "function") {
            return onBack();
        }
        if (backPath) {
            return this.context.router.push(backPath);
        }
        if (route && route.backRoute) {
            return this.context.router.push(route.backRoute);
        }
        this.context.router.push('/income');
    }


    handleSave(data) {
        let { periodParams, intl, route, i18n } = this.props;
        periodCheckDecorator(async () => {
            let id = this.props.params.invoiceId;
            try {
                data = await this.props.saveEntity(this.props.unitId, data.id, data);
                Toast.saved();
                if (!id) {
                    if (route && route.successRoute) {
                        this.context.router.push(`${route.successRoute}/${data.value.body.id}`);
                    } else {
                        this.context.router.push(`/invoices/${data.value.body.id}`);
                    }
                }
            } catch (e) {
                Toast.error(e);
            }
        }, {
            periodParams,
            date: data.invoiceDate,
            intl,
            i18n
        });
    }


    handleDelete() {
        let intl = this.props.intl;
        Alert.alert(
            intl.formatMessage(messages.deleteTitle), 
            intl.formatMessage(messages.deleteQuestion), 
            [
                { text: intl.formatMessage(commonMessages.buttonNo) }, 
                { text: intl.formatMessage(commonMessages.buttonYes), primary: true, onPress: async () => {
                    try {
                        await this.props.deleteEntity(this.props.unitId, this.props.params.invoiceId);
                        this.handleBack();
                        Toast.deleted();
                    } catch (e) {
                        Toast.error(e);
                    }
                }
            }]
        );
    }

    async handlePreview() {
        let { unitId } = this.props;
        let data = this.refs.form.getData();
        let response = await backendRequest(`/api/${unitId}/invoice/html`, "POST", { body: data, parseResponse: x => x });

        this.setState({ preview: true });
        
        let doc = document.getElementById('invoicePreview').contentWindow.document;
        doc.open();
        doc.write(response.body);
        doc.close();
    }

    async handlePdfDownload() {
        let id = this.props.params.invoiceId;
        let { unitId, unit, intl } = this.props;
        let invoice = this.refs.form.getData();

        try {
            let invoice = this.refs.form.getData();
            let response = await backendRequest(`/api/${unitId}/invoices/${id}/pdf`, 'POST', { body: invoice, handleResponse: r => r });
            let blob = await response.blob();
            FileSaver.saveAs(blob, intl.formatMessage(messages.fileName, { idNumber: invoice.idNumber || "" }));

        } catch(e) {
            console.error(e);
        }
        
    }

    async handleClone() {
        let { unitId, route, intl } = this.props;
        let data = this.refs.form.getData();
        try {
            let response = await backendRequest(`/api/${unitId}/invoices/clone`, "POST", { body: data });

            let invoice = response.body;

            if (invoice && invoice.id) {
                Toast.saved();
                this.context.router.push(`/invoices/${invoice.id}`);
                this.props.fetchEntity(unitId, invoice.id);
            }
        } catch (e) {
            console.error(e);
            Toast.error(e);
        }
    }


    async prepareEmail() {
        let id = this.props.params.invoiceId;
        let unitId = this.props.unitId;

        let email = {};
        try {
            this.setState({ emailForm: true, emailPending: true });
            let response = await backendRequest(`/api/${unitId}/invoices/${id}/email`, "GET");
            email = response.body;
        } catch(e) {
            console.error(e);
        }
        this.setState({ emailPending: false, emailData: email });
    } 


    async handleSendEmail(email) {
        let intl = this.props.intl,
            unitId = this.props.unitId, 
            invoiceId = this.props.params.invoiceId;
        try {
            this.setState({ emailPending: true });
            await backendRequest(`/api/${unitId}/invoices/${invoiceId}/email`, "POST", { body: email });
            Toast.emailSent();
            this.setState({ emailForm: false });
        } catch (e) {
            Toast.error(e);
            console.error(e);
        }
        this.setState({ emailPending: false });
    }


    render() {
        let id = this.props.params.invoiceId;
        let intl = this.props.intl;
        let edit = !!id;
        let
            unit = this.props.unit,
            status = this.props.status,
            pending = !!(status && ( status.isFetching || status.isSaving || status.isDeleting)),
            disabled = false;


        return (
            <div className="pv10">
                <Toolbar>
                    <ToolbarSection>
                        <DetailTitle 
                            title={ intl.formatMessage(edit ? messages.editTitle : messages.newTitle) }
                            titleIcon={ icons.invoice }
                            />
                    </ToolbarSection>
                    <ToolbarButtons>
                        <ToolbarButton 
                            label={ intl.formatMessage(messages.backButton) } 
                            onClick={ this.handleBack }
                            >
                            <span className="icon">{ icons.back }</span>
                        </ToolbarButton>
                        <ToolbarButton 
                            label={ intl.formatMessage(messages.deleteButton) } 
                            onClick={ this.handleDelete }
                            disabled={ !id || pending }
                            >
                            <span className="icon">{ icons.delete }</span>
                        </ToolbarButton>
                        <ToolbarButton 
                            label={ intl.formatMessage(messages.pdfButton) } 
                            onClick={ this.handlePdfDownload }
                            disabled={ !id || pending }
                            >
                            <span className="icon">{ icons.pdf }</span>
                        </ToolbarButton>
                        <ToolbarButton 
                            label={ intl.formatMessage(messages.emailButton) } 
                            onClick={ this.prepareEmail }
                            disabled={ !id || pending }
                            >
                            <span className="icon">{ icons.email }</span>
                        </ToolbarButton>
                        {/*
                        <ToolbarButton 
                            label={ intl.formatMessage(messages.cloneButton) } 
                            onClick={ this.handleClone }
                            disabled={ !id || pending }
                            >
                            <span className="icon">{ icons.copy }</span>
                        </ToolbarButton>
                        */}
                        <ToolbarButton 
                            label={ intl.formatMessage(messages.saveButton) } 
                            onClick={ () => this.refs.form.submit(this.handleSave) }
                            disabled={ pending }
                            >
                            <span className="icon">{ icons.save }</span>
                        </ToolbarButton>
                    </ToolbarButtons>
                </Toolbar>

                <InvoiceForm 
                    ref="form"
                    data={ this.props.data } 
                    unit={ this.props.unit }
                    unitCurrency={ this.props.unit.currency }
                    unitCurrencySymbol={ this.props.unit.currencySymbol }
                    i18n={ this.props.i18n }
                    taxTemplates={ this.props.unit.taxTemplates }             

                    onSubmit={ this.handleSave }

                    invoiceId={ id }
                    unitId={ this.props.unitId }   
                    intl={ this.props.intl }

                    disabled={ pending || disabled }/>

                <Modal show={ this.state.preview } >
                    <ModalButtonBar>
                        <button onClick={ () => this.setState({ preview: false }) }>{ intl.formatMessage({ id: "common.button.close" }) }</button>
                    </ModalButtonBar>
                    <ModalContent>
                        <iframe id="invoicePreview" className="invoice-preview"></iframe>
                    </ModalContent>
                </Modal>

                <Modal show={ this.state.emailForm } closeButton onClose={ () => this.setState({ emailForm: false }) } size="big" dismissButton>
                    <ModalTitle>{ intl.formatMessage(messages.sendEmailTitle) }</ModalTitle>
                    <ModalContent>
                        <InvoiceEmailForm ref="emailForm" disabled={ this.state.emailPending } data={ this.state.emailData || {} } onSubmit={ this.handleSendEmail }/>
                    </ModalContent>
                    <ModalButtonBar>
                        <button
                            onClick={ () => this.setState({ emailForm: false }) }
                            disabled={ pending || this.state.emailPending }>{ intl.formatMessage(commonMessages.buttonCancel) }</button>
                        <button 
                            onClick={ () => this.refs.emailForm.submit() }
                            className="primary" disabled={ pending || this.state.emailPending }>{ intl.formatMessage(commonMessages.buttonSend) }</button>
                    </ModalButtonBar>
                    <ActivityIndicator show={ this.state.emailPending } type="overlay"/>
                </Modal>
                <ActivityIndicator show={ pending } type="overlay" />
            </div>
        );
    }

}

InvoiceDetail.contextTypes = {
    router: PropTypes.object.isRequired
};




function mapDispatchToProps(dispatch, props) {
    return {
        dispatch,
        prepareEntity: (unit) => dispatch(prepareEntity(unit)),
        fetchEntity: (unitId, id) => dispatch(fetchEntity(id, { unitId })),
        saveEntity: (unitId, id, data) => dispatch(saveEntity(id, data, { unitId })),
        deleteEntity: (unitId, id) => dispatch(deleteEntity(id, { unitId }))
    };
}


export default injectIntl(connect(selector, mapDispatchToProps)(InvoiceDetail));
