// Package tracklist manages track-list display configuration.
package tracklist

import (
	"errors"
	"fmt"
	"slices"
)

var (
	errUnknownColumnID = errors.New("unknown track-list column ID")
	errDuplicateColumn = errors.New("duplicate column ID")
)

// ColumnID identifies a displayable column in the track list.
type ColumnID string

// Valid column identifiers.
const (
	ColTrackName   ColumnID = "trackName"
	ColArtistName  ColumnID = "artistName"
	ColTrackLength ColumnID = "trackLength"
	ColAlbum       ColumnID = "album"
	ColGenre       ColumnID = "genre"
	ColYear        ColumnID = "year"
	ColComposer    ColumnID = "composer"
	ColTrackNumber ColumnID = "trackNumber"
	ColDiscNumber  ColumnID = "discNumber"
	ColFilePath    ColumnID = "filePath"
	ColFileType    ColumnID = "fileType"
	ColSampleRate  ColumnID = "sampleRate"
	ColBitDepth    ColumnID = "bitDepth"
	ColChannels    ColumnID = "channels"
	ColBitrate     ColumnID = "bitrate"
	ColFileSize    ColumnID = "fileSize"
	ColPlayCount   ColumnID = "playCount"
	ColAlbumArt    ColumnID = "albumArt"
)

// AllColumnIDs lists every recognised column in default display
// order.
var AllColumnIDs = []ColumnID{
	ColAlbumArt,
	ColTrackName,
	ColArtistName,
	ColTrackLength,
	ColAlbum,
	ColGenre,
	ColYear,
	ColComposer,
	ColTrackNumber,
	ColDiscNumber,
	ColFilePath,
	ColFileType,
	ColSampleRate,
	ColBitDepth,
	ColChannels,
	ColBitrate,
	ColFileSize,
	ColPlayCount,
}

// DefaultColumns is the initial column configuration.  Album is in it
// (H-15): without it the three identical `Tideline / Aurora Fields /
// 00:06` rows in this app's own fixture library cannot be told apart,
// in an app that has a duplicate-detection feature.  Must match
// DEFAULT_COLUMN_IDS in frontend/src/components/track-list/columns.ts,
// which is what the UI falls back to before the config arrives.
var DefaultColumns = []Column{
	{ID: ColTrackName},
	{ID: ColArtistName},
	{ID: ColAlbum},
	{ID: ColTrackLength},
}

// Column represents a visible column in the track list.
type Column struct {
	ID ColumnID `json:"id" toml:"ID"`
}

// Config holds track-list display preferences.
type Config struct {
	Columns []Column `json:"columns" toml:"Columns"`
}

// ApplyDefaults fills zero-value fields with sensible defaults.
func (c *Config) ApplyDefaults() {
	if len(c.Columns) == 0 {
		c.Columns = make([]Column, len(DefaultColumns))
		copy(c.Columns, DefaultColumns)
	}
}

// Validate checks that every column ID is recognised and that
// there are no duplicates.
func (c *Config) Validate() error {
	c.ApplyDefaults()

	seen := make(map[ColumnID]bool, len(c.Columns))

	for _, col := range c.Columns {
		if !isValidColumnID(col.ID) {
			return fmt.Errorf(
				"%w: %q", errUnknownColumnID, col.ID,
			)
		}

		if seen[col.ID] {
			return fmt.Errorf(
				"%w: %q", errDuplicateColumn, col.ID,
			)
		}

		seen[col.ID] = true
	}

	return nil
}

// isValidColumnID returns true when id matches a known column.
func isValidColumnID(id ColumnID) bool {
	return slices.Contains(AllColumnIDs, id)
}
