package ru.yandex.direct.web.entity.uac

import com.univocity.parsers.csv.CsvWriter
import com.univocity.parsers.csv.CsvWriterSettings
import ru.yandex.direct.core.entity.uac.model.GroupByDateType
import ru.yandex.direct.grid.processing.model.statistics.GdCampaignStatisticsColumnValues
import ru.yandex.direct.grid.processing.model.statistics.GdCampaignStatisticsColumnValues.AVG_CPC
import ru.yandex.direct.grid.processing.model.statistics.GdCampaignStatisticsColumnValues.AVG_CPM
import ru.yandex.direct.grid.processing.model.statistics.GdCampaignStatisticsColumnValues.CLICKS
import ru.yandex.direct.grid.processing.model.statistics.GdCampaignStatisticsColumnValues.CONVERSIONS
import ru.yandex.direct.grid.processing.model.statistics.GdCampaignStatisticsColumnValues.CONVERSION_RATE
import ru.yandex.direct.grid.processing.model.statistics.GdCampaignStatisticsColumnValues.COST
import ru.yandex.direct.grid.processing.model.statistics.GdCampaignStatisticsColumnValues.COST_PER_CONVERSION
import ru.yandex.direct.grid.processing.model.statistics.GdCampaignStatisticsColumnValues.CTR
import ru.yandex.direct.grid.processing.model.statistics.GdCampaignStatisticsColumnValues.INSTALLS
import ru.yandex.direct.grid.processing.model.statistics.GdCampaignStatisticsColumnValues.POST_VIEW_CONVERSIONS
import ru.yandex.direct.grid.processing.model.statistics.GdCampaignStatisticsColumnValues.POST_VIEW_INSTALLS
import ru.yandex.direct.grid.processing.model.statistics.GdCampaignStatisticsColumnValues.SHOWS
import ru.yandex.direct.grid.processing.model.statistics.GdCampaignStatisticsValueHolder
import ru.yandex.direct.intapi.client.model.request.statistics.option.ReportOptionGroupByDate
import java.io.ByteArrayOutputStream
import java.io.IOException
import java.io.OutputStreamWriter
import java.io.Writer
import java.time.LocalDate

private val csvWriterSettings = CsvWriterSettings()

private val mapper = linkedMapOf(
    SHOWS to { v: GdCampaignStatisticsColumnValues -> valueToString(v.shows) },
    CLICKS to { v: GdCampaignStatisticsColumnValues -> valueToString(v.clicks) },
    CTR to { v: GdCampaignStatisticsColumnValues -> valueToString(v.ctr) },
    COST to { v: GdCampaignStatisticsColumnValues -> valueToString(v.cost) },
    CONVERSION_RATE to { v: GdCampaignStatisticsColumnValues -> valueToString(v.conversionRate) },
    COST_PER_CONVERSION to { v: GdCampaignStatisticsColumnValues -> valueToString(v.costPerConversion) },
    CONVERSIONS to { v: GdCampaignStatisticsColumnValues -> valueToString(v.conversions) },
    INSTALLS to { v: GdCampaignStatisticsColumnValues -> valueToString(v.installs) },
    AVG_CPC to { v: GdCampaignStatisticsColumnValues -> valueToString(v.avgCpc) },
    AVG_CPM to { v: GdCampaignStatisticsColumnValues -> valueToString(v.avgCpm) },
    POST_VIEW_CONVERSIONS to { v: GdCampaignStatisticsColumnValues -> valueToString(v.postViewConversions) },
    POST_VIEW_INSTALLS to { v: GdCampaignStatisticsColumnValues -> valueToString(v.postViewInstalls) },
)

fun getHeader(): List<String> {
    val headers = listOf("Date")
    return headers.plus(mapper.keys.map { it.name().replaceFirstChar { first -> first.uppercase() } })
}

fun getRowStats(
    columnValues: GdCampaignStatisticsColumnValues,
    date: LocalDate,
): List<String> {
    val rowSet = listOf(date.toString())
    return rowSet.plus(mapper.values.map { it.invoke(columnValues) })
}

private fun valueToString(valueHolder: GdCampaignStatisticsValueHolder?): String {
    return if (valueHolder != null && valueHolder.value != null) {
        valueHolder.value.toString()
    } else "0"
}

@Throws(IOException::class)
fun generateFileData(
    intro: Array<String>,
    rowsetHeaders: List<String>,
    rowset: List<List<String>>
): ByteArrayOutputStream {
    val csvResult = ByteArrayOutputStream()
    val outputWriter: Writer = OutputStreamWriter(csvResult)
    val introWriter = CsvWriter(outputWriter, csvWriterSettings)
    introWriter.writeRow(intro)

    val rowsetWriter = CsvWriter(outputWriter, csvWriterSettings)
    rowsetWriter.writeHeaders(rowsetHeaders)
    rowsetWriter.writeRowsAndClose(rowset)
    introWriter.close()
    rowsetWriter.close()
    outputWriter.close()
    return csvResult
}

fun exportCampaignStatisticsFilename(
    campaignId: String,
    beginDate: LocalDate,
    endDate: LocalDate,
    groupByDate: GroupByDateType
): String {
    return String.format(
        "campaign_results_%s_%s_%s_%s.csv",
        campaignId,
        groupByDate.getType(),
        beginDate,
        endDate
    )
}

fun toReportOptionDate(groupByDate: GroupByDateType): ReportOptionGroupByDate {
    return when (groupByDate) {
        GroupByDateType.DAY -> ReportOptionGroupByDate.DAY
        GroupByDateType.WEEK -> ReportOptionGroupByDate.WEEK
        GroupByDateType.MONTH -> ReportOptionGroupByDate.MONTH
        else -> ReportOptionGroupByDate.NONE
    }
}
