import com.gridnine.xtrip.common.l10n.model.LocaleHelper
import com.gridnine.xtrip.common.model.EntityReference
import com.gridnine.xtrip.common.model.booking.OperationBatch
import com.gridnine.xtrip.common.model.dict.CodeSystem
import com.gridnine.xtrip.common.model.dict.DictionaryCache
import com.gridnine.xtrip.common.model.dict.DictionaryReference
import com.gridnine.xtrip.common.model.dict.GeoLocation
import com.gridnine.xtrip.common.model.dict.LocationType
import com.gridnine.xtrip.common.model.entity.EntityStorage
import com.gridnine.xtrip.common.model.helpers.DictHelper
import com.gridnine.xtrip.common.model.helpers.SystemHelper
import com.gridnine.xtrip.common.model.profile.Address
import com.gridnine.xtrip.common.model.profile.Organization
import com.gridnine.xtrip.common.model.profile.SalesPoint
import com.gridnine.xtrip.common.model.system.MetadataKey
import com.gridnine.xtrip.common.reports.model.AirTicketsTemplateReportTicket
import com.gridnine.xtrip.common.util.MiscUtil
import com.gridnine.xtrip.common.util.TextUtil
import org.joda.time.Period

import java.text.SimpleDateFormat

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: "center-center-bold", h_alignment: "CENTER", v_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: "left-center-bold-border", h_alignment: "LEFT", v_alignment: "CENTER", fontBold : true, leftBorder:'THIN', rightBorder:'THIN', topBorder:'THIN', bottomBorder:'THIN', wrapText: true)
createStyle(name: "left-center-bold", h_alignment: "LEFT", v_alignment: "CENTER", fontBold : 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: "center-center-border", h_alignment: "CENTER", v_alignment: "CENTER", leftBorder:'THIN', rightBorder:'THIN', topBorder:'THIN', bottomBorder:'THIN', wrapText: true)
createStyle(name: "right-center-border", h_alignment: "RIGHT", v_alignment: "CENTER", leftBorder:'THIN', rightBorder:'THIN', topBorder:'THIN', bottomBorder:'THIN', wrapText: true)
createStyle(name: "right-center-border-number", format: "#,##0.00", h_alignment: "RIGHT", v_alignment: "CENTER", leftBorder:'THIN', rightBorder:'THIN', topBorder:'THIN', bottomBorder:'THIN', wrapText: true)
createStyle(name: "center-center-bold-border", fontBold : true, h_alignment: "CENTER", v_alignment: "CENTER", leftBorder:'THIN', rightBorder:'THIN', topBorder:'THIN', bottomBorder:'THIN', wrapText: true)
createStyle(name: "center-border-number", h_alignment: "CENTER", leftBorder:'THIN', rightBorder:'THIN', topBorder:'THIN', bottomBorder:'THIN', wrapText: true)
createStyle(name: "center-center-border-number", format: "#,##0.00", h_alignment: "CENTER", v_alignment: "CENTER", leftBorder:'THIN', rightBorder:'THIN', topBorder:'THIN', bottomBorder:'THIN', wrapText: true)

def printTitle() {
    rowHeight(30); text("Реестр № ___________________ ", "center-center-bold", 15, 1)
    nextRow(); rowHeight(15); text("воинских перевозочных документов (ВПД), ", "center-center-bold", 15, 1)
    nextRow(); text("на основании которых оформлены авиабилеты к счёту № _______________ от ___________", "center-center-bold", 15, 1)

    nextRow(); nextRow(); text("Агентство:", "left", 3, 1)
    nextColumn(); nextColumn(); nextColumn(); text(agencyCode(), "right")
    nextColumn(); text(parameters['AGENCY_NAME'], "left", 5, 1)
    5.times {
        nextColumn()
    }
    text("Период:", "left-bold")

    SimpleDateFormat sdf = new SimpleDateFormat("dd.MM.yyyy")
    def periodBeginParameter = parameters['key-report-params']?.periodBegin
    def periodEndParameter = parameters['key-report-params']?.periodEnd

    nextColumn()
    text((periodBeginParameter ? sdf.format(periodBeginParameter) : "") +
            " - " +
            (periodEndParameter ? sdf.format(periodEndParameter) : ""),
            "left-bold", 2, 1)

    nextRow(); rowHeight(5)
    nextRow(); rowHeight(15); text("Организация-клиент:", "left", 3, 1)
    nextColumn(); nextColumn(); nextColumn(); text("МИНОБОРОНЫ РФ", "left-bold", 2, 1)

    nextRow(); rowHeight(5)

    nextRow(); rowHeight(15); text("Вид оплаты:", "left", 3, 1)
    nextColumn(); nextColumn(); nextColumn(); text("Воинское требование", "left", 2, 1)

    nextRow(); rowHeight(5)

    nextRow(); rowHeight(15); text("Валюта:", "left", 3, 1)
    nextColumn(); nextColumn(); nextColumn(); text("RUB", "left", 2, 1)

    nextRow(); rowHeight(5)

    nextRow(); rowHeight(15); text("Перевозчик:", "left", 3, 1)
    nextColumn(); nextColumn(); nextColumn(); text("А/К \"Сибирь\"", "left", 2, 1)

    nextRow(); nextRow()
    text("ВВЛ " + parameters['pageName'], "left-bold", 6, 1)
    nextRow()
}

def agencyCode() {
    Organization agency = (Organization) EntityStorage.get().resolve(parameters['key-report-params']?.agency)?.entity

    String res = agency ? SystemHelper.findMetadataAsString(agency.getMetadata(), MetadataKey.KEY_S7_AGENCY_CODE) : null

    return res ? res : ''
}

def printHeader() {
    nextRow(); rowHeight(75)

    text("№ п/п", "center-center-bold-border")
    nextColumn(); text("Личный" + "\n" + "номер" + "\n" + "кассира", "center-center-bold-border")
    nextColumn(); text("Пункт" + "\n" + "оформления" + "\n" + "перевозочного" + "\n" + "документа", "center-center-bold-border")
    nextColumn(); text("Серия, номер" + "\n" + "перевозочного" + "\n" + "документа", "center-center-bold-border")
    nextColumn(); text("Серия, номер" + "\n" + "воинского" + "\n" + "требования", "center-center-bold-border")
    nextColumn(); text("Дата оформления" + "\n" + "перевозочного" + "\n" + "документа", "center-center-bold-border")
    nextColumn(); text("Дата перевозки" + "\n" + "(по перевозочному" + "\n" + "документу)", "center-center-bold-border")
    nextColumn(); text("Перевозчик (код)", "center-center-bold-border")
    nextColumn(); text("Номер рейса", "center-center-bold-border")
    nextColumn(); text("Аэропорт" + "\n" + "отправления", "center-center-bold-border")
    nextColumn(); text("Аэропорт" + "\n" + "назначения", "center-center-bold-border")
    nextColumn(); text("Фамилия, имя," + "\n" + "отчество" + "\n" + "пассажира" + "\n" + "возраст детей", "center-center-bold-border")
    nextColumn(); text("Наименование," + "\n" + "серия, номер документа," + "\n" + "удостоверяющего" + "\n" + "личность", "center-center-bold-border")
    nextColumn(); text("Вид тарифа", "center-center-bold-border")
    nextColumn(); text("Сумма к оплате" + "\n" + "(в рублях)", "center-center-bold-border")
    nextColumn(); text("Корректировка" + "\n" + "суммы" + "\n" + "(в рублях)", "center-center-bold-border")
    nextColumn(); text("Основание" + "\n" + "корректировки" + "\n" + "суммы", "center-center-bold-border")
    nextColumn(); text("Вид тарифа" + "\n" + "(из АСБ)", "center-center-bold-border")

    nextRow(); rowHeight(15)

    int i = 0
    18.times {
        i++
        text(String.valueOf(i))
        nextColumn()
    }

}

def printTickets() {
    Map<OperationBatch, List<AirTicketsTemplateReportTicket>> ticketsMap = collectTicketsByOpBatch()
    List<AirTicketsTemplateReportTicket> sellTickets = ticketsMap.get(OperationBatch.SELL)
    List<AirTicketsTemplateReportTicket> refundTickets = ticketsMap.get(OperationBatch.REFUND)

    printBatch(sellTickets, "Продажа")
    printBatch(refundTickets, "Возврат")

    nextRow(); text("ИТОГО:", "left-center-bold-border", 3, 1)

    13.times {
        nextColumn(); text("")
    }

    nextColumn()
    formula("${cellIndex(-(3 + refundTickets.size()), 0)}-${cellIndex(-1, 0)}", "center-center-border-number")

    3.times {
        nextColumn(); text("")
    }

    nextRow(); nextRow(); nextColumn()

    text("Требований ВПД - " + mtdCount(ticketsMap) +  " шт.", "left-center-bold", 2, 1)
}

def printBatch(List<AirTicketsTemplateReportTicket> ticketsList, String batchName) {
    SimpleDateFormat sdf = new SimpleDateFormat("dd.MM.yy")

    nextRow(); text(batchName + ":", "left-center-bold-border", 15, 1)

    ticketsList.eachWithIndex { ticket, index ->
        nextRow(); rowHeight(15)

        text(String.valueOf(index + 1), "center-center-border")

        nextColumn()
        text(ticket.validator ? ticket.validator.substring(Math.max(0, ticket.validator.length() - 5), ticket.validator.length()) : "")

        nextColumn()
        text(salesPointCityCode(ticket.salesPoint))

        nextColumn()
        text(ticket.ticketNumber ? ticket.ticketNumber : "")

        nextColumn()
        text(ticket.militaryClaimNumber ? ticket.militaryClaimNumber : "")

        nextColumn()
        text(ticket.issueDate ? sdf.format(ticket.issueDate) : "")

        nextColumn()
        text(ticket.departureDate ? sdf.format(ticket.departureDate) : "")

        nextColumn()
        text("S7")

        nextColumn()
        text(TextUtil.join(", ", new LinkedHashSet(ticket.flightNumbers)))

        nextColumn()
        text(locName(ticket.departureGeoLocation))

        nextColumn()
        text(locName(ticket.arriveGeoLocation))

        nextColumn()
        text(travellerName(ticket))

        nextColumn()
        text(ticket.travellerPassportNumber ? ticket.travellerPassportNumber : "")

        nextColumn()
        text("1")

        nextColumn()
        number(ticket.price ? ticket.price : BigDecimal.ZERO, "center-center-border-number")

        nextColumn()
        text("", "center-center-border")

        nextColumn()
        text("", "center-center-border")

        nextColumn()
        text(ticket.fareBasisLine != null ? ticket.fareBasisLine : "")
    }

    nextRow(); text("Итого " + batchName.toLowerCase() + ":", "left-center-bold-border", 3, 1)
    13.times {
        nextColumn(); text("")
    }

    nextColumn()
    if (ticketsList.size() > 0) {
        formula("SUM(${cellIndex(-ticketsList.size(), 0)}:${cellIndex(-1, 0)})", "center-center-border-number")
    } else {
        number(BigDecimal.ZERO, "center-center-border-number")
    }

    3.times {
        nextColumn(); text("")
    }
}

def collectTicketsByOpBatch() {
    Map<OperationBatch, List<AirTicketsTemplateReportTicket>> result = new HashMap<>()
    result.put(OperationBatch.SELL, new ArrayList<>())
    result.put(OperationBatch.REFUND, new ArrayList<>())

    tickets { AirTicketsTemplateReportTicket ticket ->
        if (result.containsKey(ticket.operationBatch)) {
            result.get(ticket.operationBatch).add(ticket)
        } else {
            throw new IllegalArgumentException(
                    String.format("Ticket %s (uid %s) has illegal operation batch %s",
                            ticket.ticketNumber, ticket.uid, ticket.operationBatch))
        }
    }

    return result
}

def route(AirTicketsTemplateReportTicket ticket) {
    StringBuilder sb = new StringBuilder()

    ticket.segmentTariffs.each {
        it.segments.each {
            if (sb.length() > 0) {
                sb.append("-")
            }
            sb.append(locName(it.departureLocation))
                    .append("-")
                    .append(locName(it.arrivalLocation))
        }
    }

    return sb.toString()
}

def locName(DictionaryReference<GeoLocation> reference) {
    if (reference == null) {
        return ""
    }

    GeoLocation location = DictionaryCache.get().resolveReference(reference)
    if (location == null) {
        return reference.toString()
    }

    if (location.type != LocationType.CITY && location.parent != null) {
        return locName(location.parent)
    }

    return location.toString(LocaleHelper.RU_LOCALE)
}

def salesPointCityCode(EntityReference<SalesPoint> spReference) {
    if (spReference == null) {
        return ""
    }

    SalesPoint salesPoint = EntityStorage.get().resolve(spReference)?.getEntity()
    if (salesPoint == null) {
        return ""
    }

    for (Address address: salesPoint.getAddresses()) {
        DictionaryReference<GeoLocation> cityReference = address.getCity()
        if (cityReference == null) {
            continue
        }

        String code = DictHelper.getCodeVariant(cityReference, CodeSystem.CRT)

        if (TextUtil.nonBlank(code)) {
            return code
        }
    }

    return ""
}

def travellerName(AirTicketsTemplateReportTicket ticket) {
    String res = TextUtil.nonNullStr(ticket.cyrillicName).toUpperCase()

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

    Period age = MiscUtil.age(ticket.travellerBirthday, ticket.departureDate)

    if (age && age.getYears() < 18) {
        if (!res.isEmpty()) {
            res += " "
        }

        res += new SimpleDateFormat("dd.MM.yy").format(ticket.travellerBirthday)
    }

    return res
}

def mtdCount(Map<OperationBatch, List<AirTicketsTemplateReportTicket>> ticketMap) {
    int res = 0

    Set<String> mtdNumbers = new HashSet<>()
    ticketMap.values().each {
        it.each {
            if (TextUtil.isBlank(it.militaryClaimNumber) || mtdNumbers.add(it.militaryClaimNumber)) {
                res++
            }
        }
    }

    return res
}

def setAutoWidth() {
    nextRow(); rowHeight(15); columnWidth(10)

    17.times {
        nextColumn()
        columnAutoWidth(true)
    }
}

page{"МО ВВЛ " + parameters['title']} {
    printTitle()
    printHeader()
    printTickets()
    setAutoWidth()
}