import com.gridnine.xtrip.common.Environment
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.ProductStatus
import com.gridnine.xtrip.common.model.booking.SimpleTax
import com.gridnine.xtrip.common.model.booking.TransportationType
import com.gridnine.xtrip.common.model.booking.air.Tax
import com.gridnine.xtrip.common.model.dict.CommunicationType
import com.gridnine.xtrip.common.model.dict.DictionaryCache
import com.gridnine.xtrip.common.model.dict.ProductCategory
import com.gridnine.xtrip.common.model.entity.EntityStorage
import com.gridnine.xtrip.common.model.helpers.FinanceHelper
import com.gridnine.xtrip.common.model.profile.Address
import com.gridnine.xtrip.common.model.profile.Communication
import com.gridnine.xtrip.common.model.profile.Organization
import com.gridnine.xtrip.common.model.system.Metadata
import com.gridnine.xtrip.common.model.system.MetadataKey
import com.gridnine.xtrip.common.model.system.MetadataKeyDescriptor
import com.gridnine.xtrip.common.reports.model.AirTicketsTemplateReportParameters
import com.gridnine.xtrip.common.reports.model.AirTicketsTemplateReportSegmentTariff
import com.gridnine.xtrip.common.reports.model.AirTicketsTemplateReportTicket
import com.gridnine.xtrip.common.reports.model.AirTicketsTemplateReportSegment
import com.gridnine.xtrip.common.util.MiscUtil
import com.gridnine.xtrip.common.util.TextUtil

//CREATING STYLES
createStyle(name: 'baseStyle', fontBold: true,  h_alignment: 'LEFT', v_alignment: 'CENTER', fontHeight:12, leftBorder:'THIN', rightBorder:'THIN', topBorder:'THIN', bottomBorder:'THIN')
createStyle(name: 'headerStyle', parent: 'baseStyle', h_alignment: 'CENTER')
createStyle(name: 'style', fontBold: false, fontHeight: 11, parent: 'baseStyle')
createStyle(name: 'textData', parent: 'style')
createStyle(name: 'textDataBold', parent: 'baseStyle')
createStyle(name: 'dateData', format: 'm/d/yy', parent: 'style',  v_alignment: 'CENTER')
createStyle(name: 'dateDataNotBorder',format: 'm/d/yy', fontBold: false, h_alignment: 'LEFT', v_alignment: 'CENTER', fontHeight:11)
createStyle(name: 'dateDataBold', format: 'm/d/yy', parent: 'baseStyle', v_alignment: 'CENTER')
createStyle(name: 'numberData', format: '#,##0.00', parent: 'style',  h_alignment: 'RIGHT', v_alignment: 'CENTER')
createStyle(name: 'emptyNumberData', parent: 'style')
createStyle(name: 'numberDataBold', format: '#,##0.00', parent: 'baseStyle',  h_alignment: 'RIGHT', v_alignment: 'CENTER')

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 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, 'baseStyle')
        }
    } else {
        text('', 'baseStyle')
    }
}

static def getOrganization(EntityReference<Organization> erO) {
    EntityContainer<Organization> ecO = EntityStorage.get().resolve(erO)
    return ecO?.entity
}

static def getOrganizationPhone (Organization org) {
    def phone = ''
    org?.communications?.each { Communication communication->
        if(communication.type == CommunicationType.WORK_PHONE) {
            phone = communication.countryCode + communication.cityCode + communication.sense
        }
    }
    return phone
}

def reportHeader (EntityReference<Organization> orgRef) {

    def getOrganizationCode = { Organization org ->
        def utAgencyCode = ''
        for(Metadata md : org.metadata) {
            MetadataKeyDescriptor mdKd = Environment.getPublished(DictionaryCache.class).resolveReference(md.key)
            if (mdKd != null) {
                if(MetadataKey.KEY_UT_AGENCY_CODE.name().equals(mdKd.code)) {
                    utAgencyCode  = md.value.toString()
                }
            }
        }
        return utAgencyCode
    }

    def getOrganizationCountry = {Organization org ->
        def defaultCountry = ''
        org.addresses.each { Address address ->
            String country = address.country.toString(LocaleHelper.RU_LOCALE)
            if(TextUtil.nonBlank(country)) {
                defaultCountry = country
            }
        }
        return defaultCountry
    }

    def scw = 12

    Organization org = getOrganization(orgRef)
    def orgName = ''
    def orgCode = ''
    def orgCountry = ''
    def orgPhone = ''
    def currency = FinanceHelper.getDefaultCurrency().code
    def currentDate = new Date()

    if (org != null) {
        orgName = org.fullName.toString(LocaleHelper.RU_LOCALE)
        orgCode = getOrganizationCode(org)
        orgCountry = getOrganizationCountry(org)
        orgPhone = getOrganizationPhone(org)
    }

    rowHeight(2*scw)
    columnWidth(scw)
    text(parameters['header'], 'headerStyle', 8, 1)
    nextRow()
    text('Авиакомпания', 'baseStyle', 2, 1)
    2.times {nextColumn()}
    columnWidth(2*scw)
    text('ЮТЭЙР', 'baseStyle')
    nextColumn()
    columnWidth(1.5*scw)
    text('Код:', 'baseStyle')
    nextColumn()
    columnWidth(2.5*scw)
    text('UT', 'baseStyle')
    nextColumn()
    columnWidth(2*scw)
    text('Отчет', 'baseStyle')
    nextColumn()
    columnWidth(2*scw)
    text(parameters['title'], 'baseStyle', 2, 1)
    nextRow()
    rowHeight(2*scw)
    text('Агент', 'baseStyle', 2, 1)
    2.times {nextColumn()}
    text(orgName, 'baseStyle')
    nextColumn()
    text('Код:', 'baseStyle')
    nextColumn()
    text(orgCode, 'baseStyle')
    nextColumn()
    text('Период', 'baseStyle')
    nextColumn()
    text(parameters.REPORT_PERIOD, 'baseStyle', 2, 1)
    nextRow()
    rowHeight(2*scw)
    text('Валюта', 'baseStyle', 2, 1)
    2.times {nextColumn()}
    text(currency, 'baseStyle')
    nextColumn()
    text('Дата', 'baseStyle')
    nextColumn()
    date(currentDate, 'dateDataBold')
    nextColumn()
    text('Стр:', 'baseStyle')
    nextColumn()
    text(orgCountry, 'baseStyle', 2, 1)
    nextRow()
    rowHeight(2*scw)
    text('Контактный телефон', 'baseStyle', 2, 1)
    2.times {nextColumn()}
    text(orgPhone, 'baseStyle', 1 , 1)
    1.times {nextColumn()}
    text('% агентского вознаграждения по договору', 'baseStyle', 3, 1)
    3.times{nextColumn()}
    text(' ', 'baseStyle', 2, 1)
    2.times {nextRow()}

}


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

def reportTitle() {
    rowHeight(30)
    printColumnHeader('№ п/п', 8)                   // 1
    printColumnHeader('Номер документа', 22)        // 2
    printColumnHeader('Дата операции', 0)           // 3
    printColumnHeader('Маршрут', 15)                // 4
    printColumnHeader('Код тарифа', 15)             // 5
    printColumnHeader('Тариф', 0)                   // 6
    printColumnHeader('Сборы', 22)                  // 7
//    printColumnHeader('Тариф', 15)                  // 8
//    printColumnHeader('Сборы', 15)                  // 9
    printColumnHeader('Сумма аг. вознагр.', 22)     // 10
    printColumnHeader('К перечислению', 20)         // 11
    nextRow()
    rowHeight(15)
    for (i in 1..9)
        printColumnHeader(i + '', 0)
    nextRow()
}

def reportBody() {
    int index = 0
    def vvl = new ArrayList<>()
    def mvl = new ArrayList<>()
    allTickets.each { AirTicketsTemplateReportTicket ticket ->
        if (ticket.transportationType == TransportationType.DOMESTIC) {
            vvl.add(ticket)
        } else  {
            mvl.add(ticket)
        }
    }
    cellFill('ВВЛ')
    nextRow()
    index = fillTable(vvl)
    if (index > 0) {
        text('Промежуточный итог', 'baseStyle', 2, 1)
        nextColumn()
        3.times {
            nextColumn()
            cellFill('')
        }
        nextColumn()
        2.times {
            cellFill(Formula.getSumFormulaByRow(cellIndex(-index, 0), cellIndex(-1, 0)))
            nextColumn()
        }
        2.times {
            cellFill('')
            nextColumn()
        }
        2.times {
            cellFill(Formula.getSumFormulaByRow(cellIndex(-index, 0), cellIndex(-1, 0)))
            nextColumn()
        }
        nextRow()
    }
    cellFill('МВЛ')
    nextRow()
    index = fillTable(mvl)
    if (index > 0) {
        5.times { nextColumn() }
        2.times {
            cellFill(Formula.getSumFormulaByRow(cellIndex(-index, 0), cellIndex(-1, 0)))
            nextColumn()
        }
        2.times {
            nextColumn()
        }
        2.times {
            cellFill(Formula.getSumFormulaByRow(cellIndex(-index, 0), cellIndex(-1, 0)))
            nextColumn()
        }
        nextRow()
    }
}

def getFee(List<Tax> taxes) {
    BigDecimal fees = BigDecimal.ZERO
    if (taxes != null) {
        for (Tax tax : taxes) {
            if ((tax.code != null) && (tax.equivalentAmount != null)) {
                fees = MiscUtil.sum(fees, tax.equivalentAmount)
            }
        }
    }
    return fees
}

def fillTable(ArrayList<AirTicketsTemplateReportTicket> tickets) {
    int count = 0
    int index = 0
    tickets.each { AirTicketsTemplateReportTicket ticket ->
        number(++count, 'baseStyle'); nextColumn()
        boolean first = true
        if (ticket.segmentTariffs.isEmpty()){
            cellFill(ticket.blankOwnerNumber + ' ' + ticket.ticketNumber); nextColumn()
            cellFill(ticket.issueDate)
            8.times {
                nextColumn()
                cellFill('')
            }
            nextRow()
            index++
            first = false
        }
        ticket.segmentTariffs.each { AirTicketsTemplateReportSegmentTariff tariff ->
            if(!first) {
                cellFill(''); nextColumn()
            }
            cellFill(ticket.blankOwnerNumber + ' ' + ticket.ticketNumber); nextColumn()
            cellFill(ticket.issueDate); nextColumn()
            if(ticket.status =~ ProductStatus.VOID && ticket.productCategory =~ ProductCategory.AIR) {
                cellFill('Аннулирован')
                7.times {
                    nextColumn()
                    cellFill('')
                }
                nextRow()
                index++
                first = false
            } else {
                String fareBasis = ''
                String route = ''
                tariff.segments.each { AirTicketsTemplateReportSegment segment ->
                    route += segment.routeLine
                    route += ' '
                    fareBasis += segment.fareBasis
                    fareBasis += ' '
                }
                cellFill(route); nextColumn()
                cellFill(fareBasis); nextColumn()
                cellFill(tariff.tariff); nextColumn()
                BigDecimal taxesSum = first ? getFee(ticket.taxes) : BigDecimal.ZERO
                cellFill(taxesSum); nextColumn()
//                cellFill(''); nextColumn()
//                cellFill(''); nextColumn()
                cellFill(tariff.vendorCommissionValue); nextColumn()
                cellFill(MiscUtil.sum(tariff.tariff, MiscUtil.sub(taxesSum, tariff.vendorCommissionValue)))

                nextRow()
                index++
                first = false
            }
        }
    }
    return index
}

def reportEnd(EntityReference<Organization> orgRef) {

    def ceo = ''
    def accountant = ''
    def currentDate = new Date()

    if (parameters['ceo'] != null) ceo = parameters['ceo']
    if (parameters['main_accountant'] != null) accountant = parameters['main_accountant']

    nextColumn()
    text('Генеральный директор', 'simpleTextData', 2, 1)
    2.times {nextColumn()}
    text('_____________________', 'simpleTextData', 2, 1)
    2.times {nextColumn()}
    text('/ ' + ceo + '/', 'simpleTextData', 2, 1)
    2.times {nextColumn()}
    text('Исп. ________', 'simpleTextData')
    nextRow()
    nextColumn()
    text('Главный бухгалтер', 'simpleTextData', 2, 1)
    2.times {nextColumn()}
    text('_____________________', 'simpleTextData', 2, 1)
    2.times {nextColumn()}
    text('/ ' + accountant + '/', 'simpleTextData', 2, 1)
    2.times {nextColumn()}
    text('Тел.' + getOrganizationPhone(getOrganization(orgRef)), 'simpleTextData')
    nextRow()
    7.times {nextColumn()}
    date(currentDate, 'dateDataNotBorder')
    nextRow()
}

page{parameters['title']} {
    warn 'report version = ' + '0.1.0'

    AirTicketsTemplateReportParameters airTicketParams = parameters.params
    EntityReference<Organization> orgRef = airTicketParams.agency

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