package table

import (
	"fmt"
	"io"

	"github.com/jedib0t/go-pretty/v6/table"
	prettytable "github.com/jedib0t/go-pretty/v6/table"
	"github.com/jedib0t/go-pretty/v6/text"

	sliceutil "github.com/tidbcloud/aisupport/packages/sdk-go/infra/utils/container/slice"
)

type PrinterTable struct {
	output io.Writer
	style  prettytable.Style
}

func NewTable(output io.Writer) *PrinterTable {
	return &PrinterTable{
		output: output,
		style: table.Style{
			Name: "no-border",
			Box: table.BoxStyle{
				PaddingLeft:  " ",
				PaddingRight: " ",
			},
			Options: table.Options{
				DrawBorder:      false,
				SeparateColumns: false,
				SeparateFooter:  false,
				SeparateHeader:  false,
				SeparateRows:    false,
			},
		},
	}
}

func (p *PrinterTable) PrintObject(value any) error {
	scheme, ok := SchemeStore.Get(value)
	if !ok {
		return fmt.Errorf("not found scheme for object %T", value)
	}

	row := scheme.RowExtractor(value)
	return p.render([]string(scheme.Header), []prettytable.Row{row})
}

func (p *PrinterTable) PrintList(values []any) error {
	if len(values) == 0 {
		return nil
	}

	scheme, ok := SchemeStore.Get(values[0])
	if !ok {
		return fmt.Errorf("not found scheme for object %T", values[0])
	}

	rows := make([]prettytable.Row, 0, len(values))
	for _, value := range values {
		row := scheme.RowExtractor(value)
		rows = append(rows, row)
	}

	return p.render([]string(scheme.Header), rows)
}

func (p *PrinterTable) render(headers []string, rows []prettytable.Row) error {
	writer := prettytable.NewWriter()
	writer.SetStyle(p.style)
	writer.SetColumnConfigs(leftAlignColumns(len(headers)))

	writer.AppendHeader(sliceutil.TransformSlice(headers, func(h string) any {
		return h
	}))
	writer.AppendRows(rows)

	_, err := fmt.Fprintln(p.output, writer.Render())
	return err
}

func leftAlignColumns(count int) []table.ColumnConfig {
	configs := make([]table.ColumnConfig, 0, count)

	for i := 1; i <= count; i++ {
		configs = append(configs, table.ColumnConfig{
			Number:      i,
			Align:       text.AlignLeft,
			AlignHeader: text.AlignLeft,
		})
	}

	return configs
}
