// Imports

import com.gridnine.xtrip.common.l10n.model.LocaleHelper
import com.gridnine.xtrip.common.model.ClientFop
import com.gridnine.xtrip.common.model.EntityReference
import com.gridnine.xtrip.common.model.booking.OperationBatch
import com.gridnine.xtrip.common.model.booking.ProductStatus
import com.gridnine.xtrip.common.model.dict.CodeSystem
import com.gridnine.xtrip.common.model.dict.CommunicationType
import com.gridnine.xtrip.common.model.dict.GdsName
import com.gridnine.xtrip.common.model.entity.EntityStorage
import com.gridnine.xtrip.common.model.helpers.DictHelper
import com.gridnine.xtrip.common.model.helpers.PersonalLocalizableNameFormatter
import com.gridnine.xtrip.common.model.helpers.ProfileHelper
import com.gridnine.xtrip.common.model.profile.Organization
import com.gridnine.xtrip.common.reports.model.AirTicketsTemplateReportTicket
import com.gridnine.xtrip.common.util.MiscUtil

import java.text.SimpleDateFormat

// Styles
createStyle(name: 'title', h_alignment: 'LEFT', v_alignment: 'CENTER', wrapText: true)
createStyle(name: 'titleH1', fontHeight: 12, parent: 'title')
createStyle(name: 'titleH2', fontHeight: 10, fontBold: true, parent: 'title')
createStyle(name: 'header', h_alignment: 'CENTER', v_alignment: 'CENTER', fontHeight: 8)
createStyle(name: 'columnHeader', fontBold: true, parent: 'header')
createStyle(name: 'rowHeader', parent: 'header')
createStyle(name: 'data', h_alignment: 'LEFT', v_alignment: 'CENTER', fontHeight: 8)
createStyle(name: 'dataText', parent: 'data')
createStyle(name: 'dataDate', format: 'm/d/yy', parent: 'data')
createStyle(name: 'dataNumber', h_alignment: 'RIGHT', parent: 'data')
createStyle(name: 'dataSum', format: '#,##0.00', parent: 'dataNumber')
createStyle(name: 'wrap', wrapText: true)
createStyle(name: 'ahl', h_alignment: 'LEFT')
createStyle(name: 'ahc', h_alignment: 'CENTER')
createStyle(name: 'ahr', h_alignment: 'RIGHT')
createStyle(name: 'avt', v_alignment: 'TOP')
createStyle(name: 'avc', v_alignment: 'CENTER')
createStyle(name: 'avb', v_alignment: 'BOTTOM')
createStyle(name: 'aac', h_alignment: 'CENTER', v_alignment: 'CENTER')
createStyle(name: 'bold', fontBold: true)
createStyle(name: 'italic', fontItalic: true)
createStyle(name: 'bt', topBorder: 'THIN')
createStyle(name: 'bl', leftBorder: 'THIN')
createStyle(name: 'bb', bottomBorder: 'THIN')
createStyle(name: 'br', rightBorder: 'THIN')
createStyle(name: 'ba', topBorder: 'THIN', leftBorder: 'THIN', bottomBorder: 'THIN', rightBorder: 'THIN')

// Closures
def period = {
    SimpleDateFormat sdf = new SimpleDateFormat("dd.MM.yyyy")
    def periodBeginParameter = parameters['key-report-params']?.periodBegin
    def periodEndParameter = parameters['key-report-params']?.periodEnd
    return " за период с " +
            (periodBeginParameter ? sdf.format(periodBeginParameter) : "") +
            " по " +
            (periodEndParameter ? sdf.format(periodEndParameter) : "")
}

def agentName = {
    def person = EntityStorage.get().resolve(parameters['key-report-params']?.agent)?.entity
    def format = new PersonalLocalizableNameFormatter(PersonalLocalizableNameFormatter.SIMPLE)
    return person ? format.format(person, LocaleHelper.getLocale('ru', 'RU'), false) : '?'
}

def agentPhone = {
    def person = EntityStorage.get().resolve(parameters['key-report-params']?.agent)?.entity
    def communication = person ? ProfileHelper.filterPersonCommunications(person.getCommunications(), CommunicationType.WORK_PHONE, parameters['key-report-params']?.agency) : null
    return communication ? ProfileHelper.buildFullPhoneNumber(communication) : '?'
}

def accountantName = {
    def person = EntityStorage.get().resolve(requestedParameter('accountant'))?.entity
    def format = new PersonalLocalizableNameFormatter(PersonalLocalizableNameFormatter.SIMPLE)
    return person ? format.format(person, LocaleHelper.getLocale('ru', 'RU'), false) : '?'
}

def CEOName = {
    def person = EntityStorage.get().resolve(requestedParameter('director'))?.entity
    def format = new PersonalLocalizableNameFormatter(PersonalLocalizableNameFormatter.SIMPLE)
    return person ? format.format(person, LocaleHelper.getLocale('ru', 'RU'), false) : '?'
}

def fillMap = {
    Map ticketsMap = new HashMap()
    tickets { AirTicketsTemplateReportTicket ticket ->
        List<ClientFop> fops = ticket.getClientFops()
        for (EntityReference<Organization> client : requestedParameter('clients')){
            if (ticket.previousTicketNumber == null || ticket.status == ProductStatus.REFUND){

                if (ticketsMap.get(client) == null) {
                    ticketsMap.put(client, new LinkedHashSet<>())
                }
                for (ClientFop fop : fops) {
                    if (fop.getPayer().equals(client)) {
                        ticketsMap.get(client).add(ticket)
                    }
                }
            }
        }
    }
    return ticketsMap
}
def amountOfPayers(AirTicketsTemplateReportTicket ticket, EntityReference<Organization> org) {
    BigDecimal amount = BigDecimal.ZERO
    ticket.getClientFops().each { ClientFop fop ->
        if (fop.payer.equals(org)){
            if (!fop.getUid().contains('MCO')){
                amount = MiscUtil.sum(amount, fop.amount.value)
            }
        }
    }
    return amount
}

//Functions
def cashierPersonalNumber(agent) {
    def result = 'Не указано'
    def cashier = EntityStorage.get().resolve(agent)?.entity
    if (cashier != null) {
        cashier.getGdsReferences().each {
            if (it.getGdsName() == GdsName.SIRENA)
                result = it.getReference()
        }
    }
    return result
}

def isRefund(ticket) {
    return ticket.operationBatch == OperationBatch.REFUND
}

def nextRowWithHeight(height) {
    rowHeight(height)
    nextRow()
}

def printFee(AirTicketsTemplateReportTicket ticket, int counter) {
    nextRowWithHeight(25)
    number(++counter, 'dataText|ba')
    nextColumn()
    text(cashierPersonalNumber(ticket.getAgent()), 'dataText|ba')
    nextColumn()
    text(ticket.militaryClaimNumber ? ticket.militaryClaimNumber : "", 'dataText|ba')
    nextColumn()
    text((ticket.validatingCarrierNumber ? ticket.validatingCarrierNumber + " " : "") +
            (ticket.ticketNumber ? ticket.ticketNumber : ""), 'dataText|ba')
    nextColumn()
    text(ticket.validatingCarrier ? DictHelper.getCodeVariant(ticket.validatingCarrier, CodeSystem.CRT) : "", 'dataText|ba')
    nextColumn()
    date(ticket.issueDate, 'dataDate|ba')
    nextColumn()
    date(ticket.departureDate, 'dataDate|ba')
    nextColumn()
    text("", 'dataText|ba')
    nextColumn()
    number(isRefund(ticket) ? BigDecimal.ZERO : ticket.clientFeeValue, 'dataSum|ba')
    nextColumn()
    number(isRefund(ticket) ? ticket.clientFeeValue : BigDecimal.ZERO, 'dataSum|ba')
    2.times {
        nextColumn()
        text("", 'dataText|ba')
    }
}

Map ticketsMap = fillMap()
requestedParameter('clients').forEach() { EntityReference<Organization> org ->
    Organization client = EntityStorage.get().resolve(org)?.entity
    Set<AirTicketsTemplateReportTicket> ticketsList = ticketsMap.get(org) ? ticketsMap.get(org) : new ArrayList<>()
    Set mtdSet = new HashSet()

    page { 'Реестр ' + client.getShortName().toString().replaceAll("\\d*\\*", "") } {
        // Set landscape mode
        landscape(true)

        // Set narrow margins
        margin(0.25, 0.25, 0.75, 0.75)

        // Set scale
        scale(100)

        // Set preserve mode
        preserve(false)

// Report header
        text('Реестр перевозочных документов по требованиям ' +
                client + period(), 'title|ba|avb', 12, 1)
        nextRowWithHeight(40)

// Table header
        text('№', 'columnHeader|wrap|ba')
        nextColumn()
        text('Касса', 'columnHeader|wrap|ba')
        nextColumn()
        text('№ документа', 'columnHeader|wrap|ba')
        nextColumn()
        text('Тип, серия, № а/б', 'columnHeader|wrap|ba')
        nextColumn()
        text('А/К', 'columnHeader|wrap|ba')
        nextColumn()
        text('Дата продажи', 'columnHeader|wrap|ba')
        nextColumn()
        text('Дата вылета', 'columnHeader|wrap|ba')
        nextColumn()
        text('Маршрут', 'columnHeader|wrap|ba')
        nextColumn()
        text('Продажа', 'columnHeader|wrap|ba')
        nextColumn()
        text('Возврат', 'columnHeader|wrap|ba')
        nextColumn()
        text('Вид тарифа', 'columnHeader|wrap|ba')
        nextColumn()
        text('ФИО пассажира', 'columnHeader|wrap|ba')

        nextRowWithHeight(25)

// Table
        int counter = 0

        ticketsList.forEach() {
            number(++counter, 'dataText|ba')
            nextColumn()
            text(cashierPersonalNumber(it.getAgent()), 'dataText|ba')
            nextColumn()
            text(it.militaryClaimNumber ? it.militaryClaimNumber : "", 'dataText|ba')
            nextColumn()
            text((it.validatingCarrierNumber ? it.validatingCarrierNumber + " " : "") +
                    (it.ticketNumber ? it.ticketNumber : ""), 'dataText|ba')
            nextColumn()
            text(it.validatingCarrier ? DictHelper.getCodeVariant(it.validatingCarrier, CodeSystem.CRT) : "", 'dataText|ba')
            nextColumn()
            date(it.issueDate, 'dataDate|ba')
            nextColumn()
            date(it.departureDate, 'dataDate|ba')
            nextColumn()
            text(it.crtRouteLine, 'dataText|ba')
            nextColumn()
            number(isRefund(it) ? BigDecimal.ZERO : amountOfPayers(it, org), 'dataSum|ba')
            nextColumn()
            number(isRefund(it) ? it.price : BigDecimal.ZERO, 'dataSum|ba')
            nextColumn()
            text(it.fareBasisLine, 'dataText|ba')
            nextColumn()
            text(it.travellerName ? it.travellerName : "", 'dataText|ba')

            if (it.militaryClaimNumber != null && !isRefund(it)) {
                mtdSet.add(it.militaryClaimNumber)
            }

            if (it.clientFeeValue != null) {
                printFee(it, counter)
                counter++
            }

            nextRowWithHeight(25)
        }

        //Summary block
        rowHeight(30)
        2.times {
            text('', 'dataText|ba')
            nextColumn()
        }
        text('ИТОГО', 'dataText|ba|avb|bold')
        6.times {
            nextColumn()
            text('', 'dataText|ba')
        }
        if (!ticketsList.isEmpty()){
            formula("SUM(I3:${cellIndex(-1, 0)})", 'dataSum|ba|avb|bold')
            nextColumn()
            formula("SUM(J3:${cellIndex(-1, 0)})", 'dataSum|ba|avb|bold')
        } else {
            number(BigDecimal.ZERO, 'dataSum|ba|avb|bold')
            nextColumn()
            number(BigDecimal.ZERO, 'dataSum|ba|avb|bold')
        }

        2.times {
            nextColumn()
            text('', 'dataText|ba')
        }
        nextRow()

        2.times { nextColumn() }
        text('Кол-во ВПД ' + mtdSet.size() + ' шт.', 'dataText')
        nextRow()

        // Auto width
        15.times {
            columnAutoWidth()
            nextColumn()
        }
        nextRow()

        //Manual column width
        7.times { nextColumn() }
        columnWidth(20)
        nextColumn()
        columnWidth(20)
        nextColumn()
        columnWidth(20)
        nextRow()

        //Credits
        2.times { nextRow() }
        4.times { nextColumn() }
        text('Генеральный директор:', 'titleH2|ahl', 3, 1)
        3.times { nextColumn() }
        text('', 'bb')
        nextColumn()
        text(CEOName(), 'titleH2|ahl')

        2.times { nextRow() }
        4.times { nextColumn() }
        text('Главный бухгалтер:', 'titleH2|ahl', 3, 1)
        3.times { nextColumn() }
        text('', 'bb')
        nextColumn()
        text(accountantName(), 'titleH2|ahl')

        2.times { nextRow() }
        4.times { nextColumn() }
        def signPlace = '  _______________________'
        text('Представитель ' + client.shortName + signPlace, 'titleH2|ahl', 8, 1)

        2.times { nextRow() }
        text('Исполнил: ', 'dataText', 2, 1)
        2.times { nextColumn() }
        text(agentName(), 'dataText')
        nextRow()
        text('тел./факс', 'dataText', 2, 1)
        2.times { nextColumn() }
        text(agentPhone(), 'dataText')
    }
}