package ui

import (
	"fmt"
	"strings"

	"github.com/gdamore/tcell/v2"
	"github.com/rivo/tview"

	picoclawconfig "github.com/sipeed/picoclaw/pkg/config"
)

func (s *appState) buildChannelMenuItems() []MenuItem {
	return []MenuItem{
		channelItem(
			"Telegram",
			"Telegram bot settings",
			s.config.Channels.Telegram.Enabled,
			func() { s.push("channel-telegram", s.telegramForm()) },
		),
		channelItem(
			"Discord",
			"Discord bot settings",
			s.config.Channels.Discord.Enabled,
			func() { s.push("channel-discord", s.discordForm()) },
		),
		channelItem(
			"QQ",
			"QQ bot settings",
			s.config.Channels.QQ.Enabled,
			func() { s.push("channel-qq", s.qqForm()) },
		),
		channelItem(
			"MaixCam",
			"MaixCam gateway",
			s.config.Channels.MaixCam.Enabled,
			func() { s.push("channel-maixcam", s.maixcamForm()) },
		),
		channelItem(
			"WhatsApp",
			"WhatsApp bridge",
			s.config.Channels.WhatsApp.Enabled,
			func() { s.push("channel-whatsapp", s.whatsappForm()) },
		),
		channelItem(
			"Feishu",
			"Feishu bot settings",
			s.config.Channels.Feishu.Enabled,
			func() { s.push("channel-feishu", s.feishuForm()) },
		),
		channelItem(
			"DingTalk",
			"DingTalk bot settings",
			s.config.Channels.DingTalk.Enabled,
			func() { s.push("channel-dingtalk", s.dingtalkForm()) },
		),
		channelItem(
			"Slack",
			"Slack bot settings",
			s.config.Channels.Slack.Enabled,
			func() { s.push("channel-slack", s.slackForm()) },
		),
		channelItem(
			"Matrix",
			"Matrix bot settings",
			s.config.Channels.Matrix.Enabled,
			func() { s.push("channel-matrix", s.matrixForm()) },
		),
		channelItem(
			"LINE",
			"LINE bot settings",
			s.config.Channels.LINE.Enabled,
			func() { s.push("channel-line", s.lineForm()) },
		),
		channelItem(
			"OneBot",
			"OneBot settings",
			s.config.Channels.OneBot.Enabled,
			func() { s.push("channel-onebot", s.onebotForm()) },
		),
		channelItem(
			"WeCom",
			"WeCom bot settings",
			s.config.Channels.WeCom.Enabled,
			func() { s.push("channel-wecom", s.wecomForm()) },
		),
		channelItem(
			"WeCom App",
			"WeCom App settings",
			s.config.Channels.WeComApp.Enabled,
			func() { s.push("channel-wecomapp", s.wecomAppForm()) },
		),
	}
}

func (s *appState) channelMenu() tview.Primitive {
	menu := NewMenu("Channels", s.buildChannelMenuItems())
	menu.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
		if event.Key() == tcell.KeyEsc {
			s.pop()
			return nil
		}
		return event
	})
	return menu
}

func refreshChannelMenuFromState(menu *Menu, s *appState) {
	menu.applyItems(s.buildChannelMenuItems())
}

func (s *appState) telegramForm() tview.Primitive {
	cfg := &s.config.Channels.Telegram
	form := baseChannelForm("Telegram", cfg.Enabled, s.makeChannelOnEnabled(&cfg.Enabled))
	form.AddInputField("Token", cfg.Token, 128, nil, func(text string) {
		cfg.Token = strings.TrimSpace(text)
	})
	form.AddInputField("Proxy", cfg.Proxy, 128, nil, func(text string) {
		cfg.Proxy = strings.TrimSpace(text)
	})
	addAllowFromField(form, &cfg.AllowFrom)
	return wrapWithBack(form, s)
}

func (s *appState) discordForm() tview.Primitive {
	cfg := &s.config.Channels.Discord
	form := baseChannelForm("Discord", cfg.Enabled, s.makeChannelOnEnabled(&cfg.Enabled))
	form.AddInputField("Token", cfg.Token, 128, nil, func(text string) {
		cfg.Token = strings.TrimSpace(text)
	})
	form.AddCheckbox("Mention Only", cfg.MentionOnly, func(checked bool) {
		cfg.MentionOnly = checked
	})
	addAllowFromField(form, &cfg.AllowFrom)
	return wrapWithBack(form, s)
}

func (s *appState) qqForm() tview.Primitive {
	cfg := &s.config.Channels.QQ
	form := baseChannelForm("QQ", cfg.Enabled, s.makeChannelOnEnabled(&cfg.Enabled))
	form.AddInputField("App ID", cfg.AppID, 64, nil, func(text string) {
		cfg.AppID = strings.TrimSpace(text)
	})
	form.AddInputField("App Secret", cfg.AppSecret, 128, nil, func(text string) {
		cfg.AppSecret = strings.TrimSpace(text)
	})
	addAllowFromField(form, &cfg.AllowFrom)
	return wrapWithBack(form, s)
}

func (s *appState) maixcamForm() tview.Primitive {
	cfg := &s.config.Channels.MaixCam
	form := baseChannelForm("MaixCam", cfg.Enabled, s.makeChannelOnEnabled(&cfg.Enabled))
	form.AddInputField("Host", cfg.Host, 64, nil, func(text string) {
		cfg.Host = strings.TrimSpace(text)
	})
	addIntField(form, "Port", cfg.Port, func(value int) { cfg.Port = value })
	addAllowFromField(form, &cfg.AllowFrom)
	return wrapWithBack(form, s)
}

func (s *appState) whatsappForm() tview.Primitive {
	cfg := &s.config.Channels.WhatsApp
	form := baseChannelForm("WhatsApp", cfg.Enabled, s.makeChannelOnEnabled(&cfg.Enabled))
	form.AddInputField("Bridge URL", cfg.BridgeURL, 128, nil, func(text string) {
		cfg.BridgeURL = strings.TrimSpace(text)
	})
	addAllowFromField(form, &cfg.AllowFrom)
	return wrapWithBack(form, s)
}

func (s *appState) feishuForm() tview.Primitive {
	cfg := &s.config.Channels.Feishu
	form := baseChannelForm("Feishu", cfg.Enabled, s.makeChannelOnEnabled(&cfg.Enabled))
	form.AddInputField("App ID", cfg.AppID, 64, nil, func(text string) {
		cfg.AppID = strings.TrimSpace(text)
	})
	form.AddInputField("App Secret", cfg.AppSecret, 128, nil, func(text string) {
		cfg.AppSecret = strings.TrimSpace(text)
	})
	form.AddInputField("Encrypt Key", cfg.EncryptKey, 128, nil, func(text string) {
		cfg.EncryptKey = strings.TrimSpace(text)
	})
	form.AddInputField("Verification Token", cfg.VerificationToken, 128, nil, func(text string) {
		cfg.VerificationToken = strings.TrimSpace(text)
	})
	addAllowFromField(form, &cfg.AllowFrom)
	return wrapWithBack(form, s)
}

func (s *appState) dingtalkForm() tview.Primitive {
	cfg := &s.config.Channels.DingTalk
	form := baseChannelForm("DingTalk", cfg.Enabled, s.makeChannelOnEnabled(&cfg.Enabled))
	form.AddInputField("Client ID", cfg.ClientID, 64, nil, func(text string) {
		cfg.ClientID = strings.TrimSpace(text)
	})
	form.AddInputField("Client Secret", cfg.ClientSecret, 128, nil, func(text string) {
		cfg.ClientSecret = strings.TrimSpace(text)
	})
	addAllowFromField(form, &cfg.AllowFrom)
	return wrapWithBack(form, s)
}

func (s *appState) slackForm() tview.Primitive {
	cfg := &s.config.Channels.Slack
	form := baseChannelForm("Slack", cfg.Enabled, s.makeChannelOnEnabled(&cfg.Enabled))
	form.AddInputField("Bot Token", cfg.BotToken, 128, nil, func(text string) {
		cfg.BotToken = strings.TrimSpace(text)
	})
	form.AddInputField("App Token", cfg.AppToken, 128, nil, func(text string) {
		cfg.AppToken = strings.TrimSpace(text)
	})
	addAllowFromField(form, &cfg.AllowFrom)
	return wrapWithBack(form, s)
}

func (s *appState) lineForm() tview.Primitive {
	cfg := &s.config.Channels.LINE
	form := baseChannelForm("LINE", cfg.Enabled, s.makeChannelOnEnabled(&cfg.Enabled))
	form.AddInputField("Channel Secret", cfg.ChannelSecret, 128, nil, func(text string) {
		cfg.ChannelSecret = strings.TrimSpace(text)
	})
	form.AddInputField("Channel Access Token", cfg.ChannelAccessToken, 128, nil, func(text string) {
		cfg.ChannelAccessToken = strings.TrimSpace(text)
	})
	form.AddInputField("Webhook Host", cfg.WebhookHost, 64, nil, func(text string) {
		cfg.WebhookHost = strings.TrimSpace(text)
	})
	addIntField(form, "Webhook Port", cfg.WebhookPort, func(value int) { cfg.WebhookPort = value })
	form.AddInputField("Webhook Path", cfg.WebhookPath, 64, nil, func(text string) {
		cfg.WebhookPath = strings.TrimSpace(text)
	})
	addAllowFromField(form, &cfg.AllowFrom)
	return wrapWithBack(form, s)
}

func (s *appState) matrixForm() tview.Primitive {
	cfg := &s.config.Channels.Matrix
	form := baseChannelForm("Matrix", cfg.Enabled, s.makeChannelOnEnabled(&cfg.Enabled))
	form.AddInputField("Homeserver", cfg.Homeserver, 128, nil, func(text string) {
		cfg.Homeserver = strings.TrimSpace(text)
	})
	form.AddInputField("User ID", cfg.UserID, 128, nil, func(text string) {
		cfg.UserID = strings.TrimSpace(text)
	})
	form.AddInputField("Access Token", cfg.AccessToken, 128, nil, func(text string) {
		cfg.AccessToken = strings.TrimSpace(text)
	})
	form.AddInputField("Device ID", cfg.DeviceID, 128, nil, func(text string) {
		cfg.DeviceID = strings.TrimSpace(text)
	})
	form.AddCheckbox("Join On Invite", cfg.JoinOnInvite, func(checked bool) {
		cfg.JoinOnInvite = checked
	})
	addAllowFromField(form, &cfg.AllowFrom)
	return wrapWithBack(form, s)
}

func (s *appState) onebotForm() tview.Primitive {
	cfg := &s.config.Channels.OneBot
	form := baseChannelForm("OneBot", cfg.Enabled, s.makeChannelOnEnabled(&cfg.Enabled))
	form.AddInputField("WS URL", cfg.WSUrl, 128, nil, func(text string) {
		cfg.WSUrl = strings.TrimSpace(text)
	})
	form.AddInputField("Access Token", cfg.AccessToken, 128, nil, func(text string) {
		cfg.AccessToken = strings.TrimSpace(text)
	})
	addIntField(
		form,
		"Reconnect Interval",
		cfg.ReconnectInterval,
		func(value int) { cfg.ReconnectInterval = value },
	)
	form.AddInputField(
		"Group Trigger Prefix",
		strings.Join(cfg.GroupTriggerPrefix, ","),
		128,
		nil,
		func(text string) {
			cfg.GroupTriggerPrefix = splitCSV(text)
		},
	)
	addAllowFromField(form, &cfg.AllowFrom)
	return wrapWithBack(form, s)
}

func (s *appState) wecomForm() tview.Primitive {
	cfg := &s.config.Channels.WeCom
	form := baseChannelForm("WeCom", cfg.Enabled, s.makeChannelOnEnabled(&cfg.Enabled))
	form.AddInputField("Token", cfg.Token, 128, nil, func(text string) {
		cfg.Token = strings.TrimSpace(text)
	})
	form.AddInputField("Encoding AES Key", cfg.EncodingAESKey, 128, nil, func(text string) {
		cfg.EncodingAESKey = strings.TrimSpace(text)
	})
	form.AddInputField("Webhook URL", cfg.WebhookURL, 128, nil, func(text string) {
		cfg.WebhookURL = strings.TrimSpace(text)
	})
	form.AddInputField("Webhook Host", cfg.WebhookHost, 64, nil, func(text string) {
		cfg.WebhookHost = strings.TrimSpace(text)
	})
	addIntField(form, "Webhook Port", cfg.WebhookPort, func(value int) { cfg.WebhookPort = value })
	form.AddInputField("Webhook Path", cfg.WebhookPath, 64, nil, func(text string) {
		cfg.WebhookPath = strings.TrimSpace(text)
	})
	addAllowFromField(form, &cfg.AllowFrom)
	addIntField(
		form,
		"Reply Timeout",
		cfg.ReplyTimeout,
		func(value int) { cfg.ReplyTimeout = value },
	)
	return wrapWithBack(form, s)
}

func (s *appState) wecomAppForm() tview.Primitive {
	cfg := &s.config.Channels.WeComApp
	form := baseChannelForm("WeCom App", cfg.Enabled, s.makeChannelOnEnabled(&cfg.Enabled))
	form.AddInputField("Corp ID", cfg.CorpID, 64, nil, func(text string) {
		cfg.CorpID = strings.TrimSpace(text)
	})
	form.AddInputField("Corp Secret", cfg.CorpSecret, 128, nil, func(text string) {
		cfg.CorpSecret = strings.TrimSpace(text)
	})
	addInt64Field(form, "Agent ID", cfg.AgentID, func(value int64) { cfg.AgentID = value })
	form.AddInputField("Token", cfg.Token, 128, nil, func(text string) {
		cfg.Token = strings.TrimSpace(text)
	})
	form.AddInputField("Encoding AES Key", cfg.EncodingAESKey, 128, nil, func(text string) {
		cfg.EncodingAESKey = strings.TrimSpace(text)
	})
	form.AddInputField("Webhook Host", cfg.WebhookHost, 64, nil, func(text string) {
		cfg.WebhookHost = strings.TrimSpace(text)
	})
	addIntField(form, "Webhook Port", cfg.WebhookPort, func(value int) { cfg.WebhookPort = value })
	form.AddInputField("Webhook Path", cfg.WebhookPath, 64, nil, func(text string) {
		cfg.WebhookPath = strings.TrimSpace(text)
	})
	addAllowFromField(form, &cfg.AllowFrom)
	addIntField(
		form,
		"Reply Timeout",
		cfg.ReplyTimeout,
		func(value int) { cfg.ReplyTimeout = value },
	)
	return wrapWithBack(form, s)
}

func (s *appState) makeChannelOnEnabled(enabledPtr *bool) func(bool) {
	return func(v bool) {
		*enabledPtr = v
		s.dirty = true
		refreshMainMenuIfPresent(s)
		if menu, ok := s.menus["channel"]; ok {
			refreshChannelMenuFromState(menu, s)
		}
	}
}

func addAllowFromField(form *tview.Form, allowFrom *picoclawconfig.FlexibleStringSlice) {
	form.AddInputField("Allow From", strings.Join(*allowFrom, ","), 128, nil, func(text string) {
		*allowFrom = splitCSV(text)
	})
}

func baseChannelForm(title string, enabled bool, onEnabled func(bool)) *tview.Form {
	form := tview.NewForm()
	form.SetBorder(true).SetTitle(fmt.Sprintf("Channel: %s", title))
	form.SetButtonBackgroundColor(tcell.NewRGBColor(80, 250, 123))
	form.SetButtonTextColor(tcell.NewRGBColor(12, 13, 22))
	form.AddCheckbox("Enabled", enabled, func(checked bool) {
		onEnabled(checked)
	})
	return form
}

func wrapWithBack(form *tview.Form, s *appState) tview.Primitive {
	form.AddButton("Back", func() {
		s.pop()
	})
	form.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
		if event.Key() == tcell.KeyEsc {
			s.pop()
			return nil
		}
		return event
	})
	return form
}

func splitCSV(input string) picoclawconfig.FlexibleStringSlice {
	parts := strings.Split(strings.TrimSpace(input), ",")
	cleaned := make([]string, 0, len(parts))
	for _, part := range parts {
		value := strings.TrimSpace(part)
		if value == "" {
			continue
		}
		cleaned = append(cleaned, value)
	}
	return cleaned
}

func addIntField(form *tview.Form, label string, value int, onChange func(int)) {
	form.AddInputField(label, fmt.Sprintf("%d", value), 16, nil, func(text string) {
		var parsed int
		if _, err := fmt.Sscanf(strings.TrimSpace(text), "%d", &parsed); err == nil {
			onChange(parsed)
		}
	})
}

func addInt64Field(form *tview.Form, label string, value int64, onChange func(int64)) {
	form.AddInputField(label, fmt.Sprintf("%d", value), 16, nil, func(text string) {
		var parsed int64
		if _, err := fmt.Sscanf(strings.TrimSpace(text), "%d", &parsed); err == nil {
			onChange(parsed)
		}
	})
}

func channelItem(label, description string, enabled bool, action MenuAction) MenuItem {
	item := MenuItem{
		Label:       label,
		Description: description,
		Action:      action,
	}
	if !enabled {
		color := tcell.ColorGray
		item.MainColor = &color
	}
	return item
}
