import React, { PureComponent } from 'react';

import { Alert, Modal, ModalTitle, ModalContent, ToggleButtons, Table } from 'lib/components';

import icons from 'constants/icons';

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

import backendRequest from 'lib/backend';
import handlebars from 'lib/handlebars';
import { paymentQRCode, codabarCode } from 'lib/barcodes';

import './style.scss';

//TODO refactor to be more versatile



class TemplateSelector extends PureComponent {


    constructor(props) {
        super(props);
        this.state = {
            editor: false,
            selectedTemplate: null
        };

        this.fetchTemplates = this.fetchTemplates.bind(this);
        this.renderEditor = this.renderEditor.bind(this);
        this.renderTemplate = this.renderTemplate.bind(this);
        this.selectTemplate = this.selectTemplate.bind(this);
        this.renderPreview = this.renderPreview.bind(this);
        this.changeLang = this.changeLang.bind(this);
        this.saveUnitLabels = this.saveUnitLabels.bind(this);
    }


    componentWillMount() {
        this.fetchTemplates(this.props.unitId, this.props.template);
    }

    componentWillReceiveProps(props) {
        if (props.unitId != this.props.unitId) {
            this.fetchTemplates(props.unitId, props.template);    
        }
    }


    async fetchTemplates(unitId, templateId) {
        try {
            let { body } = await backendRequest(`/api/${unitId}/templates`);
            if (Array.isArray(body)) {
                let templates = body.slice();
                let selectedTemplate = false;
                let templateChanged = false;

                for (let i = 0; i < body.length; i++) {
                    if (body[i].code == templateId && (!selectedTemplate || selectedTemplate.id != templateId)) {
                        selectedTemplate = body[i];
                        templateChanged = true;
                        break;
                    }
                }

                if (!selectedTemplate && templates.length) {
                    selectedTemplate = templates[0];
                    templateChanged = true;
                }

                this.setState({ templates });
                if (templateChanged) {
                    this.selectTemplate(selectedTemplate);
                }
            }
        } catch (e) {
            console.error(e);
        }
    }


    async selectTemplate(template) {
        let { unitId, templateLang, defaultLang } = this.props;
        let { onChangeTemplate, onChangeLanguage, onChange, intl } = this.props;

        try {
            let compiledTemplate = handlebars.compile(template.template);
            let labelsData = await selectTemplateLabels(unitId, template.id, templateLang, defaultLang, intl);

            //TODO refactor
            typeof onChangeTemplate == "function" && onChangeTemplate(template.code);
            if (typeof onChangeLanguage == "function" && labelsData.defaultLanguage != templateLang) {
                onChangeLanguage(labelsData.defaultLanguage);
            }

            this.setState({ selectedTemplate: { id: template.id, template, ...labelsData }, compiledTemplate });
            this.renderPreview(labelsData.labels);
        } catch (e) {
            console.error(e);
        }
    }

    changeLang(lang) {
        let { selectedTemplate } = this.state;
        let { onChangeLanguage } = this.props;

        let labels = lang == '_' ? selectedTemplate.unitLabels : selectedTemplate.languages[lang];
        typeof onChangeLanguage == "function" && onChangeLanguage(lang);
        this.setState({ selectedTemplate: { ...selectedTemplate, defaultLanguage: lang, labels } });
        this.renderPreview(labels);
    }

    renderTemplate(template) {
        let { selectedTemplate } = this.state;
        if (!template || !template.code) {
            return null;
        }
        return (
            <div key={ template.id } className={ `flex-list-row ${selectedTemplate != null && selectedTemplate.id == template.id ? " selected" : ""}` }>
                <div className="content">
                    <div className="list-row-data">
                        <div className="record-type">
                            <div className="icon">
                                { icons.invoice }
                            </div>
                            <div className="date"></div>
                        </div>
                        <div className="main">
                            <div className="main-value">
                                { template.name }
                            </div>
                            <div className="additional-info">
                                { template.code }
                            </div>
                        </div>
                    </div>
                </div>
                <div className="actions">
                     <button className="icon" onClick={ () => this.selectTemplate(template) }>{icons.leftMenu}</button>
                </div>


            </div>
        );
    }

    async renderPreview(labels, callback) {
        let { previewData = DATA, unit } = this.props;
        let { compiledTemplate, selectedTemplate } = this.state;
        if (!compiledTemplate) {
            return "";
        }

        try {
            //init
            if (previewData != this.state.previewData) {
                //TODO compile bar codes
                if (previewData && Array.isArray(previewData.paymentMethods)) {
                    for (let i = 0; i < previewData.paymentMethods.length; i++) {
                        let pm = previewData.paymentMethods[i];
                        if (pm.bankIban) {
                            let code = await paymentQRCode(pm.bankIban, previewData.totalPayable, previewData.currency, null, previewData.idNumber);
                            pm.dataUrl = code;
                        }
                    }
                }

                if (previewData && previewData.idNumber) {
                    previewData.idCode = await codabarCode(previewData.idNumber);
                }
            }

            let html = compiledTemplate({ 
                invoice: previewData || {}, 
                ctx: unit || { currencySymbol: '€', currency: 'EUR', unitCurrency: 'CZK', unitCurrencySymbol: 'Kč', thousandDelimiter: " " }, 
                idCode: previewData && previewData.idCode,
                tax: true, //TODO
                exchangeRate: false, //TODO
                labels 
            });

            typeof callback === "function" ? callback(html) : this.setState({ html, previewData });
        } catch (e) {
            console.error(e);
        }
    }


    renderEditor() {
        let { unitId, templateLang, defaultLang, intl } = this.props;
        let { editor, selectedTemplate } = this.state;

        if (selectedTemplate == null) {
            return null;
        }

        //use "default" labels when not initialized
        let unitLabels = selectedTemplate.unitLabels || {};
        if (!unitLabels || !Object.keys(unitLabels).length) {
            unitLabels = {};

            if (selectedTemplate.languages[templateLang]) {
                unitLabels = { ...selectedTemplate.languages[templateLang] };
            } else if (selectedTemplate.languages[defaultLang]) {
                unitLabels = { ...selectedTemplate.languages[defaultLang] };
            } else {
                unitLabels = {};
            }
        }
        selectedTemplate.unitLabels = unitLabels;

        return (
            <Modal show={ editor } closeButton onClose={ () => this.setState({ editor: false }) } size="fullscreen" className="xxx">
                <ModalTitle />
                <ModalContent >
                    <TemplateEditor 
                        templateId={ selectedTemplate.id } 
                        unitId={ unitId } 
                        onSave={ this.saveUnitLabels } 
                        data={ DATA }
                        renderTemplate={ this.renderPreview }
                        defaultLang={ templateLang == '_' ? defaultLang : (templateLang || defaultLang) }
                        { ...selectedTemplate }
                        labels={ unitLabels }
                        intl={ intl }
                        />
                </ModalContent>
            </Modal>
        )
    }

    saveUnitLabels(labels) {
        let { intl } = this.props;
        let { selectedTemplate } = this.state;
        let { options = [] } = selectedTemplate;
        let add = true;
        for (let i = 0; i < options.length; i++) {
            if (options[i].value == "_") {
                add = false;
                break;
            }
        }
        if (add) {
            options.unshift({ value: '_', label: intl.formatMessage(messages.unitLabels) });
        }

        this.setState({ selectedTemplate: { ...selectedTemplate, unitLabels: labels, defaultLanguage: "_" }, editor: false }, () => {
            this.changeLang("_");
        });
    }

    render() {
        let { value, onChange, unitId, className, editable = true } = this.props;
        let { editor, selectedTemplate, templates, html } = this.state;

        return (
            <div className={ `TemplateSelector ${className}` }>
                <div className="list">
                    { Array.isArray(templates) && templates.map(this.renderTemplate) }
                </div>
                { selectedTemplate ? (
                    <div className="preview">
                        <div className="paper">
                            <div dangerouslySetInnerHTML={{ __html: html }}/>
                        </div>
                        <div className="mb20 p10">
                            <ToggleButtons 
                                options={ selectedTemplate.options } 
                                value={ selectedTemplate.defaultLanguage } 
                                onChange={ this.changeLang }
                                simpleValue 
                                />
                            <button type="button" onClick={ () => this.setState({ editor: true }) }>Translate template</button>
                        </div>
                    </div>
                ) : <div className="preview"/> }
                { editable && editor ? this.renderEditor() : null }
            </div>
        );
    }

}


export default injectIntl(TemplateSelector);


class TemplateEditor extends React.PureComponent {

    constructor(props) {
        super(props);
        this.state = {
            fields: {},
            labels: null
        };

        this.initData = this.initData.bind(this);
        this.saveLabels = this.saveLabels.bind(this);
        this.renderLabel = this.renderLabel.bind(this);
        this.switchLang = this.switchLang.bind(this);
    } 


    componentWillMount() {
        this.initData(this.props)
    }


    componentWillReceiveProps(props) {
        if (this.props.templateId != props.templateId || this.props.unitId != props.unitId || this.props.defaultLanguage != props.defaultLanguage) {
            this.initData(props);
        }
    }

    initData({ codes, languages = {}, labels, defaultLang }) {
        this.setState({ codes, languages, labels, defaultLanguage: defaultLang, options: Object.keys(languages).map(v => ({ value: v, label: v })) });
    }


    async saveLabels() {
        let { unitId, templateId, defaultLanguage, onSave } = this.props;
        let { labels } = this.state;

        try {
            await backendRequest(`/api/${unitId}/templates/${templateId}/labels`, "PUT", {
                body: labels || []
            });
            if (typeof onSave === "function") {
                onSave(labels);
            } else {
                await this.initData(unitId, templateId, defaultLanguage);
            }
        } catch (e) {
            console.error(e);
        }
    }


    switchLang(lang) {
        let { languages, labels } = this.state;
        let { intl } = this.props;

        this.setState({ defaultLanguage: lang });

        Alert.alert(
            intl.formatMessage(messages.changeLangAlertTitle), 
            intl.formatMessage(messages.changeLangAlertQuestion), 
            [
                { text: intl.formatMessage({ id: "common.button.no" }) }, 
                { text: intl.formatMessage({ id: "common.button.yes" }), primary: true, onPress: () => {
                        
                        let langs = Object.keys(languages);
                        for (let i = 0; i < langs.length; i++) {
                            if (langs[i] == lang) {
                                labels = { ...languages[lang] };
                                break;
                            }
                        }
                        this.setState({ labels: { ...labels } });
                }
            }]
        );
    }


    changeLabel(code, e) {
        let { labels = {} } = this.state;
        labels[code] = e.target.value;

        this.setState({ labels: { ...labels } });
    }

    renderLabel(code, idx) {
        let { codes, languages = {}, labels, defaultLanguage } = this.state;
        return (
            <div key={ `${code}_${idx}` } className="mb10">
                <input value={ labels[code] || "" } onChange={ this.changeLabel.bind(this, code) } />
                <div className="label-hint">
                    { languages[defaultLanguage || "en"][code] }
                </div>
            </div>
        )
    }


    render() {
        let { data = {}, renderTemplate } = this.props;
        let { codes, languages = {}, labels, defaultLanguage, options, html } = this.state;
        
        return (
            <div className="">
                <div className="mb20 pv10">
                    <ToggleButtons 
                        options={ options } 
                        value={ defaultLanguage } 
                        onChange={ this.switchLang }
                        simpleValue 
                        />
                </div>
                <div className="label-fields">
                    { codes && codes.map(this.renderLabel) }
                </div>
                <div>
                    <button type="button" onClick={ this.saveLabels }>Save</button>
                </div>
                <div className="TemplateSelector paper">
                    <div dangerouslySetInnerHTML={{ __html: html }}/>
                </div>
            </div>
        );
    }

}


export async function fetchTemplates(unitId) {
    let { body } = await backendRequest(`/api/${unitId}/templates`);
    return body || [];
}


//FIXME
export async function selectTemplateLabels(unitId, templateId, lang, defaultLang, intl) {
    let { body } = await backendRequest(`/api/${unitId}/templates/${templateId}/labels`);
    
    let 
        options = [],
        labels = {}, 
        langs = null,
        defaultLanguage = null;

    if (lang == "_" && !(body.unitLabels && Object.keys(body.unitLabels).length)) {
        lang = defaultLang || "en";
    }

    if (body.languages) {
        langs = Object.keys(body.languages);
        for (let i = 0; i < langs.length; i++) {
            if (langs[i] == lang) {
                defaultLanguage = lang;
                labels = { ...body.languages[lang] };
                break;
            }
        }
        
        options = Object.keys(body.languages).map(lang => ({ label: lang, value: lang }));
    }

    if (body.unitLabels && Object.keys(body.unitLabels).length) {
        options.unshift({ value: '_', label: intl && intl.formatMessage(messages.unitLabels) });

        if (lang == "_") {
            defaultLanguage = "_";
            for (let code in body.unitLabels) {
                labels[code] = body.unitLabels[code];
            }
        }
    }


    return { ...body, labels, defaultLanguage, options };
}



const DATA = JSON.parse("{\"id\":965,\"version\":50,\"unitId\":1,\"idNumber\":\"201710001\",\"status\":\"PAID\",\"billableStatus\":\"finished\",\"paymentType\":\"BANK_TRANSFER\",\"paymentAccount\":\"1135914031/3030\",\"paymentIban\":\"CZ8130300000001135914031\",\"paymentNote\":\"3030\",\"paymentBankName\":\"Airbank\",\"paymentDate\":\"2017-11-21\",\"customer\":{\"id\":938,\"version\":46,\"unitId\":1,\"name\":\"Hays Information Technology s.r.o.\",\"idNumber\":\"05311268\",\"taxNumber\":\"CZ05311268\",\"address\":\"Olivova 2096/4\\nPraha - Nové Město\\n110 00\",\"invoiceEmailSubject\":\"${subject_name} - Faktura ${id_number}\",\"invoiceEmailMessage\":\"Dobrý den, \\n\\nv příloze Vám zasílám fakturu číslo ${id_number} na částku ${total_payable}. Faktura je splatná dne ${due_date}. \\n\\nDěkuji\\n\",\"invoiceEmailTitle\":\"Faktura ${id_number}\",\"invoiceEmail\":\"contracting@hays.cz\",\"contacts\":null},\"customerName\":\"Hays Information Technology s.r.o.\",\"customerIdNumber\":\"05311268\",\"customerTaxNumber\":\"CZ05311268\",\"customerAddress\":\"Olivova 2096/4, \\nPraha - Nové Město,\\n110 00\",\"subjectName\":\"Jan Hrabal\",\"subjectIdNumber\":\"75386771\",\"subjectTaxNumber\":\"CZ8407194114\",\"subjectAddress\":\"Prostřední 2249\\nZlín\\n760 01\",\"includeNote\":true,\"note\":\"\",\"includeThankYouNote\":true,\"thankYouNote\":\"Děkujeme Vám za využívání našich služeb\",\"createdDate\":\"2017-10-31\",\"invoiceDate\":\"2017-10-31\",\"dueDate\":\"2017-11-17\",\"currency\":\"EUR\",\"currencySymbol\":\"€\",\"totalAmount\":7411.140000,\"totalPayable\":8967.480000,\"enableExchangeRate\":true,\"exchangeRate\":25.670000,\"exchangeRateDate\":\"2017-10-31\",\"exchangeRateSource\":\"ČNB\",\"qrPaymentCode\":true,\"uuid\":\"DZZob\",\"items\":[{\"id\":966,\"name\":\"Práce na projektu pro DHL Information Services za období 1.10. - 31.10.2017\",\"uom\":\"MD\",\"priceUom\":342.000000,\"pieces\":22.000000,\"amount\":7524.000000,\"taxItems\":[{\"id\":1255,\"flat\":false,\"taxType\":\"DPH 21%\",\"taxPercent\":21.000000,\"base\":7524.000000,\"tax\":1580.040000}]},{\"id\":967,\"name\":\"Poskytnutá sleva 1.5% dle smlouvy\",\"uom\":\"\",\"priceUom\":-112.860000,\"amount\":-112.860000,\"taxItems\":[{\"id\":1253,\"flat\":false,\"taxType\":\"DPH 21%\",\"taxPercent\":21.000000,\"base\":-112.860000,\"tax\":-23.700000}]}],\"taxItems\":[],\"tax\":[{\"id\":2240,\"taxType\":\"DPH 21%\",\"taxAmount\":0.000000,\"base\":7411.140000,\"tax\":1556.340000,\"baseInUnitCurrency\":190243.96,\"taxInUnitCurrency\":39951.25}],\"totalAmountInUnitCurrency\":190243.963800000000,\"totalPayableInUnitCurrency\":230195.211600000000}");
