/*
 * This file is part of LibEuFin.
 * Copyright (C) 2024 Taler Systems S.A.

 * LibEuFin is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation; either version 3, or
 * (at your option) any later version.

 * LibEuFin is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero General
 * Public License for more details.

 * You should have received a copy of the GNU Affero General Public
 * License along with LibEuFin; see the file COPYING.  If not, see
 * <http://www.gnu.org/licenses/>
 */

package tech.libeufin.common

import tech.libeufin.common.ANSI.displayLength
import kotlin.math.max

data class ColumnStyle(
    val alignLeft: Boolean = true
) {
    companion object {
        val DEFAULT = ColumnStyle()
    }
}

fun printTable(
    columns: List<String>, 
    rows: List<List<String>>,
    separator: Char = '|',
    colStyle: List<ColumnStyle> = listOf()
) {
    val cols: List<Pair<String, Int>> = columns.mapIndexed { i, name -> 
        val maxRow: Int = rows.asSequence().map { 
            it[i].displayLength()
        }.maxOrNull() ?: 0
        Pair(name, max(name.displayLength(), maxRow))
    }
    val table = buildString {
        fun padding(length: Int) {
            repeat(length) { append (' ') }
        }
        var first = true
        for ((name, len) in cols) {
            if (!first) {
                append(separator)
            } else {
                first = false
            }
            val pad = len - name.displayLength()
            padding(pad / 2)
            append(name)
            padding(pad / 2 + if (pad % 2 == 0) { 0 } else { 1 })
        }
        append('\n')
        for (row in rows) {
            var first = true
            cols.forEachIndexed { i, met ->
                val str = row[i]
                val style = colStyle.getOrNull(i) ?: ColumnStyle.DEFAULT
                if (!first) {
                    append(separator)
                } else {
                    first = false
                }
                val (_, len) = met
                val pad = len - str.displayLength()
                if (style.alignLeft) {
                    append(str)
                    padding(pad)
                } else {
                    padding(pad)
                    append(str)
                }
            }
            append('\n')
        }
    }
    print(table)
}