package tui

import (
	"encoding/json"
	"fmt"
	"strings"

	"github.com/charmbracelet/bubbles/viewport"
	"github.com/charmbracelet/lipgloss"
	"github.com/voocel/ainovel-cli/app"
)

// renderTopBar 渲染顶部状态栏（两行布局）。
// 第一行：小说名居中
// 第二行：左侧模型/风格信息，右侧状态胶囊
func renderTopBar(snap app.UISnapshot, width int, spinnerFrame string) string {
	// 第一行：小说名居中
	novelName := snap.NovelName
	if novelName == "" {
		novelName = "Novel Agent"
	}
	line1 := lipgloss.NewStyle().
		Width(width - 2).
		AlignHorizontal(lipgloss.Center).
		Foreground(colorText).
		Bold(true).
		Render("✦ " + novelName + " ✦")

	// 第二行左侧：模型 + 风格
	var infoParts []string
	if snap.Provider != "" {
		infoParts = append(infoParts, snap.Provider)
	}
	if snap.ModelName != "" {
		infoParts = append(infoParts, snap.ModelName)
	}
	if snap.Style != "" && snap.Style != "default" {
		infoParts = append(infoParts, snap.Style)
	}
	left := lipgloss.NewStyle().Foreground(colorDim).Render(strings.Join(infoParts, " · "))

	// 第二行右侧：状态胶囊
	label := snap.StatusLabel
	if label == "" {
		label = "READY"
	}
	color, ok := statusColors[label]
	if !ok {
		color = colorDim
	}
	capsule := statusCapsule.Foreground(lipgloss.Color("#1a1a2e")).Background(color).Render(label)

	if snap.IsRunning && spinnerFrame != "" {
		capsule = lipgloss.NewStyle().Foreground(colorAccent).Render(spinnerFrame) + " " + capsule
	}

	gap := width - lipgloss.Width(left) - lipgloss.Width(capsule) - 2
	if gap < 1 {
		gap = 1
	}
	line2 := left + strings.Repeat(" ", gap) + capsule

	content := line1 + "\n" + line2
	return topBarStyle.Width(width).
		Border(baseBorder, false, false, true, false).
		BorderForeground(colorDim).
		Render(content)
}

// renderStatePanel 渲染左侧状态面板。
func renderStatePanel(snap app.UISnapshot, width, height int) string {
	var b strings.Builder

	if snap.RecoveryLabel != "" {
		b.WriteString(highlightValueStyle.Render("恢复: " + truncate(snap.RecoveryLabel, width-4)))
		b.WriteString("\n\n")
	}

	b.WriteString(panelTitleStyle.Render("状态"))
	b.WriteString("\n")
	b.WriteString(renderField("Phase", snap.Phase))
	b.WriteString(renderFlowField(snap.Flow))
	b.WriteString(renderField("Chapter", fmt.Sprintf("%d / %d", snap.CompletedCount, snap.TotalChapters)))
	b.WriteString(renderField("Words", formatNumber(snap.TotalWordCount)))

	if snap.InProgressChapter > 0 {
		b.WriteString(renderField("Writing", fmt.Sprintf("第%d章", snap.InProgressChapter)))
	}

	if len(snap.PendingRewrites) > 0 {
		b.WriteString("\n")
		b.WriteString(panelTitleStyle.Render("返工"))
		b.WriteString("\n")
		b.WriteString(renderHighlightField("Pending", fmt.Sprintf("%v", snap.PendingRewrites)))
		if snap.RewriteReason != "" {
			b.WriteString(renderField("Reason", truncate(snap.RewriteReason, width-12)))
		}
	}

	if snap.PendingSteer != "" {
		b.WriteString("\n")
		b.WriteString(panelTitleStyle.Render("干预"))
		b.WriteString("\n")
		b.WriteString(renderHighlightField("Steer", truncate(snap.PendingSteer, width-12)))
	}

	style := lipgloss.NewStyle().
		Width(width).
		Height(height).
		Border(baseBorder, false, true, false, false).
		BorderForeground(colorDim).
		Padding(0, 1)

	return style.Render(b.String())
}

// 星光动画帧
var sparklePatterns = []string{
	"  ✦       ·     ✧          ·  ",
	"     ·  ✧     ✦    ·          ",
	"  ·        ✦       ·    ✧     ",
	" ✧    ·        ✧       ✦     ·",
	"      ✦    ·       ✧    ·     ",
	"  ·       ✧    ✦       ·      ",
	"    ✧  ·       ·    ✦    ✧    ",
	"  ✦        ·    ✧        ✦  · ",
}

// renderSparkle 渲染事件流底部的星光加载动画。
func renderSparkle(frame int) string {
	idx := frame % len(sparklePatterns)
	// 亮星用琥珀色，暗星用灰色
	line := sparklePatterns[idx]
	var b strings.Builder
	for _, ch := range line {
		switch ch {
		case '✦':
			b.WriteString(lipgloss.NewStyle().Foreground(colorAccent).Render("✦"))
		case '✧':
			b.WriteString(lipgloss.NewStyle().Foreground(lipgloss.Color("#887730")).Render("✧"))
		case '·':
			b.WriteString(lipgloss.NewStyle().Foreground(colorDim).Render("·"))
		default:
			b.WriteRune(ch)
		}
	}
	label := lipgloss.NewStyle().Foreground(lipgloss.Color("#887730")).Render("  AI 生成中…")
	return "\n" + b.String() + "\n" + label
}

// renderEventContent 将事件列表渲染为纯文本（供 viewport 使用）。
func renderEventContent(events []app.UIEvent, width int) string {
	var b strings.Builder
	for i, ev := range events {
		ts := ev.Time.Format("15:04:05")
		cat := ev.Category

		color, ok := categoryColors[cat]
		if !ok {
			color = colorText
		}

		catStyle := lipgloss.NewStyle().Foreground(color).Width(7)
		tsStyle := lipgloss.NewStyle().Foreground(colorDim)
		sumStyle := lipgloss.NewStyle().Foreground(color)

		line := tsStyle.Render(ts) + " " + catStyle.Render(cat) + " " + sumStyle.Render(truncate(ev.Summary, width-20))
		b.WriteString(line)
		if i < len(events)-1 {
			b.WriteString("\n")
		}
	}
	return b.String()
}

// renderEventFlowViewport 用 viewport 包装渲染事件流面板。
func renderEventFlowViewport(vp viewport.Model, width, height int, focused bool) string {
	// 标题栏
	titleColor := colorDim
	if focused {
		titleColor = colorAccent
	}
	title := lipgloss.NewStyle().Foreground(titleColor).Render("✦ 事件流")
	lineW := width - lipgloss.Width(title) - 4
	if lineW < 0 {
		lineW = 0
	}
	separator := lipgloss.NewStyle().Foreground(colorDim).Render(strings.Repeat("─", lineW))
	header := " " + title + " " + separator

	vpH := height - 1
	if vpH < 1 {
		vpH = 1
	}
	style := lipgloss.NewStyle().
		Width(width).
		Height(vpH).
		Padding(0, 1)

	return header + "\n" + style.Render(vp.View())
}

// renderStreamPanel 渲染流式输出面板（中间列下半部分）。
func renderStreamPanel(vp viewport.Model, width, height int, focused bool) string {
	// 分隔标题栏（始终醒目）
	title := lipgloss.NewStyle().Foreground(colorAccent).Bold(focused).Render("✦ 实时输出")
	lineW := width - lipgloss.Width(title) - 4
	if lineW < 0 {
		lineW = 0
	}
	separator := lipgloss.NewStyle().Foreground(colorDim).Render(strings.Repeat("─", lineW))
	header := " " + title + " " + separator

	// viewport 内容（height 包含 header 行，viewport 实际高度需减 1）
	vpH := height - 1
	if vpH < 1 {
		vpH = 1
	}
	vpStyle := lipgloss.NewStyle().
		Width(width).
		Height(vpH).
		Padding(0, 1).
		Foreground(colorText)

	return header + "\n" + vpStyle.Render(vp.View())
}

// renderStreamContent 将流式输出按轮次渲染为语义分块。
// Agent 调度块（以 ▸ 开头）用 accent 标题 + dim 指令；正文块用标准文本色。
func renderStreamContent(rounds []string, width int) string {
	if width < 24 {
		width = 24
	}

	var blocks []string
	for _, round := range rounds {
		text := strings.TrimSpace(round)
		if text == "" {
			continue
		}
		if strings.HasPrefix(text, "▸") {
			blocks = append(blocks, renderAgentBlock(text, width))
		} else {
			blocks = append(blocks, renderChapterBlock(text, width))
		}
	}
	return strings.Join(blocks, "\n\n")
}

// renderAgentBlock 渲染 Agent 调度块：标题 + 分隔线 + 任务指令。
func renderAgentBlock(text string, width int) string {
	headerLine, body, _ := strings.Cut(text, "\n")

	// 标题行 + 分隔线
	titleW := lipgloss.Width(headerLine)
	lineW := max(0, width-titleW-1)
	header := lipgloss.NewStyle().Foreground(colorAccent).Bold(true).Render(headerLine) +
		" " + lipgloss.NewStyle().Foreground(colorDim).Render(strings.Repeat("─", lineW))

	var b strings.Builder
	b.WriteString(header)

	// 任务指令：dim 色，缩进 2 格
	body = strings.TrimSpace(body)
	if body != "" {
		taskStyle := lipgloss.NewStyle().Foreground(colorMuted)
		lines := wrapStreamText(body, max(16, width-6))
		b.WriteString("\n")
		for i, line := range lines {
			if i > 0 {
				b.WriteString("\n")
			}
			b.WriteString(taskStyle.Render("  " + line))
		}
	}
	return b.String()
}

// renderChapterBlock 渲染正文块，自动区分思考内容和章节正文。
// 思考内容（ThinkingSep 标记的段落）用淡色斜体，正文用标准文本色。
func renderChapterBlock(text string, width int) string {
	contentStyle := lipgloss.NewStyle().Foreground(colorText)
	thinkStyle := lipgloss.NewStyle().Foreground(colorDim).Italic(true)
	wrapW := max(16, width-4)

	// 按 ThinkingSep 分割：奇数段是思考，偶数段是正文
	// 格式：[正文] \x02 [思考] [正文] \x02 [思考] ...
	parts := strings.Split(text, app.ThinkingSep)

	var b strings.Builder
	for i, part := range parts {
		part = strings.TrimRight(part, " ")
		if part == "" {
			continue
		}
		isThinking := i > 0 && i%2 != 0 // ThinkingSep 之后的奇数段是思考
		// 如果整段都是思考标记开头（第一个 part 之前无正文），调整判断
		if i == 0 && part == "" {
			continue
		}

		style := contentStyle
		if isThinking {
			style = thinkStyle
		}

		lines := wrapStreamText(part, wrapW)
		for j, line := range lines {
			if b.Len() > 0 && j == 0 {
				b.WriteString("\n")
			} else if j > 0 {
				b.WriteString("\n")
			}
			b.WriteString(style.Render(line))
		}
	}
	return b.String()
}

func wrapStreamText(text string, width int) []string {
	if width < 8 {
		return []string{text}
	}

	var out []string
	for _, raw := range strings.Split(strings.ReplaceAll(text, "\r\n", "\n"), "\n") {
		if strings.TrimSpace(raw) == "" {
			out = append(out, "")
			continue
		}
		if compact, ok := compactJSONLine(raw, width); ok {
			out = append(out, compact)
			continue
		}
		prefix, rest, nextPrefix := parseWrapPrefix(raw)
		wrapped := wrapRunes(rest, max(4, width-lipgloss.Width(prefix)))
		for i, line := range wrapped {
			if i == 0 {
				out = append(out, prefix+line)
				continue
			}
			out = append(out, nextPrefix+line)
		}
	}
	return out
}

func compactJSONLine(line string, width int) (string, bool) {
	trimmed := strings.TrimSpace(line)
	if trimmed == "" {
		return "", false
	}
	if !(strings.HasPrefix(trimmed, "{") || strings.HasPrefix(trimmed, "[")) {
		return "", false
	}

	var value any
	if err := json.Unmarshal([]byte(trimmed), &value); err != nil {
		return "", false
	}

	compact, err := json.Marshal(value)
	if err != nil {
		return "", false
	}

	text := string(compact)
	limit := max(24, width-2)
	if lipgloss.Width(text) > limit {
		text = truncate(text, limit-1)
	}
	return lipgloss.NewStyle().Foreground(colorDim).Render("JSON: ") +
		lipgloss.NewStyle().Foreground(lipgloss.Color("#8fb7c9")).Render(text), true
}

func parseWrapPrefix(line string) (prefix, content, nextPrefix string) {
	indent := line[:len(line)-len(strings.TrimLeft(line, " \t"))]
	trimmed := strings.TrimSpace(line)

	switch {
	case strings.HasPrefix(trimmed, "- "), strings.HasPrefix(trimmed, "* "), strings.HasPrefix(trimmed, "• "):
		prefix = indent + trimmed[:2]
		content = strings.TrimSpace(trimmed[2:])
		nextPrefix = indent + "  "
		return prefix, content, nextPrefix
	case orderedListPrefix(trimmed) != "":
		marker := orderedListPrefix(trimmed)
		prefix = indent + marker
		content = strings.TrimSpace(strings.TrimPrefix(trimmed, marker))
		nextPrefix = indent + strings.Repeat(" ", lipgloss.Width(marker))
		return prefix, content, nextPrefix
	case strings.HasPrefix(trimmed, "```"):
		return indent, trimmed, indent
	default:
		return indent, trimmed, indent
	}
}

func orderedListPrefix(line string) string {
	end := strings.Index(line, ". ")
	if end <= 0 {
		return ""
	}
	for _, r := range line[:end] {
		if r < '0' || r > '9' {
			return ""
		}
	}
	return line[:end+2]
}

func wrapRunes(text string, width int) []string {
	if text == "" {
		return []string{""}
	}
	if width < 2 {
		return []string{text}
	}

	var lines []string
	var current strings.Builder
	currentWidth := 0

	for _, r := range text {
		rw := lipgloss.Width(string(r))
		if currentWidth > 0 && currentWidth+rw > width {
			lines = append(lines, strings.TrimRight(current.String(), " "))
			current.Reset()
			currentWidth = 0
			if r == ' ' {
				continue
			}
		}
		current.WriteRune(r)
		currentWidth += rw
	}
	if current.Len() > 0 {
		lines = append(lines, strings.TrimRight(current.String(), " "))
	}
	if len(lines) == 0 {
		return []string{""}
	}
	return lines
}

func max(a, b int) int {
	if a > b {
		return a
	}
	return b
}

// renderDetailContent 构建右侧详情面板内容。
// 优先展示基础设定（大纲、角色），然后是运行时信息（提交、审阅等）。
func renderDetailContent(snap app.UISnapshot, contentW int) string {
	var b strings.Builder

	// 大纲
	if len(snap.Outline) > 0 {
		b.WriteString(panelTitleStyle.Render("大纲"))
		b.WriteString("\n")
		for _, e := range snap.Outline {
			ch := fmt.Sprintf("%2d", e.Chapter)
			// 已完成的章节用绿色标记
			marker := lipgloss.NewStyle().Foreground(colorDim).Render("○")
			if snap.CompletedCount >= e.Chapter {
				marker = lipgloss.NewStyle().Foreground(colorSuccess).Render("●")
			} else if snap.InProgressChapter == e.Chapter {
				marker = lipgloss.NewStyle().Foreground(colorAccent).Render("◐")
			}
			title := truncate(e.Title, contentW-6)
			line := marker + lipgloss.NewStyle().Foreground(colorDim).Render(ch) + " " +
				cardContentStyle.Render(title)
			b.WriteString(line)
			b.WriteString("\n")
		}
		b.WriteString("\n")
	}

	// 角色
	if len(snap.Characters) > 0 {
		b.WriteString(panelTitleStyle.Render("角色"))
		b.WriteString("\n")
		for _, c := range snap.Characters {
			b.WriteString(cardContentStyle.Render("· " + truncate(c, contentW-2)))
			b.WriteString("\n")
		}
		b.WriteString("\n")
	}

	// 前提
	if snap.Premise != "" {
		b.WriteString(panelTitleStyle.Render("前提"))
		b.WriteString("\n")
		b.WriteString(lipgloss.NewStyle().Foreground(colorDim).Render(truncate(snap.Premise, contentW*3)))
		b.WriteString("\n\n")
	}

	// 运行时信息
	if snap.LastCommitSummary != "" {
		b.WriteString(cardTitleStyle.Render("─ 最近提交 ─"))
		b.WriteString("\n")
		b.WriteString(cardContentStyle.Render(snap.LastCommitSummary))
		b.WriteString("\n\n")
	}

	if snap.LastReviewSummary != "" {
		b.WriteString(cardTitleStyle.Render("─ 最近审阅 ─"))
		b.WriteString("\n")
		b.WriteString(cardContentStyle.Render(snap.LastReviewSummary))
		b.WriteString("\n\n")
	}

	if len(snap.RecentSummaries) > 0 {
		b.WriteString(cardTitleStyle.Render("─ 摘要 ─"))
		b.WriteString("\n")
		for _, s := range snap.RecentSummaries {
			b.WriteString(cardContentStyle.Render(truncate(s, contentW)))
			b.WriteString("\n")
		}
	}

	return b.String()
}

// renderDetailPanel 渲染右侧可滚动详情面板。
func renderDetailPanel(vp viewport.Model, width, height int, focused bool) string {
	borderColor := colorDim
	if focused {
		borderColor = colorAccent
	}
	style := lipgloss.NewStyle().
		Width(width).
		Height(height).
		Border(baseBorder, false, false, false, true).
		BorderForeground(borderColor).
		Padding(0, 1)

	return style.Render(vp.View())
}

// renderWelcome 渲染新建态首屏。
func renderWelcome(width, height int, errMsg string) string {
	content := lipgloss.NewStyle().Foreground(colorText).Render("还没有开始创作。") + "\n\n" +
		lipgloss.NewStyle().Foreground(colorDim).Render("请输入你的小说需求，系统会先进入设定与大纲阶段。") + "\n\n" +
		lipgloss.NewStyle().Foreground(colorAccent).Render("示例：写一部 12 章都市悬疑小说，主角是一名女法医")

	if errMsg != "" {
		content += "\n\n" + lipgloss.NewStyle().Foreground(colorError).Bold(true).Render("错误: "+errMsg)
	}

	return lipgloss.NewStyle().
		Width(width).
		Height(height).
		AlignHorizontal(lipgloss.Center).
		AlignVertical(lipgloss.Center).
		Render(content)
}
