// Imports

import com.gridnine.xtrip.common.Environment
import com.gridnine.xtrip.common.l10n.model.LocaleHelper
import com.gridnine.xtrip.common.model.booking.OperationBatch
import com.gridnine.xtrip.common.model.booking.TransportationType
import com.gridnine.xtrip.common.model.dict.AddressType
import com.gridnine.xtrip.common.model.dict.CodeSystem
import com.gridnine.xtrip.common.model.dict.DictionaryCache
import com.gridnine.xtrip.common.model.dict.PassportType
import com.gridnine.xtrip.common.model.entity.EntityStorage
import com.gridnine.xtrip.common.model.helpers.DictHelper
import com.gridnine.xtrip.common.model.helpers.ProfileHelper
import com.gridnine.xtrip.common.model.system.PaymentType
import com.gridnine.xtrip.common.util.MiscUtil
import com.gridnine.xtrip.common.util.TextUtil

import java.text.SimpleDateFormat

// Styles
createStyle(name: 'title', h_alignment: 'CENTER', v_alignment: 'CENTER')
createStyle(name: 'titleH1', fontHeight: 14, parent: 'title')
createStyle(name: 'titleH2', fontHeight: 9, parent: 'title')
createStyle(name: 'header', h_alignment: 'CENTER', v_alignment: 'CENTER', fontHeight: 7)
createStyle(name: 'columnHeader', wrapText: true, parent: 'header')
createStyle(name: 'rowHeader', wrapText: true, parent: 'header')
createStyle(name: 'data', h_alignment: 'CENTER', v_alignment: 'CENTER', fontHeight: 7)
createStyle(name: 'dataText', parent: 'data')
createStyle(name: 'dataDate', format: 'm/d/yy', parent: 'data')
createStyle(name: 'dataNumber', h_alignment: 'RIGHT', format: '#,##0.00', parent: 'data')
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')
createStyle(name: 'grey25', foreground: 'GREY_25_PERCENT')

// Properties
def periodBeginParameter = parameters['key-report-params']?.periodBegin
def periodEndParameter = parameters['key-report-params']?.periodEnd
def blankOwnerParameter = parameters['key-report-params']?.blankOwner
def agencyParameter = parameters['key-report-params']?.agency

// Closures
def agency = {

    def agency = EntityStorage.get().resolve(agencyParameter)?.entity
    return agency ? ProfileHelper.getFullName(agency, LocaleHelper.getLocale('ru', 'RU'), false) : 'Не указано'
}

def blankOwner = {

    def blankOwner = EntityStorage.get().resolve(blankOwnerParameter)?.entity
    return blankOwner ? ProfileHelper.getFullName(blankOwner, LocaleHelper.getLocale('ru', 'RU'), false) : 'Не указан'
}

def salesPointCityCode = { it ->

    def salesPoint = EntityStorage.get().resolve(it.salesPoint)?.entity
    def city = Environment.getPublished(DictionaryCache.class).resolveReference(ProfileHelper.filterAddresses(salesPoint?.addresses, AddressType.FACTUAL)?.city)
    return city ? DictHelper.getCodeVariant(city, CodeSystem.CRT) : null
}

def travellerName = { it ->
    String res = TextUtil.nonNullStr(it.cyrillicName).toUpperCase()

    if (TextUtil.isBlank(res)) {
        res = TextUtil.nonNullStr(it.travellerName).toUpperCase()
    }

    return res
}

def birthday = { it ->

    def age = MiscUtil.age(it.travellerBirthday, it.departureDate)

    if(age != null) {

        if(age.getYears() <= 0) {

            if(age.getMonths() <= 1) {
                return Math.max(1, age.getMonths()) + ' МЕСЯЦ'
            } else if(age.getMonths() <= 4) {
                return age.getMonths() + ' МЕСЯЦА'
            } else if(age.getMonths() < 12) {
                return age.getMonths() + ' МЕСЯЦЕВ'
            }

        } else if(age.getYears() < 12) {

            if(age.getYears() <= 1) {
                return age.getYears() + ' ГОД'
            } else if(age.getYears() <= 4) {
                return age.getYears() + ' ГОДА'
            } else if(age.getYears() < 12) {
                return age.getYears() + ' ЛЕТ'
            }
        }
    }

    return ''
}

def passportType = { it ->

    if(it.travellerPassportType == PassportType.INTERNAL) {
        return 'ПСП'
    } else if(it.travellerPassportType == PassportType.IDENTITYCARD) {
        return 'УЛ'
    } else if(it.travellerPassportType == PassportType.BIRTHDAY_NOTIFICATION) {
        return 'СР'
    }

    return ''
}

def period = {

    def periodBegin = parameters['key-report-params']?.periodBegin
    def periodEnd = parameters['key-report-params']?.periodEnd
    def format = new SimpleDateFormat('dd.MM.yyyy')
    return String.format('c %s по %s', periodBegin != null ? format.format(periodBegin) : '?', periodEnd != null ? format.format(periodEnd) : '?')
}

page{it.transportationType == TransportationType.DOMESTIC ? 'ВВЛ' : 'МВЛ'}{

    // Set landcape mode
    landscape(true)

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

    def transportationType = null

    tickets{

        if(it.transportationType != null) {
            transportationType = it.transportationType
        }
    }

    text('Реестр № ______ воинских перевозочных документов (ВПД), на основании которых оформлены авиабилеты к счёту № ______ от ___________', 'titleH2|aac', 18, 1)
    2.times{nextRow()}

    text('Агентство:', 'titleH2|ahr', 3, 1)
    3.times{nextColumn()}
    text(agency(), 'titleH2|ahl')
    nextRow()
    text('Организация-клиент:', 'titleH2|ahr', 3, 1)
    3.times{nextColumn()}
    text('МИНОБОРОНЫ РФ', 'titleH2|ahl')
    7.times{nextColumn()}
    text('Период:', 'titleH2|ahr')
    nextColumn()
    text(period(), 'titleH2|ahl')
    nextRow()
    text('Вид оплаты:', 'titleH2|ahr', 3, 1)
    3.times{nextColumn()}
    text('Воинское требование', 'titleH2|ahl')
    nextRow()
    text('Валюта:', 'titleH2|ahr', 3, 1)
    3.times{nextColumn()}
    text('RUB', 'titleH2|ahl')
    nextRow()
    text('Перевозчик:', 'titleH2|ahr', 3, 1)
    3.times{nextColumn()}
    text(blankOwner(), 'titleH2|ahl')
    5.times{nextColumn()}
    text(transportationType == TransportationType.DOMESTIC ? 'ВВЛ' : 'МВЛ', 'titleH2')
    2.times{nextRow()}

    // Report header
    rowHeight(55, false)
    columnWidth(4)
    text('№ п/п', 'columnHeader|ba')
    nextColumn()
    columnWidth(6)
    text('Личный номер кассира', 'columnHeader|ba')
    nextColumn()
    columnWidth(17)
    text('Пункт оформления перевозочного документа', 'columnHeader|ba')
    nextColumn()
    columnWidth(12)
    text('Серия, номер перевозочного документа', 'columnHeader|ba')
    nextColumn()
    columnWidth(12)
    text('Серия, номер воинского требования', 'columnHeader|ba')
    nextColumn()
    columnWidth(10)
    text('Дата оформления перевозочного документа', 'columnHeader|ba')
    nextColumn()
    columnWidth(10)
    text('Дата  перевозки  (по перевозочному документу)', 'columnHeader|ba')
    nextColumn()
    columnWidth(5)
    text('Перевозчик (код)', 'columnHeader|ba')
    nextColumn()
    columnWidth(5)
    text('Номер рейса', 'columnHeader|ba')
    nextColumn()
    columnWidth(4)
    text('Аэропорт отправления', 'columnHeader|ba')
    nextColumn()
    columnWidth(4)
    text('Аэропорт назначения', 'columnHeader|ba')
    nextColumn()
    columnWidth(24)
    text('Фамилия, имя, отчество пассажира, возраст детей', 'columnHeader|ba')
    nextColumn()
    columnWidth(12)
    text('Наименование, серия, номер документа, удостоверяющего личность', 'columnHeader|ba')
    nextColumn()
    columnWidth(7)
    text('Вид тарифа', 'columnHeader|ba')
    nextColumn()
    columnWidth(9)
    text('Сумма к оплате (в рублях)', 'columnHeader|ba')
    nextColumn()
    columnWidth(9)
    text('Корректировка суммы (в рублях)', 'columnHeader|ba')
    nextColumn()
    columnWidth(9)
    text('Основание корректировки суммы', 'columnHeader|ba')
    nextColumn()
    columnWidth(7)
    text('Тип перевозочного документа', 'columnHeader|ba')
    nextRow()

    def count = 0

    18.times{

        text(String.valueOf(count + 1), 'columnHeader|ba')
        nextColumn()

        count++
    }

    nextRow()

    def products = [:]

    products['sell'] = []
    products['refund'] = []

    tickets{

        def batch = null

        if(it.paymentTypes.contains(PaymentType.MTD)) {

            if(it.operationBatch == OperationBatch.SELL) {
                batch = 'sell'
            } else if(it.operationBatch == OperationBatch.REFUND) {
                batch = 'refund'
            }
        }

        if(batch != null) {
            products[batch].add(it)
        }
    }

    // Sell registry table (header)
    2.times{

        text(null, 'dataText|ba')
        nextColumn()
    }

    text('Продажа:', 'columnHeader|ba')
    nextColumn()

    15.times{

        text(null, 'dataText|ba')
        nextColumn()
    }

    nextRow()

    def sellTicketsCount = 0

    // Sell registry table (ticket rows)
    for(product in products['sell']) {

        text(String.valueOf(sellTicketsCount + 1), 'dataText|ba')
        nextColumn()
        text(product.validator ? product.validator.substring(Math.max(0, product.validator.length() - 5), product.validator.length()) : null, 'dataText|ba')
        nextColumn()
        text(salesPointCityCode(product)?.toString(), 'dataText|ba')
        nextColumn()
        text(product.ticketNumber, 'dataText|ba')
        nextColumn()
        text(product.relatedDocumentNumber, 'dataText|ba')
        nextColumn()
        date(product.issueDate, 'dataDate|ba')
        nextColumn()
        date(product.departureDate, 'dataDate|ba')
        nextColumn()
        text(product.validatingCarrier.getCode(), 'dataText|ba')
        nextColumn()
        text(TextUtil.join('/', product.flightNumbers, true), 'dataText|ba')
        nextColumn()
        text(product.departureLocationCodes.get(CodeSystem.CRT.name()), 'dataText|ba')
        nextColumn()
        text(product.arriveLocationCodes.get(CodeSystem.CRT.name()), 'dataText|ba')
        nextColumn()
        text(travellerName(product) + ' ' + birthday(product), 'dataText|ba')
        nextColumn()
        text(passportType(product) + ' ' + product.travellerPassportNumber, 'dataText|ba')
        nextColumn()
        text(product.fareBasisLine, 'dataText|ba')
        nextColumn()
        number(product.price, 'dataNumber|ba')
        nextColumn()
        number(null, 'dataNumber|ba')
        nextColumn()
        number(null, 'dataNumber|ba')
        nextColumn()
        text(product.eticket ? 'E' : null, 'dataText|ba')
        nextRow()

        sellTicketsCount++
    }

    // Sell registry table (footer)
    text('Итого продажа:', 'columnHeader|ahl|ba', 3, 1)
    3.times{nextColumn()}

    11.times{

        text(null, 'dataText|ba')
        nextColumn()
    }

    3.times{

        if(sellTicketsCount > 0) {
            formula("SUM(${cellIndex(-sellTicketsCount, 0)}:${cellIndex(-1, 0)})", 'dataNumber|ba')
        } else {
            number(BigDecimal.ZERO, 'dataNumber|ba')
        }

        nextColumn()
    }

    text(null, 'dataText|ba')
    nextRow()

    // Refund registry table (header)
    2.times{

        text(null, 'dataText|ba')
        nextColumn()
    }

    text('Возврат:', 'columnHeader|ba')
    nextColumn()

    15.times{

        text(null, 'dataText|ba')
        nextColumn()
    }

    nextRow()

    def refundTicketsCount = 0

    // Refund registry table (ticket rows)
    for(product in products['refund']) {

        text(String.valueOf(refundTicketsCount + 1), 'dataText|ba')
        nextColumn()
        text(product.validator ? product.validator.substring(Math.max(0, product.validator.length() - 5), product.validator.length()) : null, 'dataText|ba')
        nextColumn()
        text(salesPointCityCode(product)?.toString(), 'dataText|ba')
        nextColumn()
        text(product.ticketNumber, 'dataText|ba')
        nextColumn()
        text(product.relatedDocumentNumber, 'dataText|ba')
        nextColumn()
        date(product.issueDate, 'dataDate|ba')
        nextColumn()
        date(product.departureDate, 'dataDate|ba')
        nextColumn()
        text(product.validatingCarrier.getCode(), 'dataText|ba')
        nextColumn()
        text(TextUtil.join('/', product.flightNumbers, true), 'dataText|ba')
        nextColumn()
        text(product.departureLocationCodes.get(CodeSystem.CRT.name()), 'dataText|ba')
        nextColumn()
        text(product.arriveLocationCodes.get(CodeSystem.CRT.name()), 'dataText|ba')
        nextColumn()
        text(travellerName(product) + ' ' + birthday(product), 'dataText|ba')
        nextColumn()
        text(passportType(product) + ' ' + product.travellerPassportNumber, 'dataText|ba')
        nextColumn()
        text(product.fareBasisLine, 'dataText|ba')
        nextColumn()
        number(product.price, 'dataNumber|ba')
        nextColumn()
        number(null, 'dataNumber|ba')
        nextColumn()
        number(null, 'dataNumber|ba')
        nextColumn()
        text(product.eticket ? 'E' : null, 'dataText|ba')
        nextRow()

        refundTicketsCount++
    }

    // Refund registry table (footer)
    text('Итого возврат:', 'columnHeader|ahl|ba', 3, 1)
    3.times{nextColumn()}

    11.times{

        text(null, 'dataText|ba')
        nextColumn()
    }

    3.times{

        if(refundTicketsCount > 0) {
            formula("SUM(${cellIndex(-refundTicketsCount, 0)}:${cellIndex(-1, 0)})", 'dataNumber|ba')
        } else {
            number(BigDecimal.ZERO, 'dataNumber|ba')
        }

        nextColumn()
    }

    text(null, 'dataText|ba')
    nextRow()

    // Total
    text('Итого (продажа-возврат):', 'columnHeader|ahl|ba', 3, 1)
    3.times{nextColumn()}

    11.times{

        text(null, 'dataText|ba')
        nextColumn()
    }

    if(sellTicketsCount > 0 || refundTicketsCount > 0) {
        formula("${cellIndex(-3 - refundTicketsCount, 0)} - ${cellIndex(-1, 0)}", 'dataNumber|ba')
    } else {
        number(BigDecimal.ZERO, 'dataNumber|ba')
    }

    nextColumn()

    2.times{

        number(null, 'dataNumber|ba')
        nextColumn()
    }

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

    text('Требований ВПД:', 'titleH2|ahr', 3, 1)
    3.times{nextColumn()}
    text(sellTicketsCount + refundTicketsCount + ' шт.', 'titleH2|ahl')
    nextRow()

    text('Талонов МО:', 'titleH2|ahr', 3, 1)
    3.times{nextColumn()}
    text(sellTicketsCount + refundTicketsCount + ' шт.', 'titleH2|ahl')
    nextRow()
}
