// Imports
import com.gridnine.xtrip.common.l10n.model.LocaleHelper
import com.gridnine.xtrip.common.model.entity.EntityStorage
import com.gridnine.xtrip.common.model.finance.ChartOfAccountsElementType;
import com.gridnine.xtrip.common.model.finance.DimensionType;
import com.gridnine.xtrip.common.model.helpers.BalanceHelper;
import com.gridnine.xtrip.common.model.helpers.DictHelper;
import com.gridnine.xtrip.common.model.helpers.ProfileHelper
import com.gridnine.xtrip.common.model.booking.OperationBatch
import com.gridnine.xtrip.common.model.booking.commission.ProductType
import com.gridnine.xtrip.common.model.dict.AddressType
import com.gridnine.xtrip.common.model.dict.ContractType
import com.gridnine.xtrip.common.util.MiscUtil
import com.gridnine.xtrip.common.util.TextUtil

import java.text.SimpleDateFormat

// Styles
createStyle(name: 'title', v_alignment: 'CENTER')
createStyle(name: 'titleH1', fontHeight: 16, parent: 'title')
createStyle(name: 'titleH1Center', h_alignment: 'CENTER', parent: 'titleH1')
createStyle(name: 'titleH1CenterBold', fontBold: true, parent: 'titleH1Center')
createStyle(name: 'titleH2', fontHeight: 14, parent: 'title')
createStyle(name: 'titleH2Center', h_alignment: 'CENTER', parent: 'titleH2')
createStyle(name: 'titleH2CenterBold', fontBold: true, parent: 'titleH2Center')
createStyle(name: 'titleH3', fontHeight: 10, parent: 'title')
createStyle(name: 'titleH3Center', h_alignment: 'CENTER', parent: 'titleH3')
createStyle(name: 'titleH3Right', h_alignment: 'RIGHT', parent: 'titleH3')
createStyle(name: 'header', fontHeight: 10, v_alignment: 'CENTER', topBorder: 'THIN', leftBorder: 'THIN', bottomBorder: 'THIN', rightBorder: 'THIN')
createStyle(name: 'columnHeader', wrapText: true, h_alignment: 'CENTER', parent: 'header')
createStyle(name: 'columnHeaderBold', fontBold: true, parent: 'columnHeader')
createStyle(name: 'rowHeader', h_alignment: 'RIGHT', parent: 'header')
createStyle(name: 'rowHeaderBold', fontBold: true, parent: 'rowHeader')
createStyle(name: 'data', fontHeight: 10, v_alignment: 'CENTER', topBorder: 'THIN', leftBorder: 'THIN', bottomBorder: 'THIN', rightBorder: 'THIN')
createStyle(name: 'dataText', parent: 'data')
createStyle(name: 'dataTextCenter', h_alignment: 'CENTER', parent: 'dataText')
createStyle(name: 'dataTextBold', fontBold: true, parent: 'dataText')
createStyle(name: 'dataTextCenterBold', fontBold: true, parent: 'dataTextCenter')
createStyle(name: 'dataNumber', h_alignment: 'RIGHT', format: '#,##0.00', parent: 'data')
createStyle(name: 'dataNumberBold', fontBold: true, parent: 'dataNumber')

// Properties
def periodBeginParameter = parameters['key-report-params']?.periodBegin
def periodEndParameter = parameters['key-report-params']?.periodEnd
def supplierParameter = parameters['supplier']
def agencyParameter = parameters['agency']
def subagencyParameter = parameters['subagency']
def consolidatedParameter = parameters['consolidated']
def productTypeParameter = parameters['productType']

boolean isKzAgency(agency) {
    def country = ProfileHelper.getOrganizationCountry(agency);
    return "KZ" == country?.getCode();
}

// Closures
def agencyName = {
    def agency = EntityStorage.get().resolve(agencyParameter)?.entity
    return agency ? ProfileHelper.getFullName(agency, LocaleHelper.getLocale('ru', 'RU'), false) : 'Не указано'
}

String getAgencyAddressCodes(agency) {
    if (agency == null)
        return 'ИНН / КПП ?/?'
    if (isKzAgency(agency)) {
        return 'БИН / НДС ' +
                (agency.bin ? agency.bin : "?") + " / " +
                (agency.vatLicenseNumber ?
                        agency.vatLicenseNumber + " (" + (agency.vatSeriesDate ?
                                (new SimpleDateFormat("yyyy-MM-dd")).format(agency.vatSeriesDate) : "?") + ")" : "")
    }
    return 'ИНН / КПП ' + (agency.registrationId ? agency.registrationId : '?') + ' / ' + (agency.kpp ? agency.kpp : '?')
}

def agencyAddressCodes = {

    def agency = EntityStorage.get().resolve(agencyParameter)?.entity
    return getAgencyAddressCodes(agency);
}

def agencyAddressLegal = {

    def agency = EntityStorage.get().resolve(agencyParameter)?.entity
    return agency ? ProfileHelper.buildFullAddress(ProfileHelper.filterAddresses(agency.addresses, AddressType.LEGAL), LocaleHelper.getLocale('ru', 'RU'), false) : ''
}

def subagencyName = {

    def subagency = EntityStorage.get().resolve(subagencyParameter)?.entity
    return subagency ? ProfileHelper.getFullName(subagency, LocaleHelper.getLocale('ru', 'RU'), false) : 'Не указано'
}

def subagencyAddressCodes = {

    def subagency = EntityStorage.get().resolve(subagencyParameter)?.entity
    return getAgencyAddressCodes(subagency)
}

def subagencyAddressLegal = {

    def subagency = EntityStorage.get().resolve(subagencyParameter)?.entity
    return subagency ? ProfileHelper.buildFullAddress(ProfileHelper.filterAddresses(subagency.addresses, AddressType.LEGAL), LocaleHelper.getLocale('ru', 'RU'), false) : ''
}

def contract = {
    def contracts = new ArrayList<>()
    if (supplierParameter instanceof ArrayList) {
        supplierParameter.each {
            contracts.addAll(ProfileHelper.getContracts(it, agencyParameter, subagencyParameter, ContractType.SUBAGENCY, periodBeginParameter, periodEndParameter))
        }
    } else if (supplierParameter == null) {
        contracts = ProfileHelper.getContracts(null, agencyParameter, subagencyParameter, ContractType.SUBAGENCY, periodBeginParameter, periodEndParameter)
    } else {
        contracts = ProfileHelper.getContracts(supplierParameter, agencyParameter, subagencyParameter, ContractType.SUBAGENCY, periodBeginParameter, periodEndParameter)
    }
    def format = new SimpleDateFormat('dd.MM.yyyy')
    def result = ''

    contracts.each {
        if (TextUtil.nonBlank(result)) {
            result += '; '
        }
        def number = contracts.size() > 0 ? ProfileHelper.getContractCustomerInfo(it, subagencyParameter)?.number : null
        def issueDate = contracts.size() > 0 ? ProfileHelper.getContractCustomerInfo(it, subagencyParameter)?.issueDate : null
        result += number ? number : ''
        result += issueDate ? (result.length() > 0 ? ' от ' : '') + format.format(issueDate) : ''
    }

    return result
}

def period = {

    def format = new SimpleDateFormat('dd.MM.yyyy')
    return String.format('%s по %s', periodBeginParameter ? format.format(periodBeginParameter) : '?', periodEndParameter ? format.format(periodEndParameter) : '?')
}

def periodBeginBalance = {

    def operationDate = periodBeginParameter ? MiscUtil.getBeforeTime(periodBeginParameter) : null
    def balance = BalanceHelper.calculateBalance(subagencyParameter, operationDate, null, ChartOfAccountsElementType.SUPPLIER, DictHelper.getCurrencyInfoByAnyCode(DictHelper.getLocalCurrencyCode())?.toReference(), Collections.singletonMap(DimensionType.ORGANIZATION, agencyParameter))
    return balance ? balance : BalanceHelper.calculateBalance(agencyParameter, operationDate, null, ChartOfAccountsElementType.CUSTOMER, DictHelper.getCurrencyInfoByAnyCode(DictHelper.getLocalCurrencyCode())?.toReference(), Collections.singletonMap(DimensionType.ORGANIZATION, subagencyParameter))
}

def periodEndBalance = {

    def operationDate = periodEndParameter
    def balance = BalanceHelper.calculateBalance(subagencyParameter, operationDate, null, ChartOfAccountsElementType.SUPPLIER, DictHelper.getCurrencyInfoByAnyCode(DictHelper.getLocalCurrencyCode())?.toReference(), Collections.singletonMap(DimensionType.ORGANIZATION, agencyParameter))
    return balance ? balance : BalanceHelper.calculateBalance(agencyParameter, operationDate, null, ChartOfAccountsElementType.CUSTOMER, DictHelper.getCurrencyInfoByAnyCode(DictHelper.getLocalCurrencyCode())?.toReference(), Collections.singletonMap(DimensionType.ORGANIZATION, subagencyParameter))
}

def payment = {

    def startOperationDate = periodBeginParameter ? MiscUtil.getBeforeTime(periodBeginParameter) : null
    def endOperationDate = periodEndParameter
    def balance = BalanceHelper.calculateBalance(subagencyParameter, startOperationDate, endOperationDate, null, ChartOfAccountsElementType.SUPPLIER, DictHelper.getCurrencyInfoByAnyCode(DictHelper.getLocalCurrency())?.toReference(), Collections.singletonMap(DimensionType.ORGANIZATION, agencyParameter), false)
    return balance ? balance : BalanceHelper.calculateBalance(agencyParameter, startOperationDate, endOperationDate, null, ChartOfAccountsElementType.CUSTOMER, DictHelper.getCurrencyInfoByAnyCode(DictHelper.getLocalCurrency())?.toReference(), Collections.singletonMap(DimensionType.ORGANIZATION, subagencyParameter), true)
}

// Page "Settlement letter"
page{'Расчетное письмо'}{

    // Set landcape mode
    landscape(true)

    def counts = [:]
    counts['sell'] = 0
    counts['refund'] = [:]
    counts['refund']['ticket'] = 0
    counts['refund']['mco'] = 0
    counts['exchange'] = [:]
    counts['exchange']['ticket'] = 0
    counts['exchange']['mco'] = 0
    counts['memo'] = 0

    def tariffs = [:]
    tariffs['sell'] = BigDecimal.ZERO
    tariffs['refund'] = BigDecimal.ZERO
    tariffs['exchange'] = BigDecimal.ZERO
    tariffs['memo'] = BigDecimal.ZERO

    def taxesBlank = [:]
    taxesBlank['sell'] = BigDecimal.ZERO
    taxesBlank['refund'] = BigDecimal.ZERO
    taxesBlank['exchange'] = BigDecimal.ZERO
    taxesBlank['memo'] = BigDecimal.ZERO

    def taxesOther = [:]
    taxesOther['sell'] = BigDecimal.ZERO
    taxesOther['refund'] = BigDecimal.ZERO
    taxesOther['exchange'] = BigDecimal.ZERO
    taxesOther['memo'] = BigDecimal.ZERO

    def penalty = [:]
    penalty['sell'] = BigDecimal.ZERO
    penalty['refund'] = BigDecimal.ZERO
    penalty['exchange'] = BigDecimal.ZERO
    penalty['memo'] = BigDecimal.ZERO

    def fees = [:]
    fees['sell'] = BigDecimal.ZERO
    fees['refund'] = BigDecimal.ZERO
    fees['exchange'] = BigDecimal.ZERO
    fees['memo'] = BigDecimal.ZERO

    def commissions = [:]
    commissions['sell'] = BigDecimal.ZERO
    commissions['refund'] = BigDecimal.ZERO
    commissions['exchange'] = BigDecimal.ZERO
    commissions['memo'] = BigDecimal.ZERO

    // Initialization
    tickets{

        def batch = null
        def type = null

        if(it.operationBatch == OperationBatch.SELL) {
            if (it.productType == ProductType.AGENCY_MEMO_PRODUCT) {
                batch = 'memo'
            } else {
                batch = 'sell'
            }
        } else if(it.operationBatch == OperationBatch.REFUND) {
            batch = 'refund'
        } else if(it.operationBatch == OperationBatch.EXCHANGE) {
            batch = 'exchange'
        }

        if(batch != null) {

            if(it.productType == null || !it.productType.name().startsWith('MCO') || it.productType == ProductType.MCO_FEES) {
                type = 'ticket'
            } else {
                type = 'mco'
            }

            if(batch.equals('sell') || batch.equals('memo')) {
                counts[batch]++
            } else {
                counts[batch][type]++
            }

            def contractPenalty = it.vendorContractPenaltyValue
            if (contractPenalty == null) {
                contractPenalty = it.subagencyContractPenaltyValue
            }
            if (contractPenalty == null) {
                contractPenalty = it.clientContractPenaltyValue
            }

            if(it.subagencyContractFare != null) {tariffs[batch] = tariffs[batch].add(it.subagencyContractFare)}
            if(it.subagencyContractTaxesForBlankSum != null) {taxesBlank[batch] = taxesBlank[batch].add(it.subagencyContractTaxesForBlankSum)}
            if(it.subagencyContractOtherTaxesSum != null || it.subagencyHiddenFeeValue != null) {taxesOther[batch] = taxesOther[batch].add(MiscUtil.sum(it.subagencyContractOtherTaxesSum, it.subagencyHiddenFeeValue))}
            if(it.subagencyContractPenalty != null || contractPenalty != null) {penalty[batch] = penalty[batch].add(MiscUtil.sum(it.subagencyContractPenalty, contractPenalty))}
            if(it.subagencyFeeValue != null) {fees[batch] = fees[batch].add(MiscUtil.sub(it.subagencyFeeValue, it.subagencyHiddenFeeValue))}
            if(it.subagencyCommissionValue != null) {commissions[batch] = commissions[batch].add(it.subagencyCommissionValue)}
        }
    }

    // Set defalt row height
    rowHeight(13.2)

    // Header
    rowHeight(25, false)
    text('Отчет комиссионера', 'titleH1CenterBold', 6, 1)
    nextRow()
    rowHeight(15, false)
    text(consolidatedParameter ? 'Расчетное письмо' : 'Расчетное письмо (' + productTypeParameter + ')', 'titleH2CenterBold', 6, 1)
    2.times{nextRow()}
    text('Принципал (Агентство):', 'titleH3')
    3.times{nextColumn()}
    text('Комиссионер (Субагент):', 'titleH3')
    nextRow()
    text(agencyName(), 'titleH3')
    3.times{nextColumn()}
    text(subagencyName(), 'titleH3')
    nextRow()
    text(agencyAddressCodes(), 'titleH3')
    3.times{nextColumn()}
    text(subagencyAddressCodes(), 'titleH3')
    nextRow()
    text(agencyAddressLegal(), 'titleH3')
    3.times{nextColumn()}
    text(subagencyAddressLegal(), 'titleH3')
    2.times{nextRow()}
    text('Договор:', 'titleH3')
    nextColumn()
    text(contract(), 'titleH3')
    nextRow()
    text('Период:', 'titleH3')
    nextColumn()
    text(period(), 'titleH3')
    2.times{nextRow()}

    if(consolidatedParameter) {

        text('Сальдо на начало периода:', 'titleH3')
        nextColumn()
        number(periodBeginBalance(), 'titleH3')
        2.times{nextRow()}
    }

    // Table header
    columnWidth(28)
    text('', 'columnHeader')
    nextColumn()
    columnWidth(19)
    text(String.format('Продажа (%s)', counts['sell']), 'columnHeader')
    nextColumn()
    columnWidth(19)
    text(String.format('Возврат (%s/%s)', counts['refund']['ticket'], counts['refund']['mco']), 'columnHeader')
    nextColumn()
    columnWidth(19)
    text(String.format('Обмен (%s/%s)', counts['exchange']['ticket'], counts['exchange']['mco']), 'columnHeader')
    nextColumn()
    columnWidth(19)
    text(String.format('Претензии (%s)', counts['memo']), 'columnHeader')
    nextColumn()
    columnWidth(19)
    text('Корректировки', 'columnHeader')
    nextRow()

    // Table rows
    text('Тариф', 'rowHeader')
    nextColumn()
    number(tariffs['sell'], 'dataNumber')
    nextColumn()
    number(tariffs['refund'], 'dataNumber')
    nextColumn()
    number(tariffs['exchange'], 'dataNumber')
    nextColumn()
    number(tariffs['memo'])
    nextColumn()
    number(null, 'dataNumber')

    nextRow()

    text('Таксы за бланк', 'rowHeader')
    nextColumn()
    number(taxesBlank['sell'], 'dataNumber')
    nextColumn()
    number(taxesBlank['refund'], 'dataNumber')
    nextColumn()
    number(taxesBlank['exchange'], 'dataNumber')
    nextColumn()
    number(taxesBlank['memo'], 'dataNumber')
    nextColumn()
    number(null, 'dataNumber')

    nextRow()

    text('Другие таксы', 'rowHeader')
    nextColumn()
    number(taxesOther['sell'], 'dataNumber')
    nextColumn()
    number(taxesOther['refund'], 'dataNumber')
    nextColumn()
    number(taxesOther['exchange'], 'dataNumber')
    nextColumn()
    number(taxesOther['memo'], 'dataNumber')
    nextColumn()
    number(null, 'dataNumber')

    nextRow()

    text('Штраф', 'rowHeader')
    nextColumn()
    number(penalty['sell'], 'dataNumber')
    nextColumn()
    number(penalty['refund'], 'dataNumber')
    nextColumn()
    number(penalty['exchange'], 'dataNumber')
    nextColumn()
    number(penalty['memo'], 'dataNumber')
    nextColumn()
    number(null, 'dataNumber')

    nextRow()

    text('Сборы агентства', 'rowHeader')
    nextColumn()
    number(fees['sell'], 'dataNumber')
    nextColumn()
    number(fees['refund'], 'dataNumber')
    nextColumn()
    number(fees['exchange'], 'dataNumber')
    nextColumn()
    number(fees['memo'], 'dataNumber')
    nextColumn()
    number(null, 'dataNumber')

    nextRow()

    text('Итого', 'rowHeaderBold')
    nextColumn()
    formula("SUM(${cellIndex(-5, 0)}:${cellIndex(-1, 0)})", 'dataNumberBold')
    nextColumn()
    formula("SUM(${cellIndex(-5, 0)}:${cellIndex(-1, 0)})", 'dataNumberBold')
    nextColumn()
    formula("SUM(${cellIndex(-5, 0)}:${cellIndex(-1, 0)})", 'dataNumberBold')
    nextColumn()
    formula("SUM(${cellIndex(-5, 0)}:${cellIndex(-1, 0)})", 'dataNumberBold')
    nextColumn()
    formula("SUM(${cellIndex(-5, 0)}:${cellIndex(-1, 0)})", 'dataNumberBold')
    nextRow()

    text('Комиссия', 'rowHeader')
    nextColumn()
    number(commissions['sell'], 'dataNumber')
    nextColumn()
    number(commissions['refund'], 'dataNumber')
    nextColumn()
    number(commissions['exchange'], 'dataNumber')
    nextColumn()
    number(commissions['memo'], 'dataNumber')
    nextColumn()
    number(null, 'dataNumber')

    nextRow()

    text('Выручка за период', 'rowHeader')
    nextColumn()
    formula("SUM(${cellIndex(-2, 0)}:${cellIndex(-2, 4)})", 'dataNumberBold')
    nextRow()

    text('Комиссия за период', 'rowHeader')
    nextColumn()
    formula("SUM(${cellIndex(-2, 0)}:${cellIndex(-2, 4)})", 'dataNumberBold')
    nextRow()

    text('К перечислению', 'rowHeader')
    nextColumn()
    formula("${cellIndex(-2,0)}-${cellIndex(-1,0)}", 'dataNumberBold')
    2.times{nextRow()}

    if(consolidatedParameter) {

        text('Перечислено за период:', 'titleH3')
        nextColumn()
        number(payment(), 'titleH3')
        nextRow()
        text('Сальдо на конец периода:', 'titleH3')
        nextColumn()
        number(periodEndBalance(), 'titleH3')
        2.times{nextRow()}
    }

    // Footer
    text('От', 'titleH3Right')
    nextColumn()
    text(agencyName(), 'titleH3')
    2.times{nextColumn()}
    text('От', 'titleH3Right')
    nextColumn()
    text(subagencyName(), 'titleH3')
    3.times{nextRow()}
    text('Руководитель', 'titleH3Right')
    nextColumn()
    text('___________________', 'titleH3Center')
    2.times{nextColumn()}
    text('Руководитель', 'titleH3Right')
    nextColumn()
    text('___________________', 'titleH3Center')
    nextRow()
    nextColumn()
    text('(                               )', 'titleH3Center')
    3.times{nextColumn()}
    text('(                               )', 'titleH3Center')
    2.times{nextRow()}
    nextColumn()
    text('МП', 'titleH3Center')
    3.times{nextColumn()}
    text('МП', 'titleH3Center')
}
