import com.gridnine.xtrip.common.l10n.model.LocaleHelper
import com.gridnine.xtrip.common.model.booking.OperationBatch
import com.gridnine.xtrip.common.model.dict.CodeSystem
import com.gridnine.xtrip.common.model.dict.CurrencyInfo
import com.gridnine.xtrip.common.model.dict.DictionaryCache
import com.gridnine.xtrip.common.model.helpers.DictHelper
import com.gridnine.xtrip.common.model.system.PaymentType
import com.gridnine.xtrip.common.reports.model.AirTicketsTemplateReportSegmentTariff
import com.gridnine.xtrip.common.reports.model.AirTicketsTemplateReportTicket
import com.gridnine.xtrip.common.util.MiscUtil
import com.gridnine.xtrip.common.util.TextUtil

import java.text.SimpleDateFormat

//CREATING STYLES
createStyle(name: 'baseStyle', fontBold: false,  h_alignment: 'LEFT', v_alignment: 'CENTER', fontHeight:8, leftBorder:'THIN', rightBorder:'THIN', topBorder:'THIN', bottomBorder:'THIN')
createStyle(name: 'baseStyleBold', parent: 'baseStyle', fontBold: true)
createStyle(name: 'baseStyleClearBold', fontBold: true, h_alignment: 'LEFT', v_alignment: 'CENTER', fontHeight:8)
createStyle(name: 'headStyle', fontBold: true,  h_alignment: 'CENTER', v_alignment: 'CENTER', fontHeight:12)
createStyle(name: 'headStyle12', parent: 'headStyle', fontHeight:10)
createStyle(name: 'style', fontBold: false, fontHeight: 8, parent: 'baseStyle')
createStyle(name: 'textDataCenter', h_alignment: 'CENTER', v_alignment: 'CENTER', fontHeight:8)
createStyle(name: 'dateDataClear', format: 'm/d/yy', fontHeight: 10,  h_alignment: 'LEFT', v_alignment: 'CENTER')
createStyle(name: 'dateData', format: 'm/d/yy', parent: 'style',  h_alignment: 'RIGHT', v_alignment: 'CENTER')
createStyle(name: 'numberData', format: '#,##0.00', parent: 'style',  h_alignment: 'RIGHT', v_alignment: 'CENTER')
createStyle(name: 'numberDataCenter', parent: 'numberData', h_alignment: 'CENTER')
createStyle(name: 'numberDataClearBold', format: '#,##0.00',  h_alignment: 'RIGHT', v_alignment: 'CENTER', fontHeight: 8, fontBold: true)
createStyle(name: 'divide', topBorder:'THIN')

class Formula {
    String formula
    Formula(){}
    Formula(String formula) {
        this.formula = formula
    }

    static Formula getSumFormulaByRow (String start, String end) {
        return new Formula('SUM(' + start + ':' + end + ')')
    }
    static Formula getSumFormulaByCell(String... index) {
        def formula = ''
        for (int i=0; i<index.size(); i++) {
            if(i == 0) {
                formula += index[i]
            } else {
                formula += ',' + index[i]
            }
        }
        return new Formula('SUM(' + formula + ')')
    }
}

def cellFill(Object value) {
    if (value != null) {
        if (value instanceof Number) {
            number(value, 'numberDataClearBold')
        } else if (value instanceof Date) {
            date(value,'dateData')
        } else if (value instanceof Formula){
            formula(value.formula,'numberDataClearBold')
        } else {
            text(value, 'baseStyle')
        }
    } else {
        text('', 'baseStyle')
    }
}

def reportHeader () {

    def scw = 12

    def contractDateFrom = parameters['contract_date_from']
    def contractDateFromToString =
            contractDateFrom ? new SimpleDateFormat('dd.MM.yyyy').format(contractDateFrom).toString()
                    : '__________'
    def contactNumber = parameters['contract_number']
    contactNumberToString = contactNumber ? contactNumber.toString() : '___'
    def reportPeriod = parameters['REPORT_PERIOD']
    reportPeriod = reportPeriod ? reportPeriod : ''
    def subagencyName = parameters['SUBAGENCY_NAME']
    subagencyName = subagencyName ? subagencyName : ''

    rowHeight(1.2*scw)
    columnWidth(scw)
    text('АКТ', 'headStyle', 8, 1)
    nextRow()
    text('О НАЧИСЛЕНИИ КОМИССИОННОГО ВОЗНАГРАЖДЕНИЯ', 'headStyle', 8, 1)
    nextRow()
    text('согласно договора № ' + contactNumberToString + ' от ' + contractDateFromToString + ' года',
            'headStyle12', 8, 1)
    nextRow()
    text('за период ' + reportPeriod, 'headStyle12', 8, 1)
    nextRow()
    text('субагенту ' + subagencyName, 'headStyle12', 8, 1)
    2.times{nextRow()}
}

def printColumnHeader(String str, Number width) {
    if(width != 0) {
        columnWidth(width)
    }
    text(str, 'baseStyleBold')
    nextColumn()
}

def reportTitle() {
    rowHeight(30)
    CurrencyInfo currencyInfo = DictHelper.getCurrencyInfoByAnyCode(DictHelper.getLocalCurrencyCode())
    def currency = currencyInfo?.toString(LocaleHelper.RU_LOCALE)
    printColumnHeader('№\nп/п', 6)
    printColumnHeader('ФО', 34)
    printColumnHeader('Эмитент', 7)
    printColumnHeader('Перевозчик', 10)
    printColumnHeader('ставка\nвозн.', 8)
    printColumnHeader('Базовая сумма\nдля расчета, ' + currency, 20)
    printColumnHeader('Вознаграждение\nсубагента, ' + currency, 20)
    printColumnHeader('Ком. агентства', 20)
    nextRow()
}

def addTicketsToMapPaymentType(Map<PaymentType, Map<String, List<AirTicketsTemplateReportTicket>>> ticketsPaymantType,
                               AirTicketsTemplateReportTicket ticket){

    def airlineNumber = DictionaryCache.get().resolveReference(ticket.validatingCarrier)?.getAirlineNumber()
    airlineNumber = airlineNumber ? airlineNumber : ''

    PaymentType paymentType = ticket.subagentPaymentTypes.first()

    Map<String, List<AirTicketsTemplateReportTicket>> paymentTypeToTickets = ticketsPaymantType.get(paymentType)
    if(!paymentTypeToTickets){
        paymentTypeToTickets = new HashMap<String, List<AirTicketsTemplateReportTicket>>()
        ticketsPaymantType.put(paymentType, paymentTypeToTickets)
    }

    List<AirTicketsTemplateReportTicket> tickets = paymentTypeToTickets.get(airlineNumber)
    if(!tickets){
        tickets = new ArrayList<AirTicketsTemplateReportTicket>()
        paymentTypeToTickets.put(airlineNumber, tickets)
    }

    tickets.add(ticket)
}

def reportBody() {
    int count = 0
    def ticketsCashless = new HashMap<PaymentType, Map<String, List<AirTicketsTemplateReportTicket>>>()
    def ticketsCash = new HashMap<PaymentType, Map<String, List<AirTicketsTemplateReportTicket>>>()
    def ticketsCredit = new HashMap<PaymentType, Map<String, List<AirTicketsTemplateReportTicket>>>()

    allTickets.each { AirTicketsTemplateReportTicket ticket ->

        if (ticket.subagentPaymentTypes.contains(PaymentType.CASH)) {

            addTicketsToMapPaymentType(ticketsCash, ticket)

        } else if (ticket.subagentPaymentTypes.contains(PaymentType.INVOICE)) {

            addTicketsToMapPaymentType(ticketsCashless, ticket)

        } else if (!ticket.subagentPaymentTypes.contains(PaymentType.PTA)){

            addTicketsToMapPaymentType(ticketsCredit, ticket)
        }
    }

    def totalCount = 0
    def countCredit = 0
    def countCashless = 0
    def countCash = 0
    def columnShift = 0

    if (!ticketsCredit.isEmpty()){
        count = fillTable(ticketsCredit, totalCount)
        countCredit = count
        totalCount += count
        if (count > 0) {
            text('Итого по КР:', 'baseStyleClearBold', 2, 1)
            5.times { nextColumn() }
            3.times {
                cellFill(Formula.getSumFormulaByRow(cellIndex(-count, 0), cellIndex(-1, 0)))
                nextColumn()
            }
            nextRow()
        }
    }

    if (!ticketsCashless.isEmpty()){
        count = fillTable(ticketsCashless, totalCount)
        countCashless = count
        totalCount += count
        if (count > 0) {
            text('Итого по БЕЗНАЛ:', 'baseStyleClearBold', 2, 1)
            5.times { nextColumn() }
            3.times {
                cellFill(Formula.getSumFormulaByRow(cellIndex(-count, 0), cellIndex(-1, 0)))
                nextColumn()
            }
            nextRow()
        }
    }

    if(!ticketsCash.isEmpty()) {
        count = fillTable(ticketsCash, totalCount)
        countCash = count
        if (count > 0) {
            text('Итого по НАЛ:', 'baseStyleClearBold', 2, 1)
            5.times { nextColumn() }
            3.times {
                cellFill(Formula.getSumFormulaByRow(cellIndex(-count, 0), cellIndex(-1, 0)))
                nextColumn()
            }
            nextRow()
        }
    }

    def createSummaryFormula = {int column ->
        if (countCash == 0 && countCashless > 0 && countCredit > 0){
            return Formula.getSumFormulaByCell(cellIndex(-2 - countCashless, columnShift),
                                         '+' + cellIndex(-1, columnShift))
        }
        if (countCashless == 0 && countCredit > 0 && countCash > 0
                || countCredit == 0 && countCashless > 0 && countCash > 0){
            return Formula.getSumFormulaByCell(cellIndex(-2 - countCash, columnShift),
                                         '+' + cellIndex(-1, columnShift))
        }
        if (countCash == 0 && countCashless == 0
           || countCash == 0 && countCredit == 0
           || countCashless == 0 && countCredit == 0){
            return Formula.getSumFormulaByCell(cellIndex(-1, columnShift))
        }
        return Formula.getSumFormulaByCell(cellIndex(-4 - countCashless, columnShift),
                                     '+' + cellIndex(-2 - countCash, columnShift),
                                     '+' + cellIndex(-1, columnShift))
    }

    def countIndex = countCredit + countCash + countCashless

    if(!ticketsCash.isEmpty() || !ticketsCredit.isEmpty()) {
        if (countIndex > 0) {
            text('Всего:', 'baseStyleClearBold', 2, 1)
            5.times { nextColumn() }
            cellFill(createSummaryFormula(0))
            nextColumn()
            cellFill(createSummaryFormula(1))
            nextColumn()
            cellFill(createSummaryFormula(2))
            nextRow()
        }
    }
    8.times {
        text('', 'divide')
        nextColumn()
    }
    nextRow()
}

def sortTableByCodeVariant(List<AirTicketsTemplateReportTicket> listTicket){
    def validatingCarrierToTickets = new HashMap<String, Map<BigDecimal, List<AirTicketsTemplateReportTicket>>>()

    listTicket.each { AirTicketsTemplateReportTicket ticket ->
        def validatingCarrierCode = null
        def ticketCarrier = DictionaryCache.get().resolveReference(ticket.validatingCarrier)
        if (ticketCarrier) {
            validatingCarrierCode = DictHelper.getCodeVariant(ticketCarrier, CodeSystem.CRT, CodeSystem.IATA)
        }
        if (TextUtil.isBlank(validatingCarrierCode)){
            validatingCarrierCode = ''
        }

        def rate = ticket.subagentCommissionRate ? ticket.subagentCommissionRate : BigDecimal.ZERO

        Map<BigDecimal, List<AirTicketsTemplateReportTicket>> commissionToTickets = validatingCarrierToTickets.get(validatingCarrierCode)
        if (!commissionToTickets) {
            commissionToTickets = new HashMap<>()
            validatingCarrierToTickets.put(validatingCarrierCode, commissionToTickets)
        }

        List<AirTicketsTemplateReportTicket> tickets = null
        commissionToTickets.each { BigDecimal key, List<AirTicketsTemplateReportTicket> value ->
            if (MiscUtil.equals(key, rate)) {
                tickets = value
                return
            }
        }
        if (!tickets) {
            tickets = new ArrayList<>()
            commissionToTickets.put(rate, tickets)
        }

        tickets.add(ticket)

    }
    return validatingCarrierToTickets
}

def fillTable(Map<PaymentType, Map<String, List<AirTicketsTemplateReportTicket>>> mapTickets, int itemNumber) {
    int count = 0
    
    mapTickets.each { PaymentType fo, Map<String, List<AirTicketsTemplateReportTicket>> airlineNumberTickets ->//kp

        airlineNumberTickets.each { String airlineNumber, List<AirTicketsTemplateReportTicket> listTicket ->//421

            sortTableByCodeVariant(listTicket).each {String codeVariant, Map<BigDecimal, List<AirTicketsTemplateReportTicket>> cvTickets ->//c7

                cvTickets.each { BigDecimal rate, List<AirTicketsTemplateReportTicket> tickets ->
                    BigDecimal amount = BigDecimal.ZERO
                    BigDecimal subagentTariff = BigDecimal.ZERO
                    BigDecimal vendorTariff = BigDecimal.ZERO

                    tickets.each { AirTicketsTemplateReportTicket ticket ->

                        if(ticket.operationBatch == OperationBatch.REFUND){
                            amount = MiscUtil.sub(amount, ticket.equivalentFare)
                            ticket.segmentTariffs.each { AirTicketsTemplateReportSegmentTariff tariff ->
                                subagentTariff =  MiscUtil.sub(subagentTariff, MiscUtil.negate(tariff.subagentCommissionValue))
                                vendorTariff = MiscUtil.sub(vendorTariff, MiscUtil.negate(tariff.vendorCommissionValue))
                            }
                        } else {
                            amount = MiscUtil.sum(amount, ticket.equivalentFare)
                            ticket.segmentTariffs.each { AirTicketsTemplateReportSegmentTariff tariff ->
                                subagentTariff = MiscUtil.sum(subagentTariff, tariff.subagentCommissionValue)
                                vendorTariff = MiscUtil.sum(vendorTariff, tariff.vendorCommissionValue)
                            }
                        }
                    }
                    rowHeight(1.2*12)
                    number(++itemNumber, 'baseStyle')
                    nextColumn()
                    text(fo.toString(LocaleHelper.RU_LOCALE))
                    nextColumn()
                    text(airlineNumber, 'baseStyle')
                    nextColumn()
                    text(codeVariant, 'baseStyle')
                    nextColumn()
                    number(rate, 'numberDataCenter')
                    nextColumn()
                    number(amount, 'numberData')
                    nextColumn()
                    number(subagentTariff, 'numberData')
                    nextColumn()
                    number(vendorTariff, 'numberData')
                    nextRow()
                    count++
                }
            }
        }
    }
    return count
}

def reportEnd() {
    def ceo = parameters['ceo']
    ceo = ceo ? ceo : ''
    def subagencyName = parameters['SUBAGENCY_NAME']
    subagencyName = subagencyName ? subagencyName : ''
    def agencyName = parameters['AGENCY_NAME']
    agencyName = agencyName ? agencyName : ''
    def executor = parameters['executor']
    executor = executor ? executor : ''
    def mainAccountant = parameters['main_accountant']
    mainAccountant = mainAccountant ? mainAccountant : ''

    text('Генеральный директор', 'textDataCenter', 3, 1)
    5.times {nextColumn()}
    text(subagencyName, 'textDataCenter', 3, 1)
    nextRow()
    text(agencyName, 'textDataCenter', 3, 1)
    nextRow()
    rowHeight(2*12)
    nextColumn()
    text('________________________________________', 'simpleTextData')
    nextColumn()
    text(ceo, 'simpleTextData')
    3.times {nextColumn()}
    text('________________________________________', 'simpleTextData', 2, 1)
    2.times {nextColumn()}
    text(mainAccountant, 'simpleTextData')
    nextRow()
    text('Исполнитель:____________________________', 'simpleTextData', 2, 1)
    2.times {nextColumn()}
    text(executor, 'simpleTextData')

    nextRow()
    rowHeight(1.2*12)
    date(new Date(), 'dateDataClear', 2, 1)
}

page{"Акт"} {
    warn 'report version = ' + '0.1.0'

    reportHeader()
    reportTitle()
    reportBody()
    reportEnd()
}