// SPDX-FileCopyrightText: Amolith <amolith@secluded.site>
//
// SPDX-License-Identifier: AGPL-3.0-or-later

package ui

import (
	"os"
	"strings"

	"github.com/mattn/go-isatty"
)

// ColorMode represents the color output mode.
type ColorMode int

// Color mode constants controlling terminal output styling.
const (
	ColorAuto   ColorMode = iota // Detect from environment/TTY
	ColorAlways                  // Force colors on
	ColorNever                   // Force colors off
)

var colorMode = ColorAuto

// SetColorMode sets the global color mode.
func SetColorMode(mode ColorMode) {
	colorMode = mode
}

// IsPlain returns true when output should be unstyled plain text.
// Detection priority:
//  1. Explicit ColorNever/ColorAlways mode
//  2. NO_COLOR env var (non-empty = plain)
//  3. FORCE_COLOR env var (non-empty = styled)
//  4. TERM=dumb (plain)
//  5. TTY detection (non-TTY = plain)
func IsPlain() bool {
	switch colorMode {
	case ColorNever:
		return true
	case ColorAlways:
		return false
	case ColorAuto:
		return detectPlain()
	}

	return detectPlain()
}

// IsInteractive returns true when running in an interactive terminal.
// This checks TTY status regardless of color settings.
func IsInteractive() bool {
	return isatty.IsTerminal(os.Stdout.Fd()) || isatty.IsCygwinTerminal(os.Stdout.Fd())
}

func detectPlain() bool {
	// NO_COLOR takes precedence (https://no-color.org/)
	if noColor := os.Getenv("NO_COLOR"); noColor != "" {
		return true
	}

	// FORCE_COLOR overrides TTY detection
	if forceColor := os.Getenv("FORCE_COLOR"); forceColor != "" {
		// FORCE_COLOR=0 or FORCE_COLOR=false means no color
		lower := strings.ToLower(forceColor)
		if lower == "0" || lower == "false" {
			return true
		}

		return false
	}

	// TERM=dumb indicates minimal terminal
	if term := os.Getenv("TERM"); term == "dumb" {
		return true
	}

	// Fall back to TTY detection
	return !IsInteractive()
}
