import java.nio.file.Files
import java.text.SimpleDateFormat
import java.util.Map.Entry
import java.util.stream.Collectors

import org.apache.poi.ss.usermodel.Row
import org.apache.poi.ss.usermodel.Sheet
import org.apache.poi.ss.usermodel.Workbook
import org.apache.poi.xssf.usermodel.XSSFWorkbook
import org.slf4j.Logger
import org.slf4j.LoggerFactory

import com.gridnine.xtrip.common.Environment
import com.gridnine.xtrip.common.l10n.model.LocaleManager
import com.gridnine.xtrip.common.model.EntityContainer
import com.gridnine.xtrip.common.model.booking.ValidationMessage
import com.gridnine.xtrip.common.model.booking.commission.ProductType
import com.gridnine.xtrip.common.model.entity.EntityStorage
import com.gridnine.xtrip.common.model.system.Message
import com.gridnine.xtrip.common.model.system.MessageType
import com.gridnine.xtrip.common.parsers.model.AuraExchangeDocument
import com.gridnine.xtrip.common.parsers.model.AuraExchangeDocumentIndex
import com.gridnine.xtrip.common.parsers.model.AuraSupplementType
import com.gridnine.xtrip.common.parsers.model.ProcessingStatus
import com.gridnine.xtrip.common.parsers.model.TransactionType
import com.gridnine.xtrip.common.search.SearchCriterion
import com.gridnine.xtrip.common.search.SearchQuery
import com.gridnine.xtrip.common.search.SortOrder

Logger logger = LoggerFactory.getLogger('groovy-script')

logger.info('Validation: validation started')

Date startDate = null // new SimpleDateFormat('yyyy.MM.dd HH:mm:ss.SSS').parse('2019.04.11 00:00:00.000')
Date endDate = null // SimpleDateFormat('yyyy.MM.dd HH:mm:ss.SSS').parse('2019.04.20 23:59:59.999')

Date startCreateDate = new SimpleDateFormat('yyyy.MM.dd HH:mm:ss.SSS').parse('2019.04.11 00:00:00.000')
Date endCreateDate = new SimpleDateFormat('yyyy.MM.dd HH:mm:ss.SSS').parse('2019.04.30 23:59:59.999')

List<MessageType> types = Arrays.asList(
        //MessageType.MESSAGE,
        //MessageType.WARNING,
        MessageType.ERROR
        //MessageType.FOR_USER
        )

logger.info('Validation aura exchange document: startDate is ' + startDate)
logger.info('Validation aura exchange document: endDate is ' + endDate)

int countt = 0
int amount = 10000

int processed = 0
int found = 0

Map<String, Integer> statistics = new HashMap()

Workbook book = new XSSFWorkbook()

try {

    Sheet statisticsSheet = book.createSheet('Statistics')
    Sheet validationSheet = book.createSheet('Validation')

    int rowIndex = 0

    Row headerRow = validationSheet.createRow(rowIndex)

    headerRow.createCell(0).setCellValue('Номер')
    headerRow.createCell(1).setCellValue('Статус')
    headerRow.createCell(2).setCellValue('Тип')
    headerRow.createCell(3).setCellValue('Тип дополнительных данных')
    headerRow.createCell(4).setCellValue('Сообщение')
    headerRow.createCell(5).setCellValue('Детали')

    rowIndex++

    while(true) {

        int limit = amount
        int offset = countt * amount

        logger.info('Validation aura exchange document: searching ' + limit + ' starting from ' + offset)

        SearchQuery query = new SearchQuery()

        if(startDate != null) {
            query.getCriteria().getCriterions().add(SearchCriterion.ge(AuraExchangeDocumentIndex.Property.issueDate.name(), startDate))
        }
        
        if(endDate != null) {
            query.getCriteria().getCriterions().add(SearchCriterion.le(AuraExchangeDocumentIndex.Property.issueDate.name(), endDate))
        }

        if(startCreateDate != null) {
            query.getCriteria().getCriterions().add(SearchCriterion.ge(AuraExchangeDocumentIndex.Property.created.name(), startCreateDate))
        }
        
        if(endCreateDate != null) {
            query.getCriteria().getCriterions().add(SearchCriterion.le(AuraExchangeDocumentIndex.Property.created.name(), endCreateDate))
        }

        query.getCriteria().getCriterions().add(SearchCriterion.or(SearchCriterion.eq(AuraExchangeDocumentIndex.Property.status.name(), ProcessingStatus.WARNING), SearchCriterion.eq(AuraExchangeDocumentIndex.Property.status.name(), ProcessingStatus.ERROR)))

        query.setLimit(limit)
        query.setOffset(offset)

        query.getCriteria().orders.put('containerUid', SortOrder.ASC)

        query.getPreferredProperties().add('containerUid')

        List<AuraExchangeDocumentIndex> indexes = EntityStorage.get().search(AuraExchangeDocumentIndex.class, query).getData()

        logger.info('Validation aura exchange document: found ' + indexes.size() + ' products')

        if(indexes.size() == 0) {
            break
        }

        for(AuraExchangeDocumentIndex index : indexes) {

            logger.info('Validation aura exchange document: processing ' + processed + ' | ' + found + ' | ' + index.getSource().getUid())

            EntityContainer<AuraExchangeDocument> auraExchangeDocumentContainer = EntityStorage.get().resolve(index.getSource())

            if(auraExchangeDocumentContainer != null) {

                AuraExchangeDocument document = auraExchangeDocumentContainer.getEntity()

                String systemNumber = document.getSystemNumber()
                TransactionType transactionStatus = document.getTransactionType()
                ProductType productType = document.getProductType()
                AuraSupplementType supplementType = document.getSupplementType()

                List<Message> messages = document.getMessages().stream().filter({ Message item -> types.contains(item.getType())}).collect(Collectors.toList())

                for(int i = 0; i < messages.size(); i++) {

                    Message message = messages.get(i)

                    String messageText = LocaleManager.get().getL10nResourceManager().getMessage(message.getMessage())
                    String messageDetails = message.getDetails()

                    Row row = validationSheet.createRow(rowIndex)

                    row.createCell(0).setCellValue(i == 0 ? systemNumber : null)
                    row.createCell(1).setCellValue(i == 0 ? (transactionStatus != null ? transactionStatus.toString() : '?') : null)
                    row.createCell(2).setCellValue(i == 0 ? (productType != null ? productType.toString() : '?') : null)
                    row.createCell(3).setCellValue(i == 0 ? (supplementType != null ? supplementType.toString() : '?') : null)
                    row.createCell(4).setCellValue(messageText)
                    row.createCell(5).setCellValue(messageDetails)

                    statistics.put(messageText, statistics.get(messageText) != null ? Integer.valueOf(statistics.get(messageText).intValue() + 1) : Integer.valueOf(1))

                    rowIndex++
                }

                found++

            } else {
                logger.info('Validation aura exchange document: unable to load ' + index.getSource() + ' (' + index.getSource().getUid() + ')')
            }

            processed++
        }

        countt++
    }

    List<Entry<String, Integer>> entries = new ArrayList<>(statistics.entrySet())
    
    Collections.sort(entries, new Comparator<Entry<String, Integer>>() {
        
        public int compare(Entry<String, Integer> o1, Entry<String, Integer> o2) {
            return o2.getValue().compareTo(o1.getValue())
        }
    })

    rowIndex = 0

    headerRow = statisticsSheet.createRow(rowIndex)

    headerRow.createCell(0).setCellValue('Сообщение')
    headerRow.createCell(1).setCellValue('Количество')

    rowIndex++

    for(Entry<String, Integer> entry : entries) {

        Row row = statisticsSheet.createRow(rowIndex)

        row.createCell(0).setCellValue(entry.getKey())
        row.createCell(1).setCellValue(entry.getValue().doubleValue())

        rowIndex++
    }

    OutputStream os = Files.newOutputStream(Files.createDirectories(Environment.getDataFolder().toPath().resolve('export/validation')).resolve('validation-aura-exchange-documents.xlsx'))

    try {
        book.write(os)
    } finally {
        os.close()
    }

} catch(Throwable t) {
    logger.error('Validation aura exchange document: error occured', t)
} finally {
    book.close()
}

logger.info('Validation aura exchange document: processed ' + processed)
logger.info('Validation aura exchange document: found ' + found)

logger.info('Validation aura exchange document: validation finished')
