import java.nio.file.Files
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.model.EntityReference
import com.gridnine.xtrip.common.model.dict.ContractType
import com.gridnine.xtrip.common.model.dict.CurrencyInfo
import com.gridnine.xtrip.common.model.dict.DictionaryReference
import com.gridnine.xtrip.common.model.entity.EntityStorage
import com.gridnine.xtrip.common.model.entity.misc.IrrelevanceTolerantEntityStorage
import com.gridnine.xtrip.common.model.entity.parameters.EntityStorageCommonParameters
import com.gridnine.xtrip.common.model.entity.parameters.EntityStorageLoadParameters
import com.gridnine.xtrip.common.model.entity.parameters.EntityStorageSearchParameters
import com.gridnine.xtrip.common.model.finance.ChartOfAccountsElementType
import com.gridnine.xtrip.common.model.finance.ChartOfAccountsSettings
import com.gridnine.xtrip.common.model.finance.DimensionType
import com.gridnine.xtrip.common.model.helpers.BalanceHelper
import com.gridnine.xtrip.common.model.helpers.FinanceHelper
import com.gridnine.xtrip.common.model.profile.ContractCustomerIndex
import com.gridnine.xtrip.common.model.profile.ContractIndex
import com.gridnine.xtrip.common.model.profile.Organization
import com.gridnine.xtrip.common.search.SearchCriterion
import com.gridnine.xtrip.common.search.SearchQuery
import com.gridnine.xtrip.common.util.MiscUtil

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

logger.info('Subagency turnover statistics: turnover statistics started')

// Comparator
def comparator = [ compare: {a, b ->
        MiscUtil.compare(a.toString(), b.toString())
    }] as Comparator

def parameters = EntityStorageCommonParameters.of(new EntityStorageLoadParameters().context(IrrelevanceTolerantEntityStorage.IRRELEVANCE_TOLERANT_QUERY, Boolean.TRUE), new EntityStorageSearchParameters().context(IrrelevanceTolerantEntityStorage.IRRELEVANCE_TOLERANT_QUERY, Boolean.TRUE));

Date date = new Date()

logger.info('Subagency turnover statistics: date is ' + date)

int processed = 0
int found = 0

Map<EntityReference<Organization>, Set<EntityReference<Organization>>> customers = new HashMap()

Workbook book = new XSSFWorkbook()

try {

    SearchQuery query = new SearchQuery()

    query.getCriteria().getCriterions().add(SearchCriterion.eq(ContractIndex.Property.contractType.name(), ContractType.SUBAGENCY))
    query.getCriteria().getCriterions().add(SearchCriterion.ne(ContractIndex.Property.supplier.name(), null))
    query.getCriteria().getCriterions().add(SearchCriterion.ne(ContractIndex.Property.customer.name(), null))

    for(ContractIndex index : EntityStorage.get().search(ContractIndex.class, query).getData()) {
        customers.computeIfAbsent(index.getCustomer(), {item -> new HashSet()}).add(index.getSupplier())
    }

    query = new SearchQuery()

    query.getCriteria().getCriterions().add(SearchCriterion.eq(ContractCustomerIndex.Property.contractType.name(), ContractType.SUBAGENCY))
    query.getCriteria().getCriterions().add(SearchCriterion.ne(ContractCustomerIndex.Property.supplier.name(), null))
    query.getCriteria().getCriterions().add(SearchCriterion.ne(ContractCustomerIndex.Property.customer.name(), null))

    for(ContractCustomerIndex index : EntityStorage.get().search(ContractCustomerIndex.class, query).getData()) {
        customers.computeIfAbsent(index.getCustomer(), {item -> new HashSet()}).add(index.getSupplier())
    }

    found = customers.size();

    Sheet statisticsSheet = book.createSheet('Statistics')

    int rowIndex = 0

    Row headerRow = statisticsSheet.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++

    for(EntityReference<Organization> customer : customers.keySet().stream().sorted(comparator).collect(Collectors.toList())) {

        logger.info('Subagency turnover statistics: processing ' + (processed + 1) + ' of ' + found + ' | ' + customer)

        EntityReference<ChartOfAccountsSettings> settings = FinanceHelper.getChartOfAccountsSettings(customer, false)

        if(settings != null) {

            Set<DictionaryReference<CurrencyInfo>> currencies = FinanceHelper.getChartOfAccountsElementCurrencies(customer, settings, ChartOfAccountsElementType.SUPPLIER, parameters)

            for(EntityReference<Organization> supplier : customers.get(customer).stream().sorted(comparator).collect(Collectors.toList())) {

                for(DictionaryReference<CurrencyInfo> currency : currencies.stream().sorted(comparator).collect(Collectors.toList())) {

                    BigDecimal debit = BalanceHelper.calculateBalance(customer, date, date, ChartOfAccountsElementType.SUPPLIER, currency, Collections.singletonMap(DimensionType.ORGANIZATION, supplier), false, parameters)
                    BigDecimal credit = BalanceHelper.calculateBalance(customer, date, date, ChartOfAccountsElementType.SUPPLIER, currency, Collections.singletonMap(DimensionType.ORGANIZATION, supplier), true, parameters)

                    if(debit != null || credit != null) {

                        BigDecimal balance = MiscUtil.sum(debit, MiscUtil.negate(credit))

                        Row row = statisticsSheet.createRow(rowIndex)

                        row.createCell(0).setCellValue(customer.toString())
                        row.createCell(1).setCellValue(supplier.toString())
                        row.createCell(2).setCellValue(currency.getCode())
                        row.createCell(3).setCellValue(debit != null ? debit.toPlainString() : '')
                        row.createCell(4).setCellValue(credit != null ? credit.toPlainString() : '')
                        row.createCell(5).setCellValue(balance != null ? balance.toPlainString() : '')

                        rowIndex++
                    }
                }
            }
        }

        processed++
    }

    OutputStream os = Files.newOutputStream(Files.createDirectories(Environment.getDataFolder().toPath().resolve('export/statistics')).resolve('subagency-turnover.xlsx'))

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

} catch(Throwable t) {
    logger.error('Subagency turnover statistics: error occured', t)
} finally {
    book.close()
}

logger.info('Subagency turnover statistics: turnover statistics finished')


