import com.gridnine.xtrip.common.model.booking.OperationBatch
import com.gridnine.xtrip.common.model.booking.ProductStatus
import com.gridnine.xtrip.common.model.booking.TransportationType
import com.gridnine.xtrip.common.model.dict.MCOCategory
import com.gridnine.xtrip.common.model.dict.ProductCategory
import com.gridnine.xtrip.common.model.system.PaymentType
import com.gridnine.xtrip.common.reports.model.AirTicketsTemplateReportParameters
import com.gridnine.xtrip.common.reports.model.AirTicketsTemplateReportTicket
import com.gridnine.xtrip.common.reports.model.AirTicketsTemplateReportTicketType
import com.gridnine.xtrip.common.util.MiscUtil
import com.gridnine.xtrip.common.model.booking.air.Tax
import com.gridnine.xtrip.common.util.TextUtil

createStyle(name: "left", h_alignment: "LEFT")
createStyle(name: "right", h_alignment: "RIGHT")
createStyle(name: "center", h_alignment: "CENTER")
createStyle(name: "left-bold", h_alignment: "LEFT", fontBold : true)
createStyle(name: "right-bold", h_alignment: "RIGHT", fontBold : true)
createStyle(name: "center-bold", h_alignment: "CENTER", fontBold : true)
createStyle(name: "left-bold-border", h_alignment: "LEFT", fontBold : true,
        leftBorder:'THIN', rightBorder:'THIN', topBorder:'THIN', bottomBorder:'THIN', wrapText: true)
createStyle(name: "right-bold-border", h_alignment: "RIGHT", fontBold : true,
        leftBorder:'THIN', rightBorder:'THIN', topBorder:'THIN', bottomBorder:'THIN', wrapText: true)
createStyle(name: "center-bold-border", h_alignment: "CENTER", fontBold : true,
        leftBorder:'THIN', rightBorder:'THIN', topBorder:'THIN', bottomBorder:'THIN', wrapText: true)
createStyle(name: "left-border", h_alignment: "LEFT", leftBorder:'THIN', rightBorder:'THIN',
        topBorder:'THIN', bottomBorder:'THIN', wrapText: true)
createStyle(name: "right-border", h_alignment: "RIGHT", leftBorder:'THIN', rightBorder:'THIN',
        topBorder:'THIN', bottomBorder:'THIN', wrapText: true)
createStyle(name: "center-border", h_alignment: "CENTER", leftBorder:'THIN', rightBorder:'THIN',
        topBorder:'THIN', bottomBorder:'THIN', wrapText: true)
createStyle(name: "dateDataBold", format: 'm/d/yy', parent: 'left-bold-border')
createStyle(name: "dateData", format: 'm/d/yy', parent: 'center-border')
createStyle(name: 'numberData', format: '#,##0.00', parent: 'center-border')

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

    static Formula getSumFormulaByRow (def start, def 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 printEmptyBorderedCell() {
    text("", "left-bold-border")
    nextColumn()
}

def printHead(AirTicketsTemplateReportParameters airTicketParams) {
    text("РАСЧЕТНОЕ ПИСЬМО", "left", 4, 1); rowHeight(15); 2.times {nextRow()}
    text("Авиакомпания", "left-bold-border", 2, 1); 2.times {nextColumn()}
    text("АО\"А/к\"Якутия\" ", "left-bold-border", 2, 1); 2.times {nextColumn()}
    printEmptyBorderedCell()
    text("Код:", "left-bold-border"); nextColumn()
    text("ЯК", "left-bold-border", 2, 1); 2.times {nextColumn()}
    text("Отчет:", "left-bold-border"); nextColumn()
    printEmptyBorderedCell()

    nextRow()
    rowHeight(15)
    text("Агент", "left-bold-border", 2, 1); 2.times {nextColumn()}
    text(airTicketParams.agency.caption, "left-bold-border", 2, 2); 2.times {nextColumn()}
    printEmptyBorderedCell()
    text("Код:", "left-bold-border"); nextColumn()
    text(parameters['agency_agreement_number']?:"", "left-bold-border", 2, 2); 2.times {nextColumn()}
    text("Период:", "left-bold-border"); nextColumn()
    date(airTicketParams.periodBegin, "dateDataBold")

    nextRow()
    rowHeight(15)
    2.times {printEmptyBorderedCell()}; 2.times {nextColumn()}
    2.times {printEmptyBorderedCell()}
    printEmptyBorderedCell(); nextColumn()
    printEmptyBorderedCell()
    date(airTicketParams.periodEnd, "dateDataBold")

    nextRow()
    rowHeight(15)
    text("Страна", "left-bold-border", 2, 1); 2.times {nextColumn()}
    text("Россия", "left-bold-border"); nextColumn()
    2.times {printEmptyBorderedCell()}
    text("Валюта:", "left-bold-border"); nextColumn()
    text("Руб.", "left-bold-border", 2, 1); 2.times {nextColumn()}
    text("Дата", "left-bold-border"); nextColumn()
    date(new Date(), "dateDataBold")

    nextRow()
    rowHeight(15)
    text("Телефон", "left-bold-border", 2, 1); 2.times {nextColumn()}
    text("Факс"); nextColumn()
    3.times {printEmptyBorderedCell()}
    text("", "left-bold-border", 2, 1); 2.times {nextColumn()}
    text("Стр.", "left-bold-border"); nextColumn()
    printEmptyBorderedCell()

    2.times {nextRow()}
}

def printTitle() {
    rowHeight(15)
    text("№", "center-bold-border")
    nextColumn()
    text("РАЗДЕЛ", "center-bold-border", 6, 1)
    3.times {
        2.times {
            nextColumn()
        }
        columnWidth(15)
    }
    text("ВСЕГО", "center-bold-border")
    nextColumn()
    text("МВЛ", "center-bold-border")
    columnWidth(15)
    nextColumn()
    text("ВВЛ", "center-bold-border")
    columnWidth(15)
    nextRow()
}

static def prepareTableData (List<AirTicketsTemplateReportTicket> tickets) {

    def data = []

    def sellTariff = BigDecimal.ZERO
    def sellYQTax = BigDecimal.ZERO
    def yrTax = BigDecimal.ZERO
    def sellOtherTax = BigDecimal.ZERO
    def sellCommissions = BigDecimal.ZERO

    def refTariff = BigDecimal.ZERO
    def refYQYRTaxes = BigDecimal.ZERO
    def refOtherTax = BigDecimal.ZERO
    def refAirportTax = BigDecimal.ZERO
    def refPenalty = BigDecimal.ZERO
    def refCommissions = BigDecimal.ZERO

    def memoSum = BigDecimal.ZERO

    def sellLuggage = BigDecimal.ZERO
    def sellUnescortedMinor = BigDecimal.ZERO
    def refLuggage = BigDecimal.ZERO
    def refUnescortedMinor = BigDecimal.ZERO

    def sumByCash = BigDecimal.ZERO
    def sumByMTD = BigDecimal.ZERO

    int countOfSells = 0
    int countOfRefs = 0

    def countSell = {AirTicketsTemplateReportTicket t->
        BigDecimal sumByPaymentType = BigDecimal.ZERO
        if (t.type == AirTicketsTemplateReportTicketType.MEMO) {
            memoSum = MiscUtil.sum(memoSum, t.agencyMemoProductTariffEquivalentAmount)
        } else if (t.productCategory == ProductCategory.MCO) {
            if(t.mcoCategory == MCOCategory.EXCESS_LUGGAGE) {
                sellLuggage = MiscUtil.sum(sellLuggage, t.equivalentFare)
            } else if (t.mcoCategory == MCOCategory.UNESCORTED_MINOR) {
                sellUnescortedMinor = MiscUtil.sum(sellUnescortedMinor, t.equivalentFare)
            } else {
                refPenalty = MiscUtil.sum(refPenalty, t.price)
            }
            sumByPaymentType = t.equivalentFare
        } else if (t.productCategory == ProductCategory.AIR) {
            sellTariff = MiscUtil.sum(sellTariff, t.equivalentFare)
            sellTariff = MiscUtil.sum(sellTariff, t.penalty)
            t.taxes.each {Tax tax ->
                if (TextUtil.isSame(tax.code, 'YQ')) {
                    sellYQTax = MiscUtil.sum(sellYQTax, tax.equivalentAmount)
                    sumByPaymentType = MiscUtil.sum(sumByPaymentType, tax.equivalentAmount)
                } else if (TextUtil.isSame(tax.code, 'YR')) {
                    yrTax = MiscUtil.sum(yrTax, tax.equivalentAmount)
                    sumByPaymentType = MiscUtil.sum(sumByPaymentType, tax.equivalentAmount)
                } else {
                    sellOtherTax = MiscUtil.sum(sellOtherTax, tax.equivalentAmount)
                    sumByPaymentType = MiscUtil.sum(sumByPaymentType, tax.equivalentAmount)
                }
            }
            sumByPaymentType = MiscUtil.sum(sumByPaymentType, t.equivalentFare)
        } else if (t.productCategory == ProductCategory.EXCESS_BAGAGE) {
            sellTariff = MiscUtil.sum(sellTariff, t.equivalentFare)
        }
        sellCommissions = MiscUtil.sum(sellCommissions, t.vendorCommissionValue)
        if (t.status != ProductStatus.EXCHANGE) {
            countOfSells++
        }
        return sumByPaymentType
    }

    def countRef = {AirTicketsTemplateReportTicket t->
        BigDecimal sumByPaymentType = BigDecimal.ZERO
        if (t.productCategory == ProductCategory.MCO) {
            if (t.mcoCategory == MCOCategory.EXCESS_LUGGAGE) {
                refLuggage = MiscUtil.sum(refLuggage, t.equivalentFare)
                refPenalty = MiscUtil.sum(refPenalty, t.penalty)
            } else if (t.mcoCategory == MCOCategory.UNESCORTED_MINOR) {
                refUnescortedMinor = MiscUtil.sum(refUnescortedMinor, t.equivalentFare)
                refPenalty = MiscUtil.sum(refPenalty, t.penalty)
            } else {
                if (t.mcoCategory == MCOCategory.PENALTY && t.status == ProductStatus.REFUND) {
                    refPenalty = MiscUtil.sub(refPenalty, t.price)
                } else {
                    refPenalty = MiscUtil.sum(refPenalty, t.price)
                }
            }
            sumByPaymentType = MiscUtil.sub(sumByPaymentType, t.equivalentFare)
        } else if (t.productCategory == ProductCategory.AIR) {
            refPenalty = MiscUtil.sum(refPenalty, t.penalty)
            refTariff = MiscUtil.sum(refTariff, t.equivalentFare)
            sumByPaymentType = MiscUtil.sub(sumByPaymentType, t.equivalentFare)
            t.taxes.each {Tax tax ->
                if (TextUtil.isSame(tax.code, 'YQ') || TextUtil.isSame(tax.code, 'YR')) {
                    refYQYRTaxes = MiscUtil.sum(refYQYRTaxes, tax.equivalentAmount)
                    sumByPaymentType = MiscUtil.sub(sumByPaymentType, tax.equivalentAmount)
                } else {
                    refOtherTax = MiscUtil.sum(refOtherTax, tax.equivalentAmount)
                    sumByPaymentType = MiscUtil.sub(sumByPaymentType, tax.equivalentAmount)
                }
            }
        } else if (t.productCategory == ProductCategory.EXCESS_BAGAGE) {
            sellTariff = MiscUtil.sum(sellTariff, t.equivalentFare)
        }
        refCommissions = MiscUtil.sum(refCommissions, t.vendorCommissionValue)
        sumByPaymentType = MiscUtil.sum(sumByPaymentType, t.penalty)
        countOfRefs++
        return sumByPaymentType
    }

    tickets.each {AirTicketsTemplateReportTicket ticket ->
        switch (ticket.operationBatch) {
            case OperationBatch.SELL:
            case OperationBatch.EXCHANGE:
                if (ticket.paymentTypes.contains(PaymentType.MTD)) {
                    sumByMTD = MiscUtil.sum(countSell(ticket), sumByMTD)
                } else {
                    sumByCash = MiscUtil.sum(countSell(ticket), sumByCash)
                }
                break
            case OperationBatch.REFUND:
                if (ticket.paymentTypes.contains(PaymentType.MTD)) {
                    sumByMTD = MiscUtil.sum(countRef(ticket), sumByMTD)
                } else {
                    sumByCash = MiscUtil.sum(countRef(ticket), sumByCash)
                }
                break
        }
    }

    //sell
    data.add(sellTariff)          //0
    data.add(sellYQTax)           //1
    data.add(yrTax)               //2
    data.add(BigDecimal.ZERO)     //3
    data.add(sellLuggage)         //4
    data.add(BigDecimal.ZERO)     //5
    data.add(sellUnescortedMinor) //6
    data.add(sellCommissions)     //7
    data.add(BigDecimal.ZERO)     //8
    //refund
    data.add(refTariff)           //9
    data.add(refYQYRTaxes)        //10
    data.add(BigDecimal.ZERO)     //11
    data.add(refLuggage)          //12
    data.add(BigDecimal.ZERO)     //13
    data.add(refUnescortedMinor)  //14
    data.add(refPenalty)          //15
    data.add(refCommissions)      //16
    //additional
    data.add(BigDecimal.ZERO)     //17
    data.add(BigDecimal.ZERO)     //18
    data.add(sumByCash)           //19
    data.add(sumByMTD)            //20
    data.add(BigDecimal.ZERO)     //21
    data.add(countOfSells)        //22
    data.add(countOfRefs)         //23
    //Other Taxes
    data.add(sellOtherTax)        //24
    data.add(refOtherTax)         //25

    return data
}

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

def printRow(def row, int rowH) {
    text(row[0], "center-border")
    nextColumn()
    rowHeight(rowH)
    text(row[1], "center-border", 6, 1)
    6.times {nextColumn()}
    cellFill(row[2])
    nextColumn()
    cellFill(row[3])
    nextColumn()
    cellFill(row[4])
    nextRow()
}

def printTickets() {

    List<AirTicketsTemplateReportTicket> vvlTickets = new ArrayList<>()
    List<AirTicketsTemplateReportTicket> mvlTickets = new ArrayList<>()

    allTickets.each { AirTicketsTemplateReportTicket ticket ->
        if(ticket.transportationType == TransportationType.DOMESTIC) {
            vvlTickets.add(ticket)
        } else if(ticket.transportationType == TransportationType.INTERNATIONAL
                || ticket.transportationType == TransportationType.COMBINED) {
            mvlTickets.add(ticket)
        }
    }

    def vvl = prepareTableData(vvlTickets)
    def mvl = prepareTableData(mvlTickets)

    def negateCell = {def cellIndex ->
        return '-' + cellIndex
    }

    def sellFormula = {int column ->
        return Formula.getSumFormulaByCell(cellIndex(1, column), cellIndex(2, column),
                cellIndex(3, column), cellIndex(4, column), cellIndex(5, column), negateCell(cellIndex(9, column)))
    }

    def refFormula = {int column ->
        return Formula.getSumFormulaByCell(cellIndex(1, column), cellIndex(2, column), cellIndex(3, column),
                cellIndex(4, column), negateCell(cellIndex(8 , column)), negateCell(cellIndex(9, column)))
    }

    def addPayFormula = {int column, int rowShift ->
        return Formula.getSumFormulaByCell(cellIndex(rowShift + 1, column), cellIndex(rowShift + 2, column), cellIndex(rowShift + 3, column))
    }

    def rowFormula = {
        return Formula.getSumFormulaByRow(cellIndex(0, 8), cellIndex(0, 9))
    }

    def paymentTypeFormula = {int column ->
        return Formula.getSumFormulaByCell(cellIndex(1, column), cellIndex(2, column))
    }

    def resultFormula = {int column ->
        return Formula.getSumFormulaByCell(cellIndex(-3, column), negateCell(cellIndex(-1, column)),
                negateCell(cellIndex(-2, column)), negateCell(cellIndex(-4, column)),
                negateCell(cellIndex(-7, column)), negateCell(cellIndex(-8, column)),
                negateCell(cellIndex(-18, column)), cellIndex(-29, column))
    }

    def balanceFormula = {int column ->
        return Formula.getSumFormulaByCell(cellIndex(-7, column), cellIndex(-37, column), negateCell(cellIndex(-6, column)))
    }

    def listedFormula = {int column ->
        return Formula.getSumFormulaByRow(cellIndex(1, column), cellIndex(5, column))
    }

    def sumTaxSell = {arr ->
        def sum = BigDecimal.ZERO
        sum = MiscUtil.sum(sum, arr[4], arr[5], arr[6], arr[24])
        return sum
    }

    def sumTaxRef = {arr ->
        def sum = BigDecimal.ZERO
        sum = MiscUtil.sum(sum, arr[12], arr[13], arr[14], arr[25])
        return sum
    }

    printRow(['',    'Сальдо на начало периода'
              , rowFormula(), BigDecimal.ZERO, BigDecimal.ZERO], 15)
    printRow(['1',   'Продажа'
              , sellFormula(7), sellFormula(8), sellFormula(9)], 15)
    printRow(['1.1', 'Тариф расчетный (за перевозку пассажиров и/или сверхнормативного багажа)'
              , rowFormula(), mvl[0], vvl[0]], 30)
    printRow(['1.2', 'Топливный сбор'
              , rowFormula(), mvl[1], vvl[1]], 15)
    printRow(['1.3', 'Такса YR'
              , rowFormula(), mvl[2], vvl[2]], 15)
    printRow(['1.4', 'Аэропортовый сбор (МВЛ)'
              , rowFormula(), mvl[3], vvl[3]], 15)
    printRow(['1.5', 'Дополнительные сборы'
              , rowFormula(), sumTaxSell(mvl), sumTaxSell(vvl)], 15)
    printRow(['1.5.1', 'Сборы за перевозку тяжеловесного и/или негабаритного багажа'
              , rowFormula(), mvl[4], vvl[4]], 15)
    printRow(['1.5.2', 'Спец. тариф за перевозку багажа с объявленной ценностью (% от суммы объявленной ценности)'
              , rowFormula(), mvl[5], vvl[5]], 30)
    printRow(['1.5.3', 'Сборы за перевозку несопровождаемого ребенка'
              , rowFormula(), mvl[6], vvl[6]], 15)
    printRow(['1.6', 'Комиссионные'
              , rowFormula(), mvl[7], vvl[7]], 15)
    printRow(['1.7', 'Корректировка комиссии'
              , rowFormula(), mvl[8], vvl[8]], 15)
    printRow(['2', 'Возврат'
              , refFormula(7), refFormula(8), refFormula(9)], 15)
    printRow(['2.1', 'Тариф расчетный (за перевозку пассажиров и/или сверхнормативного багажа)'
              , rowFormula(), mvl[9], vvl[9]], 30)
    printRow(['2.2', 'Топливный сбор'
              , rowFormula(), mvl[10], vvl[10]], 15)
    printRow(['2.3', 'Аэропортовый сбор (МВЛ)'
              , rowFormula(), mvl[11], vvl[11]], 15)
    printRow(['2.4', 'Дополнительные сборы'
              , rowFormula(), sumTaxRef(mvl), sumTaxRef(vvl)], 15)
    printRow(['2.4.1', 'Сборы за перевозку тяжеловесного и/или негабаритного багажа'
              , rowFormula(), mvl[12], vvl[12]], 15)
    printRow(['2.4.2', 'Спец. тариф за перевозку багажа с объявленной ценностью (% от суммы объявленной ценности)'
              , rowFormula(), mvl[13], vvl[13]], 30)
    printRow(['2.4.3', 'Сборы за перевозку несопровождаемого ребенка'
              , rowFormula(), mvl[14], vvl[14]], 15)
    printRow(['2.5', 'Штрафы (% Удержание от тарифа и/или Сбор за возврат/обмен билетов)'
              , rowFormula(), mvl[15], vvl[15]], 30)
    printRow(['2.6',  'Комиссионные'
              , rowFormula(), mvl[16], vvl[16]], 15)
    printRow(['3', 'Дополнительные комиссионные по программе "Агент-Бонус"'
              , rowFormula(), mvl[17], vvl[17]], 15)
    printRow(['4', 'Дополнительные комиссионные'
              , rowFormula(), mvl[18], vvl[18]], 15)
    printRow(['5', 'По формам оплаты'
              , paymentTypeFormula(7), paymentTypeFormula(8), paymentTypeFormula(9)], 15)
    printRow(['5.1', 'Наличные'
              , rowFormula(), mvl[19], vvl[19]], 15)
    printRow(['5.2', 'Организации-клиенты КР МО'
              , rowFormula(), mvl[20], vvl[20]], 15)
    printRow(['6', 'Расчеты по претензионным уведомлениям'
              , rowFormula(), mvl[21], vvl[21]], 15)
    printRow(['7', 'Оформеление/переоформление на рейсы других перевозчиков по распоряжениям АК(№ документа, дата)'
              , rowFormula(), BigDecimal.ZERO, BigDecimal.ZERO], 30)
    printRow(['8', 'Взаиморасчеты (№ документа, дата)'
              , rowFormula(), BigDecimal.ZERO, BigDecimal.ZERO], 15)
    printRow(['9', 'Итого к перечислению в АК'
              , resultFormula(7), resultFormula(8), resultFormula(9)], 15)
    printRow(['10', 'Перечислено '
              , listedFormula(7), listedFormula(8), listedFormula(9)], 15)
    printRow(['10.1',  ''
              , rowFormula(), BigDecimal.ZERO, BigDecimal.ZERO], 15)
    printRow(['10.2',  ''
              , rowFormula(), BigDecimal.ZERO, BigDecimal.ZERO], 15)
    printRow(['10.3',  ''
              , rowFormula(), BigDecimal.ZERO, BigDecimal.ZERO], 15)
    printRow(['10.4',  ''
              , rowFormula(), BigDecimal.ZERO, BigDecimal.ZERO], 15)
    printRow(['10.5',  ''
              , rowFormula(), BigDecimal.ZERO, BigDecimal.ZERO], 15)
    printRow(['11',  'Сальдо на конец периода'
              , balanceFormula(7), balanceFormula(8), balanceFormula(9)], 15)
    printRow(['12',  'Продано документов (без аннулированных БСО)'
              , rowFormula(), mvl[22], vvl[22]], 15)
    printRow(['13',  'Возвращено БСО'
              , rowFormula(), mvl[23], vvl[23]], 15)
}

def printEnd() {
    nextRow()
    rowHeight(15)
    text('Бухгалтер', 'center', 3, 1)
    3.times {
        nextColumn()
    }
    def creator = parameters['report_author_name']
    text(creator, 'center', 3, 1)
    2.times {nextRow()}
    text('Исполнитель:', 'center', 3, 1)
    3.times {
        nextColumn()
    }
    text(creator, 'center', 3, 1)
}

page{"Расчетное письмо"} {
    // 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(false)

    AirTicketsTemplateReportParameters airTicketParams = parameters.params
    printHead(airTicketParams)
    printTitle()
    printTickets()
    printEnd()
}