package tui

import (
	"os"
	"path/filepath"
	"sort"
	"strings"

	tea "github.com/charmbracelet/bubbletea"
	"github.com/charmbracelet/lipgloss"
)

// FileBrowserModel handles file selection
type FileBrowserModel struct {
	currentDir string
	entries    []os.DirEntry
	selected   int
	filter     string // file extension filter (e.g., ".pcap")
	height     int
	offset     int

	// Results
	selectedFile string
	cancelled    bool
	err          error
}

// NewFileBrowser creates a new file browser starting at dir
func NewFileBrowser(startDir string, filter string) FileBrowserModel {
	if startDir == "" {
		startDir, _ = os.Getwd()
	}

	fb := FileBrowserModel{
		currentDir: startDir,
		filter:     filter,
		height:     15,
	}
	fb.loadDir()
	return fb
}

func (m *FileBrowserModel) loadDir() {
	entries, err := os.ReadDir(m.currentDir)
	if err != nil {
		m.err = err
		return
	}

	// Filter and sort entries
	var filtered []os.DirEntry
	for _, e := range entries {
		if e.IsDir() {
			filtered = append(filtered, e)
		} else if m.filter == "" {
			filtered = append(filtered, e)
		} else {
			name := strings.ToLower(e.Name())
			if strings.HasSuffix(name, m.filter) || strings.HasSuffix(name, ".pcapng") {
				filtered = append(filtered, e)
			}
		}
	}

	// Sort: directories first, then alphabetically
	sort.Slice(filtered, func(i, j int) bool {
		iDir := filtered[i].IsDir()
		jDir := filtered[j].IsDir()
		if iDir != jDir {
			return iDir
		}
		return strings.ToLower(filtered[i].Name()) < strings.ToLower(filtered[j].Name())
	})

	m.entries = filtered
	m.selected = 0
	m.offset = 0
}

// Init initializes the model
func (m FileBrowserModel) Init() tea.Cmd {
	return nil
}

// Update handles messages
func (m FileBrowserModel) Update(msg tea.Msg) (FileBrowserModel, tea.Cmd) {
	switch msg := msg.(type) {
	case tea.KeyMsg:
		switch msg.String() {
		case "esc", "q":
			m.cancelled = true
			return m, nil

		case "up", "k":
			if m.selected > 0 {
				m.selected--
				if m.selected < m.offset {
					m.offset = m.selected
				}
			}

		case "down", "j":
			if m.selected < len(m.entries)-1 {
				m.selected++
				if m.selected >= m.offset+m.height {
					m.offset = m.selected - m.height + 1
				}
			}

		case "enter":
			if len(m.entries) == 0 {
				return m, nil
			}

			entry := m.entries[m.selected]
			fullPath := filepath.Join(m.currentDir, entry.Name())

			if entry.IsDir() {
				m.currentDir = fullPath
				m.loadDir()
			} else {
				m.selectedFile = fullPath
			}

		case "backspace", "h":
			// Go to parent directory
			parent := filepath.Dir(m.currentDir)
			if parent != m.currentDir {
				m.currentDir = parent
				m.loadDir()
			}

		case "home":
			home, err := os.UserHomeDir()
			if err == nil {
				m.currentDir = home
				m.loadDir()
			}
		}

	case tea.WindowSizeMsg:
		m.height = msg.Height - 10
		if m.height < 5 {
			m.height = 5
		}
	}

	return m, nil
}

// View renders the file browser
func (m FileBrowserModel) View() string {
	titleStyle := lipgloss.NewStyle().
		Bold(true).
		Foreground(lipgloss.Color("#7D56F4")).
		MarginBottom(1)

	pathStyle := lipgloss.NewStyle().
		Foreground(lipgloss.Color("#AFAFAF")).
		MarginBottom(1)

	dirStyle := lipgloss.NewStyle().
		Foreground(lipgloss.Color("#8BE9FD"))

	fileStyle := lipgloss.NewStyle().
		Foreground(lipgloss.Color("#F8F8F2"))

	selectedStyle := lipgloss.NewStyle().
		Bold(true).
		Background(lipgloss.Color("#44475A")).
		Foreground(lipgloss.Color("#50FA7B"))

	helpStyle := lipgloss.NewStyle().
		Foreground(lipgloss.Color("#626262")).
		MarginTop(1)

	var b strings.Builder

	b.WriteString(titleStyle.Render("📁 Select PCAP File"))
	b.WriteString("\n")
	b.WriteString(pathStyle.Render(m.currentDir))
	b.WriteString("\n\n")

	if m.err != nil {
		b.WriteString(lipgloss.NewStyle().Foreground(lipgloss.Color("#FF5555")).Render("Error: " + m.err.Error()))
		b.WriteString("\n")
	}

	if len(m.entries) == 0 {
		b.WriteString("(empty directory)\n")
	} else {
		// Show entries with scrolling
		end := m.offset + m.height
		if end > len(m.entries) {
			end = len(m.entries)
		}

		for i := m.offset; i < end; i++ {
			entry := m.entries[i]
			name := entry.Name()

			var style lipgloss.Style
			prefix := "  "

			if entry.IsDir() {
				name = "📂 " + name + "/"
				style = dirStyle
			} else {
				name = "📄 " + name
				style = fileStyle
			}

			if i == m.selected {
				prefix = "▶ "
				style = selectedStyle
			}

			b.WriteString(prefix + style.Render(name) + "\n")
		}

		// Show scroll indicator
		if len(m.entries) > m.height {
			b.WriteString(pathStyle.Render(
				strings.Repeat("─", 20) +
					" " + string(rune('0'+m.offset/10)) + string(rune('0'+m.offset%10)) +
					"/" + string(rune('0'+len(m.entries)/10)) + string(rune('0'+len(m.entries)%10)) + " " +
					strings.Repeat("─", 20)))
			b.WriteString("\n")
		}
	}

	b.WriteString("\n")
	b.WriteString(helpStyle.Render("↑/↓ navigate • Enter select/open • Backspace parent • Esc cancel"))

	return b.String()
}

// IsSelected returns true if a file was selected
func (m FileBrowserModel) IsSelected() bool {
	return m.selectedFile != ""
}

// IsCancelled returns true if cancelled
func (m FileBrowserModel) IsCancelled() bool {
	return m.cancelled
}

// GetSelectedFile returns the selected file path
func (m FileBrowserModel) GetSelectedFile() string {
	return m.selectedFile
}

// GetCurrentDir returns current directory
func (m FileBrowserModel) GetCurrentDir() string {
	return m.currentDir
}
