
import com.gridnine.xtrip.common.l10n.model.LocaleHelper;
import com.gridnine.xtrip.common.model.EntityContainer;
import com.gridnine.xtrip.common.model.EntityReference;
import com.gridnine.xtrip.common.model.booking.Payment;
import com.gridnine.xtrip.common.model.booking.ProductStatus;
import com.gridnine.xtrip.common.model.booking.air.Tax;
import com.gridnine.xtrip.common.model.booking.commission.ProductType;
import com.gridnine.xtrip.common.model.dict.MCOCategory;
import com.gridnine.xtrip.common.model.dict.ManagerType;
import com.gridnine.xtrip.common.model.dict.ProductCategory;
import com.gridnine.xtrip.common.model.entity.EntityStorage;
import com.gridnine.xtrip.common.model.helpers.AirProductHelper;
import com.gridnine.xtrip.common.model.helpers.ProfileHelper;
import com.gridnine.xtrip.common.model.profile.Organization;
import com.gridnine.xtrip.common.model.profile.Person;
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.util.MiscUtil;

//CREATING STYLES
createStyle(name: 'title', h_alignment: 'CENTER', v_alignment: 'CENTER')
createStyle(name: 'titleH1',fontBold: true, fontHeight: 12, parent: 'title')
createStyle(name: 'titleH2',fontBold: false,h_alignment: 'LEFT', fontHeight: 9, parent: 'title')
createStyle(name: 'header', fontBold: true,  h_alignment: 'CENTER', v_alignment: 'CENTER', fontHeight:9, leftBorder:'MEDIUM', rightBorder:'MEDIUM', topBorder:'MEDIUM', bottomBorder:'MEDIUM', wrapText: true)
createStyle(name: 'columnHeader', fontHeight: 9, parent: 'header')
createStyle(name: 'rowHeader',fontHeight: 9, h_alignment: 'LEFT', wrapText: true, parent: 'titleH2')
createStyle(name: 'data', h_alignment: 'LEFT', v_alignment: 'CENTER', fontHeight: 7)
createStyle(name: 'textData', parent: 'data')
createStyle(name: 'textDataBold', parent: 'data',fontBold: true)
createStyle(name: 'dateData', format: 'm/d/yy', parent: 'data')
createStyle(name: 'dateDataBold', format: 'm/d/yy', parent: 'data',fontBold: true)
createStyle(name: 'numberData', h_alignment: 'RIGHT', format: '#,##0.00', parent: 'data')
createStyle(name: 'numberDataBold', h_alignment: 'RIGHT', format: '#,##0.00', parent: 'data',fontBold: true)
createStyle(name: 'metadataTitle',fontBold: true, h_span: 2, h_alignment: 'RIGHT', v_alignment: 'CENTER', fontHeight:10)
createStyle(name: 'metadataValue', parent: 'metadataTitle', h_span: 10, fontBold: false, h_alignment: 'LEFT')
createStyle(name: 'metadataDateValue', parent: 'metadataValue', format: 'm/d/yy')
createStyle(name: 'statusGroupTitle', parent: 'header', h_span: 4, fontBold: true)
createStyle(name: 'statusGroupNumber',parent: 'header', h_span: 2)
createStyle(name: 'subagencyGroupTitle', parent: 'statusGroupTitle')
createStyle(name: 'totalTitle', parent: 'subagencyGroupTitle')
createStyle(name: 'totalNumber',parent: 'totalTitle', h_span: 1)
createStyle(name: 'subGroup',parent: 'header', h_span: 2, v_span :1)
createStyle(name: 'group',parent: 'header', h_span: 1, v_span :1)
createStyle(name: 'titleH0',fontBold: true, fontHeight: 12, parent: 'title', h_span :3)
createStyle(name: 'smallTitle',fontBold: true, h_span: 1, h_alignment: 'RIGHT', v_alignment: 'CENTER', fontHeight:10)
createStyle(name: 'smallTitleSpan3',fontBold: true, h_span: 3, h_alignment: 'RIGHT', v_alignment: 'CENTER', fontHeight:10)
createStyle(name: 'GroupNumber',parent: 'header', v_span: 2)
createStyle(name: 'wrap', wrapText: true)

//ADDITIONAL FUNCTIONS
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 + ')')
    }
}

String[] blankTypes = ['ak', 'tkp', 'other']
String[] taxesAirlineSet = ['RU', 'Ru', 'ru', 'РУ', 'ру', 'Ру']
//String[] taxesAgsSet = ['cc', 'dd'] // all other taxes

def cellFill = { 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, 'textData')
        }
    }
}
def cellFillBold = { value ->
    if (value != null) {
        if (value instanceof Number) {
            number(value,'numberDataBold')
        } else if (value instanceof Date) {
            date(value,'dateDataBold')
        } else {
            text(value, 'textDataBold')
        }
    }
}

def getOrgReference = { String type ->
    AirTicketsTemplateReportParameters airTicketParams = parameters.params

    if(type.equals('agency')){
        return airTicketParams?.agency
    } else if(type.equals('supplier')){
        return airTicketParams?.supplier
    } else {
        return null
    }
}

def getPaymentTypeInt = { List<PaymentType> list ->
    if(list.any { return (it == PaymentType.CASH) || (it == PaymentType.INVOICE) }) return 1
    else if(list.any { return (it == PaymentType.CREDIT_CARD) || (it == PaymentType.CREDIT_CARD_AGENCY) }) return 2
    return 3
}

def reportHead = { EntityReference<Organization> orgRefAgency ->
    def orgName     = ''
    def datePeriod  = parameters.REPORT_PERIOD

    Organization org = EntityStorage.get().resolve(orgRefAgency)?.entity
    if(org != null){
        orgName = org.fullName.toString()
    }

    rowHeight(13)
    nextColumn();text('Расчетное письмо по авиакомпании Ангара', 'titleH0')
    nextRow();
    text('Дата создания', 'metadataTitle')
    nextColumn();text(datePeriod,'smallTitle');
    nextRow();

    text('Наименование агентства', 'metadataTitle');
    nextColumn();text(orgName,'smallTitleSpan3');

}

def createBodyHead = {
    int scw = 10

    nextRow();
    rowHeight(13);
    nextRow();
    setStyle('columnHeader')
    rowHeight(40)
    columnWidth(0.6*scw);
    text('№п/п', 'GroupNumber');
    nextColumn();columnWidth(2*scw);text('Наименование статьи выручки', 'GroupNumber')
    nextColumn();columnWidth(2*scw);text('Всего', 'GroupNumber')
    nextColumn();columnWidth(4*scw);text('В том числе', 'subGroup')
    nextRow()
    setStyle('columnHeader')
    3.times{nextColumn()};columnWidth(2*scw);text('Бланки а/к', 'group')
    nextColumn();columnWidth(2*scw);text('Бланки ТКП', 'group')

    setStyle('columnHeader')

    nextRow();text('1')
    nextColumn();text('2')
    nextColumn();text('3')
    nextColumn();text('4')
    nextColumn();text('5')
    rowHeight(12)
}

def createBody = {
    Map<String,Object> map = new HashMap<String,Object>()

    warn 'size=' + allTickets.size()

    allTickets.each { AirTicketsTemplateReportTicket ticket ->
        //                                                               2G
        if (ProfileHelper.isOrganizationCode(ticket.blankOwner, "ИК")) {
            if (map.get(blankTypes[0]) == null) map.put(blankTypes[0], [])
            map.get(blankTypes[0]).add(ticket)
        } else if (ProfileHelper.isOrganizationCode(ticket.blankOwner, "Ш1")) {
            if (map.get(blankTypes[1]) == null) map.put(blankTypes[1], [])
            map.get(blankTypes[1]).add(ticket)
        } else {
            if (map.get(blankTypes[2]) == null) map.put(blankTypes[2], [])
            map.get(blankTypes[2]).add(ticket)
        }
    }

    return map
}

def makeCalculation = { List<AirTicketsTemplateReportTicket> list ->
    def table = []

    def sell        = BigDecimal.ZERO
    def luggage     = BigDecimal.ZERO
    def penatly     = BigDecimal.ZERO
    def refund      = BigDecimal.ZERO
    def sellRta     = BigDecimal.ZERO
    def taxesAirline= BigDecimal.ZERO
    def taxesAgs    = BigDecimal.ZERO

    def commissionPass      = BigDecimal.ZERO
    def commissionluggage   = BigDecimal.ZERO


    list.each{ AirTicketsTemplateReportTicket ticket ->
        if (getPaymentTypeInt(ticket.paymentTypes) == 1) {

            BigDecimal multiplier = BigDecimal.ONE;
            BigDecimal commission = ticket.vendorCommissionValue != null ?
            (ticket.status == ProductStatus.REFUND ? ticket.vendorCommissionValue.negate() : ticket.vendorCommissionValue) : BigDecimal.ZERO;
            if(ticket.productCategory == ProductCategory.EXCESS_BAGAGE){
                luggage = MiscUtil.sum(luggage,ticket.equivalentFare)
                commissionluggage = MiscUtil.sum(commissionluggage, commission)
            } else if (ticket.productCategory == ProductCategory.MCO) {
                if(ticket.mcoCategory == MCOCategory.PTA){
                    sellRta = MiscUtil.sum(sellRta,ticket.equivalentFare)
                    commissionPass = MiscUtil.sum(commissionPass, commission)
                } else if (ticket.mcoCategory == MCOCategory.PENALTY) {
                    penatly = MiscUtil.sum(penatly,ticket.price)
                    commissionPass = MiscUtil.sum(commissionPass, commission)
                }
            } else if (ticket.productCategory == ProductCategory.AIR) {
                if (ticket.status == ProductStatus.SELL) {
                    sell = MiscUtil.sum(sell,ticket.equivalentFare)
                    commissionPass = MiscUtil.sum(commissionPass, commission)
                } else if (ticket.status == ProductStatus.REFUND) {
                    refund = MiscUtil.sum(refund,ticket.equivalentFare)
                    commissionPass = MiscUtil.sum(commissionPass, commission)
                    multiplier = multiplier.negate();
                }
            }

            ticket.taxes.each { Tax tax ->
                if (tax.equivalentAmount != null && !"ZZ".equals(tax.code)) {
                    def value = ticket.status == ProductStatus.SELL ? (tax.equivalentAmount) : tax.equivalentAmount.negate()
                    if(taxesAirlineSet.contains(tax.code)) {
                        taxesAirline = taxesAirline.add(value)
                    }
                    else {
                        taxesAgs = taxesAgs.add(value)
                    }
                }
            }
        }
    }

    table.add(MiscUtil.sum(sell, luggage, penatly, refund.negate(), sellRta))
    table.add(sell)
    table.add(luggage)
    table.add(penatly)
    table.add(refund)
    table.add(sellRta)

    table.add(MiscUtil.sum(commissionPass,commissionluggage))
    table.add(commissionPass)
    table.add(commissionluggage)

    table.add(MiscUtil.sum(taxesAirline, taxesAgs))
    table.add(taxesAirline)
    table.add(taxesAgs)

    return table
}

def fillTableResult = {Map<String,Object> map ->
    def table = []

    def tableAk = map?.get(blankTypes[0])
    def tableTch= map?.get(blankTypes[1])

    tableAk = makeCalculation(map?.get(blankTypes[0]))
    tableTch= makeCalculation(map?.get(blankTypes[1]))

    def rowShift    = 1
    def columnShift = -1

    def createFormulaForRow = {int row ->
        return Formula.getSumFormulaByRow(
        cellIndex(rowShift + row,columnShift),
        cellIndex(rowShift + row,columnShift+1)
        )
    }

    def createFormulaForSummTransfer = {int column ->
        return Formula.getSumFormulaByCell(
            cellIndex(rowShift + 3,columnShift + column),
            cellIndex(rowShift + 4,columnShift + column),
            cellIndex(rowShift + 5,columnShift + column),
            cellIndex(rowShift + 11,columnShift + column),
            '-' + cellIndex(rowShift + 6,columnShift + column),
            '-' + cellIndex(rowShift + 14,columnShift + column)
            )
    }

    def createFormulaForResult = {int column ->
        return Formula.getSumFormulaByCell(
        cellIndex(rowShift + 0,columnShift + column),
        cellIndex(rowShift + 16,columnShift + column),
        '-' +cellIndex(rowShift + 17,columnShift + column)
        )
    }

    int row = 0
    table.add(['1', 'Сальдо на начало отчетного месяца', createFormulaForRow(row++), '', ''])

    table.add(['2', 'Выручка пассажирской, всего', createFormulaForRow(row++), tableAk[0], tableTch[0]])
    table.add(['', 'в том числе:', '', '', '']); row++
    table.add(['2.1', 'Тариф', createFormulaForRow(row++), tableAk[1], tableTch[1]])
    table.add(['2.2', 'Багаж', createFormulaForRow(row++), tableAk[2], tableTch[2]])
    table.add(['2.3', 'Штрафные санкции', createFormulaForRow(row++), tableAk[3], tableTch[3]])
    table.add(['2.4', 'Возврат', createFormulaForRow(row++), tableAk[4], tableTch[4]])
    table.add(['2.5', 'Продажа РТА', createFormulaForRow(row++), tableAk[5], tableTch[5]])

    table.add(['3', 'Выручка почтово-грузовая, всего', createFormulaForRow(row++), '', ''])
    table.add(['3.1', 'Выручка почтовая', createFormulaForRow(row++), '', ''])
    table.add(['3.2', 'Выручка грузовая', createFormulaForRow(row++), '', ''])

    table.add(['4', 'Таксы авиакомпании', createFormulaForRow(row++),  tableAk[9], tableTch[9]])
    table.add(['', 'в том числе: таксы А/К', createFormulaForRow(row++),  tableAk[10], tableTch[10]])
    table.add(['', 'АГС', createFormulaForRow(row++),  tableAk[11], tableTch[11]])

    table.add(['5', 'Комиссионный сбор, всего', createFormulaForRow(row++), tableAk[6], tableTch[6]])
    table.add(['5.1', 'от пассажирской выручки', createFormulaForRow(row++), tableAk[7], tableTch[7]])
    table.add(['5.2', 'от платного багажа', createFormulaForRow(row++), tableAk[8], tableTch[8]])
    table.add(['5.3', 'от почтовой выручки', createFormulaForRow(row++), '', ''])
    table.add(['5.4', 'от грузовой выручки', createFormulaForRow(row++), '', ''])

    table.add(['6', 'Сумма к перечислению', createFormulaForRow(row++), createFormulaForSummTransfer(0), createFormulaForSummTransfer(1)])

    table.add(['7', 'Перечислено, всего', createFormulaForRow(row++), '', ''])
    table.add(['', 'в том числе:', '', '', '']); row++
    table.add(['7.1', 'На расчетный счет Авиакомпании', createFormulaForRow(row++), '', ''])
    table.add(['7.2', 'По распоряжению Авиакомпании', createFormulaForRow(row++), '', ''])
    table.add(['7.3', 'ВЗ', createFormulaForRow(row++), '', ''])

    table.add(['8', 'Сальдо на конец отчетного месяца', createFormulaForRow(row++), createFormulaForResult(0), createFormulaForResult(1)])

    return table
}

def fillBody = { Map<String,Object> body ->
    def table = fillTableResult(body)

    table.each { row ->
        nextRow()
        rowHeight(12)

        row.each {
            cellFill(it)
            nextColumn()
        }
    }
}

def reportBody = { EntityReference<Organization> orgRefAgency ->
    createBodyHead()
    Map<String,Object> map = createBody()
    fillBody(map)
}

def reportEnd = { EntityReference<Organization> orgRefAgency ->
    def directorAgency          = ''
    def mainAccountantAgency    = ''

    Organization orgAgency  = EntityStorage.get().resolve(orgRefAgency)?.entity

    if(orgAgency != null){
        EntityReference<Person> erP = ProfileHelper.getManager(orgRefAgency, ManagerType.CHIEF_ACCOUNTANT, new Date())
        if(erP != null){
            EntityContainer<Person> ecP = EntityStorage.get().resolve(erP)
            mainAccountantAgency = ProfileHelper.getFullName(ecP.entity,LocaleHelper.getCurrentLocale(), false)
        }
        erP = ProfileHelper.getManager(orgRefAgency, ManagerType.DIRECTOR, new Date())
        if(erP != null){
            EntityContainer<Person> ecP = EntityStorage.get().resolve(erP)
            directorAgency = ProfileHelper.getFullName(ecP.entity,LocaleHelper.getCurrentLocale(), false)
        }
    }

    nextRow()
    nextRow();text('Подписи агента','metadataTitle')
    nextRow();text('Директор','metadataTitle')
    nextColumn();text(directorAgency,'smallTitleSpan3')
    nextRow();text('Главный бухгалтер','metadataTitle')
    nextColumn();text(mainAccountantAgency,'smallTitleSpan3')

    nextRow();
    text('','metadataTitle')
    nextRow();text('Подписи перевозчика','metadataTitle')
    nextRow();text('Директор','metadataTitle')
    nextRow();text('Главный бухгалтер','metadataTitle')

}

EntityReference<Organization> orgRefAgency  = getOrgReference('agency')
//REPORT
page{'Расчетное письмо'}{

    fitWidth(1)
    fitHeight(1)

    // Set portrait mode
    landscape(false)

    reportHead(orgRefAgency)
    reportBody(orgRefAgency)
    reportEnd(orgRefAgency)
}