import com.gridnine.xtrip.common.Environment
import com.gridnine.xtrip.common.l10n.model.LocaleHelper
import com.gridnine.xtrip.common.l10n.model.Number2WordsConverter
import com.gridnine.xtrip.common.l10n.model.Number2WordsConverterRegistry
import com.gridnine.xtrip.common.model.EntityReference
import com.gridnine.xtrip.common.model.booking.OperationBatch
import com.gridnine.xtrip.common.model.dict.*
import com.gridnine.xtrip.common.model.entity.EntityStorage
import com.gridnine.xtrip.common.model.helpers.DictHelper
import com.gridnine.xtrip.common.model.helpers.ProfileHelper
import com.gridnine.xtrip.common.model.profile.*
import com.gridnine.xtrip.common.reports.model.AirTicketsTemplateReportTicket
import com.gridnine.xtrip.common.search.SearchCriterion
import com.gridnine.xtrip.common.search.SearchQuery
import com.gridnine.xtrip.common.search.SortOrder
import com.gridnine.xtrip.common.util.MiscUtil
import com.gridnine.xtrip.common.util.TextUtil
import com.gridnine.xtrip.common.util.ValueHolder

import java.text.SimpleDateFormat

createStyle(name: "left", h_alignment: "LEFT", fontFamily: "TimesNewRoman", fontHeight: 11)
createStyle(name: "left-italic", h_alignment: "LEFT", fontItalic: true, fontFamily: "TimesNewRoman", fontHeight: 11)
createStyle(name: "center-bold", h_alignment: "CENTER", fontBold: true, fontHeight: 16, fontFamily: "TimesNewRoman")
createStyle(name: "left-border", h_alignment: "LEFT", v_alignment: "CENTER", topBorder: 'THIN', rightBorder: 'THIN', leftBorder: 'THIN', bottomBorder: 'THIN', wrapText: true, fontFamily: "TimesNewRoman", fontHeight: 12)
createStyle(name: "right-border", h_alignment: "RIGHT", v_alignment: "CENTER", format: '#,##0.00', topBorder: 'THIN', rightBorder: 'THIN', leftBorder: 'THIN', bottomBorder: 'THIN', wrapText: true, fontFamily: "TimesNewRoman", fontHeight: 12)
createStyle(name: "left-bold-border", h_alignment: "LEFT", v_alignment: "CENTER", fontBold: true, topBorder: 'THIN', rightBorder: 'THIN', leftBorder: 'THIN', bottomBorder: 'THIN', wrapText: true, fontFamily: "TimesNewRoman", fontHeight: 12)
createStyle(name: "center-border", h_alignment: "CENTER", v_alignment: "CENTER", topBorder: 'THIN', rightBorder: 'THIN', leftBorder: 'THIN', bottomBorder: 'THIN', wrapText: true, fontFamily: "TimesNewRoman", fontHeight: 12)
createStyle(name: "center-bold-border", h_alignment: "CENTER", v_alignment: "CENTER", fontBold: true, topBorder: 'THIN', rightBorder: 'THIN', leftBorder: 'THIN', bottomBorder: 'THIN', wrapText: true, fontFamily: "TimesNewRoman", fontHeight: 12)


def fillSheet() {
    ValueHolder<String> currencyHolder = new ValueHolder<>("")
    fillContactData()
    fillHeader(currencyHolder)
    fillTable(currencyHolder)
    fillSignature()
}

def fillContactData() {
    rowHeight(14)
    EntityReference<Organization> agency = parameters['key-report-params']?.agency
    String name = ""
    String street = ""
    String cityZip = "г. "
    String country = ""
    String phone = "Тел: "
    String email = "E-mail: "
    if (agency) {
        Organization organization = EntityStorage.get().resolve(agency)?.getEntity()
        if (organization) {
            name = ProfileHelper.getFullName(
                    organization, LocaleHelper.EN_LOCALE, false).toUpperCase()
            Address address = organization.getAddresses().find { a ->
                a.getAddressType() == AddressType.LEGAL
            }
            if (address) {
                if (address.getHouse()) {
                    street = String.format("%s %s", address.getAddress().toString(LocaleHelper.RU_LOCALE),
                            address.getHouse().toString(LocaleHelper.RU_LOCALE))
                } else {
                    street = address.getAddress().toString(LocaleHelper.RU_LOCALE)
                }
                GeoLocation city = DictionaryCache.get().resolveReference(address.getCity())
                if (city) {
                    cityZip = cityZip.concat(DictHelper.getTranslation(
                            address.getCity(), LocaleHelper.RU_LOCALE, false))
                }
                cityZip = cityZip.concat(", ")
                if (address.getZip()) {
                    cityZip = cityZip.concat(address.getZip())
                }
                Country countryDict = DictionaryCache.get().resolveReference(address.getCountry())
                if (countryDict) {
                    country = DictHelper.getTranslation(countryDict, LocaleHelper.RU_LOCALE, false)
                }
            }
            Communication phoneComm = organization.getCommunications().find { c ->
                c.getType() == CommunicationType.WORK_PHONE
            }
            if (phoneComm) {
                if (phoneComm.getCountryCode()) {
                    phone = phone.concat(phoneComm.getCountryCode())
                }
                if (phoneComm.getCityCode()) {
                    phone = phone.concat(phoneComm.getCityCode())
                }
                if (phoneComm.getSense()) {
                    phone = phone.concat(phoneComm.getSense())
                }
            }
            Communication emailComm = organization.getCommunications().find { c ->
                c.getType() == CommunicationType.EMAIL
            }
            if (emailComm) {
                email = email.concat(emailComm.getSense())
            }
        }
    }
    fillContactRow(name)
    fillContactRow(street)
    fillContactRow(cityZip)
    fillContactRow(country)
    fillContactRow(phone)
    fillContactRow(email)
    3.times {
        nextRow()
    }
}

def fillHeader(ValueHolder<String> currencyHolder) {
    2.times {
        nextColumn()
    }
    rowHeight(21)
    fillBoldCenterCell("Счет на оплату №")
    2.times {
        nextRow()
        rowHeight(14)
    }
    4.times {
        nextColumn()
    }
    fillLeftCell("Дата: ".concat(new SimpleDateFormat("dd-MM-yyyy").format(new Date())))
    2.times {
        nextRow()
    }
    EntityReference<Organization> agency = parameters['key-report-params']?.agency
    EntityReference<Organization> supplier = parameters['key-report-params']?.supplier
    String contractNumber = "№ "
    if (agency && supplier) {
        SearchQuery query = new SearchQuery()
        query.getCriteria().getCriterions().add(
                SearchCriterion.eq(ContractIndex.Property.supplier.name(), supplier))
        query.getCriteria().getCriterions().add(
                SearchCriterion.eq(ContractIndex.Property.customer.name(), agency))
        query.getCriteria().getCriterions().add(
                SearchCriterion.eq(ContractIndex.Property.disabled.name(), false))
        query.getCriteria().getCriterions()
                .add(SearchCriterion.or(
                        SearchCriterion.eq(ContractIndex.Property.endDate.name(), null),
                        SearchCriterion.ge(ContractIndex.Property.endDate.name(), new Date())))
        query.getCriteria().getOrders().put(
                ContractIndex.Property.defaultContract.name(), SortOrder.DESC)
        List<ContractIndex> contractIndices =
                EntityStorage.get().search(ContractIndex.class, query).getData()
        if (!contractIndices.isEmpty()) {
            if (TextUtil.nonBlank(contractIndices.get(0).getNumber())) {
                contractNumber = String.format("%s%s от %s г.",
                        contractNumber, contractIndices.get(0).getNumber(),
                        new SimpleDateFormat("dd MMMM yyyy", LocaleHelper.RU_LOCALE)
                                .format(contractIndices.get(0).getIssueDate()))
            }
            if (TextUtil.nonBlank(contractIndices.get(0).getPaymentCurrency())) {
                currencyHolder.setValue(contractIndices.get(0).getPaymentCurrency())
            } else {
                currencyHolder.setValue(DictHelper.getLocalCurrencyCode())
            }
        }
    }
    String name = ""
    String location = ""
    String phoneNumber = ""
    String tin = ""
    if (supplier) {
        Organization organization = EntityStorage.get().resolve(supplier)?.getEntity()
        if (organization) {
            name = ProfileHelper.getFullName(
                    organization, LocaleHelper.RU_LOCALE, false)
            Address address = organization.getAddresses().find { a ->
                a.getAddressType() == AddressType.LEGAL
            }
            if (address) {
                location = ProfileHelper.buildFullAddress(
                        address, null, LocaleHelper.RU_LOCALE, false, true, false)
            }
            Communication phoneComm = organization.getCommunications().find { c ->
                c.getType() == CommunicationType.WORK_PHONE
            }
            if (phoneComm) {
                if (phoneComm.getCountryCode()) {
                    phoneNumber = phoneNumber.concat(phoneComm.getCountryCode())
                }
                if (phoneComm.getCityCode()) {
                    phoneNumber = phoneNumber.concat(phoneComm.getCityCode())
                }
                if (phoneComm.getSense()) {
                    phoneNumber = phoneNumber.concat(phoneComm.getSense())
                }
            }
            if (organization.getRegistrationId()) {
                tin = organization.getRegistrationId()
            }
        }
    }
    fillRow("Кому:", name)
    fillRow("Адрес:", location)
    fillRow("Тел:", phoneNumber)
    fillRow("По Договору:", contractNumber)
    fillRow("ИНН:", tin)
    nextRow()
}

def fillTable(ValueHolder<String> currencyHolder) {
    ValueHolder<BigDecimal> commissionHolder = new ValueHolder<>(BigDecimal.ZERO)
    fillTableHeader(currencyHolder)
    fillTableBody(commissionHolder)
    fillTableFooter(currencyHolder, commissionHolder)
}

def fillSignature() {
    EntityReference<Organization> agency = parameters['key-report-params']?.agency
    String director = ""
    String accountant = ""
    if (agency) {
        SearchQuery query = new SearchQuery()
        query.getCriteria().getCriterions().add(SearchCriterion.eq(
                PersonEmploymentIndex.Property.organization.name(), agency))
        query.getCriteria().getCriterions().add(SearchCriterion.or(
                SearchCriterion.eq(
                        PersonEmploymentIndex.Property.workStartDate.name(), null),
                SearchCriterion.le(
                        PersonEmploymentIndex.Property.workStartDate.name(), new Date())
        ))
        query.getCriteria().getCriterions().add(SearchCriterion.or(
                SearchCriterion.eq(
                        PersonEmploymentIndex.Property.workEndDate.name(), null),
                SearchCriterion.ge(
                        PersonEmploymentIndex.Property.workEndDate.name(), new Date())
        ))
        List<PersonEmploymentIndex> indices =
                EntityStorage.get().search(PersonEmploymentIndex.class, query).getData()
        if (!indices.isEmpty()) {
            PersonEmploymentIndex dir = indices.find { pei ->
                pei.getPosition() != null && pei.getPosition().getCode() == ManagerType.CHIEF_ACCOUNTANT.name()
            }
            if (dir) {
                director = dir.getSource().getCaption()
            }
            PersonEmploymentIndex acc = indices.find { pei ->
                pei.getPosition() != null && pei.getPosition().getCode() == ManagerType.DIRECTOR.name()
            }
            if (acc) {
                accountant = acc.getSource().getCaption()
            }
        }
    }
    fillSignatureRow("Директор:", director)
    fillSignatureRow("Главный бухгалтер:", accountant)
}

def fillTableHeader(ValueHolder<String> currencyHolder) {
    rowHeight(22)
    nextColumn()
    fillBoldCenterBorderCell("№")
    fillBoldCenterBorderCell("Наименование")
    fillBoldCenterBorderCell(currencyHolder.getValue())
    fillBoldCenterBorderCell("USD")
    nextRow()
}

def fillTableBody(ValueHolder<BigDecimal> commissionHolder) {
    Date toDate = parameters['key-report-params']?.periodEnd
    nextColumn()
    rowHeight(26)
    fillCenterBorderCell("1")
    fillLeftBorderCell(String.format("%s\n%s г.", "Комиссионное вознагрождение за",
            new SimpleDateFormat("LLLL yyyy", LocaleHelper.RU_LOCALE)
                    .format(toDate).toLowerCase()))
    BigDecimal commission = BigDecimal.ZERO
    tickets { AirTicketsTemplateReportTicket ticket ->
        BigDecimal amount = (BigDecimal) ticket.getCommissions()
                .findAll { c ->
                    c.getContractType() == ContractType.VENDOR && c.getEquivalentAmount() != null
                }.collect { c ->
            c.getEquivalentAmount()
        }.sum(BigDecimal.ZERO)
        if (ticket.getOperationBatch() == OperationBatch.REFUND) {
            commission = MiscUtil.sub(commission, amount)
        } else {
            commission = MiscUtil.sum(commission, amount)
        }
    }
    fillRightBorderCell(commission)
    fillLeftBorderCell("")
    nextRow()
    nextColumn()
    rowHeight(25)
    fillCenterBorderCell("")
    fillBoldLeftBorderCell("Итого к оплате")
    fillRightFormulaBorderCell("${cellIndex(-1, 0)}")
    fillCenterBorderCell("")
    commissionHolder.setValue(commission)
    2.times {
        nextRow()
    }
}

def fillTableFooter(ValueHolder<String> currencyHolder,
                    ValueHolder<BigDecimal> commissionHolder) {
    rowHeight(14)
    String money = ""
    Number2WordsConverter number2WordsConverter =
            Environment.getPublished(Number2WordsConverterRegistry.class)
                    .findConverter(LocaleHelper.RU_LOCALE, currencyHolder.getValue())
    if (number2WordsConverter != null) {
        try {
            money = TextUtil.capitalize(number2WordsConverter.toCurrencyWords(
                    commissionHolder.getValue(), currencyHolder.getValue(),
                    false, true, true))
        } catch (Exception ignored) {
            // Ignore
        }
    }
    nextColumn()
    fillLeftCell("Всего к оплате:")
    fillLeftCell(money)
    2.times {
        nextRow()
    }
    nextColumn()
    fillLeftCell("Банковские реквизиты для перечисления в ".concat(currencyHolder.getValue()))
    2.times {
        nextRow()
    }
    EntityReference<Organization> agency = parameters['key-report-params']?.agency
    String account = "Расчетный счет: №"
    String mfo = "МФО: "
    String bank = ""
    String tin = "ИНН: №"
    if (agency) {
        Organization organization = EntityStorage.get().resolve(agency)?.getEntity()
        if (organization) {
            BankAccount bankAccount = organization.getBankAccounts()
                    .find { ba ->
                        ba.getCurrency() == currencyHolder.getValue()
                    }
            if (bankAccount) {
                account = account.concat(bankAccount.getSettlementAccount())
                bank = bankAccount.getBankName()
            }
            if (organization.getRegistrationId()) {
                tin = tin.concat(organization.getRegistrationId())
            }
            //TODO MFO
        }
    }
    fillRow(account)
    fillRow(mfo)
    fillRow(bank)
    fillRow(tin)
    6.times {
        nextRow()
    }
}

def fillContactRow(String data) {
    4.times {
        nextColumn()
    }
    fillLeftCell(data)
    nextRow()
}

def fillRow(String data) {
    nextColumn()
    fillLeftCell(data)
    nextRow()
}

def fillRow(String first, String second) {
    nextColumn()
    fillItalicLeftCell(first)
    fillLeftCell(second)
    nextRow()
}

def fillSignatureRow(String position, String name) {
    nextColumn()
    fillItalicLeftCell(position)
    2.times {
        nextColumn()
    }
    fillItalicLeftCell(name)
    2.times {
        nextRow()
    }
}

def fillLeftCell(String data) {
    fillCell(data, "left")
}

def fillItalicLeftCell(String data) {
    fillCell(data, "left-italic")
}

def fillBoldCenterCell(String data) {
    fillCell(data, "center-bold")
}

def fillBoldCenterBorderCell(String data) {
    fillCell(data, "center-bold-border")
}

def fillLeftBorderCell(String data) {
    fillCell(data, "left-border")
}

def fillRightBorderCell(BigDecimal data) {
    fillCell(data, "right-border")
}

def fillRightFormulaBorderCell(String data) {
    fillFormulaCell(data, "right-border")
}

def fillBoldLeftBorderCell(String data) {
    fillCell(data, "left-bold-border")
}

def fillCenterBorderCell(String data) {
    fillCell(data, "center-border")
}

def fillCell(String data, String style) {
    text(data, style, 1, 1)
    nextColumn()
}

def fillCell(BigDecimal data, String style) {
    number(data, style)
    nextColumn()
}

def fillFormulaCell(String data, String style) {
    formula(data, style)
    nextColumn()
}

def setWidth() {
    nextRow()
    columnWidth(9)
    nextColumn()
    columnWidth(15)
    nextColumn()
    columnWidth(41)
    nextColumn()
    columnWidth(19)
    nextColumn()
    columnWidth(19)
    nextColumn()
    columnWidth(9)
}

page { "INVOICE" } {
    // Set fix width for amount of sheets
    fitWidth(1)

    // Set fix height for amount of sheets
    fitHeight(1)

    // Set portrait mode
    landscape(false)

    // Set narrow margins
    margin(0.25, 0.25, 0.25, 0.25)

    // Set scale
    scale(70)

    // Set preserve mode
    preserve(true)

    fillSheet()
    setWidth()
}

