package com.marvinelsen.crossstraits.internal

import com.marvinelsen.chinese.transliteration.api.PinyinSyllable
import com.marvinelsen.chinese.transliteration.api.Zhuyin
import com.marvinelsen.crossstraits.api.CrossStraitsDefinition
import com.marvinelsen.crossstraits.api.CrossStraitsEntry
import com.marvinelsen.crossstraits.api.CrossStraitsParser
import org.apache.commons.csv.CSVFormat
import org.apache.commons.csv.CSVRecord
import java.io.InputStream

internal class CsvCrossStraitsParser : CrossStraitsParser {
    companion object {
        const val TRADITIONAL_COLUMN_INDEX = 5
        const val SIMPLIFIED_COLUMN_INDEX = 6
        const val ZHUYIN_TAIWAN_COLUMN_INDEX = 10
        const val ZHUYIN_MAINLAND_COLUMN_INDEX = 12
        const val DEFINITION_START_COLUMN_INDEX = 14
        const val DEFINITION_END_COLUMN_INDEX = 43
        val DEFINITION_COLUMNS_INDICES = (DEFINITION_START_COLUMN_INDEX..DEFINITION_END_COLUMN_INDEX)
    }

    override fun parse(inputStream: InputStream) = CSVFormat.DEFAULT
        .parse(inputStream.bufferedReader())
        .drop(1)
        .map(CSVRecord::toCrossStraitsEntry)
}

private fun CSVRecord.toCrossStraitsEntry(): CrossStraitsEntry {
    val traditional = this[CsvCrossStraitsParser.TRADITIONAL_COLUMN_INDEX]
    val simplified = this[CsvCrossStraitsParser.SIMPLIFIED_COLUMN_INDEX]

    val pronunciationTaiwan = this[CsvCrossStraitsParser.ZHUYIN_TAIWAN_COLUMN_INDEX]
        .sanitizeZhuyin()
        .split(Zhuyin.SEPARATOR)
        .filterNot { it.isBlank() }
        .map { PinyinSyllable.fromZhuyin(it) }

    val pronunciationMainland = this[CsvCrossStraitsParser.ZHUYIN_MAINLAND_COLUMN_INDEX]
        .sanitizeZhuyin()
        .split(Zhuyin.SEPARATOR)
        .filterNot { it.isBlank() }
        .map { PinyinSyllable.fromZhuyin(it) }

    val definitions = CsvCrossStraitsParser.DEFINITION_COLUMNS_INDICES
        .mapNotNull { this[it] }
        .filterNot { it.isBlank() }
        .map { it.toCrossStraitsDefinition(traditional) }

    return CrossStraitsEntry(
        traditional = traditional,
        simplified = simplified.ifBlank { traditional },
        pronunciationTaiwan = pronunciationTaiwan,
        pronunciationMainland = pronunciationMainland,
        definitions = definitions
    )
}

private fun String.toCrossStraitsDefinition(traditional: String) = CrossStraitsDefinition(
    definition = this.sanitizeDefinition(),
    examples = if ("[例]" in this) {
        this.substringAfter("[例]").sanitizeExamplesFor(traditional).split("｜")
    } else {
        emptyList()
    }
)

private fun String.sanitizeZhuyin() = this
    .replace("丨", "ㄧ")
    .replace("｜", "ㄧ")
    .replace("〡", "ㄧ")
    .replace("ㄦ", "${Zhuyin.SEPARATOR}ㄦ")
    .replace("，", Zhuyin.SEPARATOR)
    .replace("﹐", Zhuyin.SEPARATOR)
    .replace(" ", Zhuyin.SEPARATOR)

private fun String.sanitizeDefinition() = this
    .substringAfter('.')
    .substringBefore("[例]")
    .replace("★", "【大陸】")
    .replace("▲", "【臺灣】")

private fun String.sanitizeExamplesFor(traditional: String) = this
    .replace("～", traditional)
    .replace("★", "【大陸】")
    .replace("▲", "【臺灣】")
    .replace("。", "")
    .replace("""\d\.""".toRegex(), "")
