package modal

import (
	"strings"

	"github.com/charmbracelet/lipgloss/v2"
	"github.com/sst/opencode/internal/layout"
	"github.com/sst/opencode/internal/styles"
	"github.com/sst/opencode/internal/theme"
)

// CloseModalMsg is a message to signal that the active modal should be closed.
type CloseModalMsg struct{}

// Modal is a reusable modal component that handles frame rendering and overlay placement
type Modal struct {
	width      int
	height     int
	title      string
	maxWidth   int
	maxHeight  int
	fitContent bool
}

// ModalOption is a function that configures a Modal
type ModalOption func(*Modal)

// WithTitle sets the modal title
func WithTitle(title string) ModalOption {
	return func(m *Modal) {
		m.title = title
	}
}

// WithMaxWidth sets the maximum width
func WithMaxWidth(width int) ModalOption {
	return func(m *Modal) {
		m.maxWidth = width
		m.fitContent = false
	}
}

// WithMaxHeight sets the maximum height
func WithMaxHeight(height int) ModalOption {
	return func(m *Modal) {
		m.maxHeight = height
	}
}

func WithFitContent(fit bool) ModalOption {
	return func(m *Modal) {
		m.fitContent = fit
	}
}

// New creates a new Modal with the given options
func New(opts ...ModalOption) *Modal {
	m := &Modal{
		maxWidth:   0,
		maxHeight:  0,
		fitContent: true,
	}

	for _, opt := range opts {
		opt(m)
	}

	return m
}

func (m *Modal) SetTitle(title string) {
	m.title = title
}

// Render renders the modal centered on the screen
func (m *Modal) Render(contentView string, background string) string {
	t := theme.CurrentTheme()

	outerWidth := layout.Current.Container.Width - 8
	if m.maxWidth > 0 && outerWidth > m.maxWidth {
		outerWidth = m.maxWidth
	}

	if m.fitContent {
		titleWidth := lipgloss.Width(m.title)
		contentWidth := lipgloss.Width(contentView)
		largestWidth := max(titleWidth+2, contentWidth)
		outerWidth = largestWidth + 6
	}

	innerWidth := outerWidth - 4

	baseStyle := styles.NewStyle().Foreground(t.TextMuted()).Background(t.BackgroundElement())

	var finalContent string
	if m.title != "" {
		titleStyle := baseStyle.
			Foreground(t.Primary()).
			Bold(true).
			Padding(0, 1)

		escStyle := baseStyle.Foreground(t.TextMuted())
		escText := escStyle.Render("esc")

		// Calculate position for esc text
		titleWidth := lipgloss.Width(m.title)
		escWidth := lipgloss.Width(escText)
		spacesNeeded := max(0, innerWidth-titleWidth-escWidth-2)
		spacer := strings.Repeat(" ", spacesNeeded)
		titleLine := m.title + spacer + escText
		titleLine = titleStyle.Render(titleLine)

		finalContent = strings.Join([]string{titleLine, "", contentView}, "\n")
	} else {
		finalContent = contentView
	}

	modalStyle := baseStyle.
		PaddingTop(1).
		PaddingBottom(1).
		PaddingLeft(2).
		PaddingRight(2)

	modalView := modalStyle.
		Width(outerWidth).
		Render(finalContent)

	// Calculate position for centering
	bgHeight := lipgloss.Height(background)
	bgWidth := lipgloss.Width(background)
	modalHeight := lipgloss.Height(modalView)
	modalWidth := lipgloss.Width(modalView)

	row := (bgHeight - modalHeight) / 2
	col := (bgWidth - modalWidth) / 2

	return layout.PlaceOverlay(
		col,
		row,
		modalView,
		background,
		layout.WithOverlayBorder(),
		layout.WithOverlayBorderColor(t.Primary()),
	)
}
