package telegram

import (
	"context"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"strconv"
	"strings"
	"time"

	"proxyrotator/internal/importer"
	"proxyrotator/internal/model"
	"proxyrotator/internal/store"

	tele "gopkg.in/telebot.v3"
)

// Commands 命令处理器
type Commands struct {
	store     store.ProxyStore
	scheduler *Scheduler
	importer  *importer.Importer

	// 导入状态
	importState map[int64]*importSession
}

type importSession struct {
	Group string
	Tags  []string
}

// NewCommands 创建命令处理器
func NewCommands(store store.ProxyStore, scheduler *Scheduler) *Commands {
	return &Commands{
		store:       store,
		scheduler:   scheduler,
		importer:    importer.NewImporter(),
		importState: make(map[int64]*importSession),
	}
}

// HandleStart /start 命令
func (c *Commands) HandleStart(ctx tele.Context) error {
	return ctx.Send(`🚀 *ProxyRotator Bot*

欢迎使用代理池管理机器人！

使用 /help 查看可用命令`, &tele.SendOptions{ParseMode: tele.ModeMarkdown})
}

// HandleHelp /help 命令
func (c *Commands) HandleHelp(ctx tele.Context) error {
	help := `📖 *可用命令*

*查询类*
/stats - 代理池统计（总数/存活/死亡/未知）
/groups - 分组统计
/get [n] - 获取 n 个可用代理（默认 5）

*操作类*
/import [group] - 导入代理（之后发送文本或文件）
/test [group] - 触发测活
/purge - 清理死代理

*其他*
/help - 显示帮助信息`

	return ctx.Send(help, &tele.SendOptions{ParseMode: tele.ModeMarkdown})
}

// HandleStats /stats 命令
func (c *Commands) HandleStats(ctx tele.Context) error {
	stats, err := c.store.GetStats(context.Background())
	if err != nil {
		return ctx.Send(fmt.Sprintf("❌ 获取统计失败: %v", err))
	}

	alive := stats.ByStatus[model.StatusAlive]
	dead := stats.ByStatus[model.StatusDead]
	unknown := stats.ByStatus[model.StatusUnknown]

	var alivePercent float64
	if stats.Total > 0 {
		alivePercent = float64(alive) / float64(stats.Total) * 100
	}

	msg := fmt.Sprintf(`📊 *代理池统计*

*总数:* %d
*存活:* %d (%.1f%%)
*死亡:* %d
*未知:* %d
*禁用:* %d

*平均延迟:* %d ms
*平均分数:* %.1f`,
		stats.Total,
		alive, alivePercent,
		dead,
		unknown,
		stats.Disabled,
		stats.AvgLatencyMs,
		stats.AvgScore,
	)

	return ctx.Send(msg, &tele.SendOptions{ParseMode: tele.ModeMarkdown})
}

// HandleGroups /groups 命令
func (c *Commands) HandleGroups(ctx tele.Context) error {
	stats, err := c.store.GetStats(context.Background())
	if err != nil {
		return ctx.Send(fmt.Sprintf("❌ 获取统计失败: %v", err))
	}

	if len(stats.ByGroup) == 0 {
		return ctx.Send("📁 暂无分组数据")
	}

	var sb strings.Builder
	sb.WriteString("📁 *分组统计*\n\n")
	for group, count := range stats.ByGroup {
		sb.WriteString(fmt.Sprintf("• `%s`: %d\n", group, count))
	}

	return ctx.Send(sb.String(), &tele.SendOptions{ParseMode: tele.ModeMarkdown})
}

// IPInfo ipinfo.io 返回结构
type IPInfo struct {
	IP       string `json:"ip"`
	City     string `json:"city"`
	Region   string `json:"region"`
	Country  string `json:"country"`
	Org      string `json:"org"`
}

// HandleGet /get [n] 命令
func (c *Commands) HandleGet(ctx tele.Context) error {
	n := 1
	args := ctx.Args()
	if len(args) > 0 {
		if parsed, err := strconv.Atoi(args[0]); err == nil && parsed > 0 {
			n = parsed
		}
	}
	if n > 20 {
		n = 20
	}

	proxies, err := c.store.List(context.Background(), model.ProxyQuery{
		StatusIn:    []model.ProxyStatus{model.StatusAlive},
		OnlyEnabled: true,
		OrderBy:     "random",
		Limit:       n,
	})
	if err != nil {
		return ctx.Send(fmt.Sprintf("❌ 获取代理失败: %v", err))
	}

	if len(proxies) == 0 {
		return ctx.Send("😢 没有可用代理")
	}

	var sb strings.Builder
	sb.WriteString(fmt.Sprintf("🔗 *可用代理 (%d)*\n\n", len(proxies)))

	for _, p := range proxies {
		var proxyURL string
		if p.Username != "" {
			proxyURL = fmt.Sprintf("%s://%s:%s@%s:%d", p.Protocol, p.Username, p.Password, p.Host, p.Port)
		} else {
			proxyURL = fmt.Sprintf("%s://%s:%d", p.Protocol, p.Host, p.Port)
		}

		// 获取 IP 位置信息
		ipInfo := fetchIPInfo(proxyURL)

		sb.WriteString(fmt.Sprintf("`%s`\n", proxyURL))
		if ipInfo != nil {
			location := fmt.Sprintf("%s, %s, %s", ipInfo.City, ipInfo.Region, ipInfo.Country)
			sb.WriteString(fmt.Sprintf("  📍 %s | %s\n", location, ipInfo.Org))
		} else {
			sb.WriteString("  📍 位置获取失败\n")
		}
		sb.WriteString("\n")
	}

	return ctx.Send(sb.String(), &tele.SendOptions{ParseMode: tele.ModeMarkdown})
}

// fetchIPInfo 通过代理获取 IP 信息
func fetchIPInfo(proxyURL string) *IPInfo {
	proxy, err := url.Parse(proxyURL)
	if err != nil {
		return nil
	}

	client := &http.Client{
		Transport: &http.Transport{
			Proxy: http.ProxyURL(proxy),
		},
		Timeout: 10 * time.Second,
	}

	resp, err := client.Get("https://ipinfo.io/json")
	if err != nil {
		return nil
	}
	defer resp.Body.Close()

	var info IPInfo
	if err := json.NewDecoder(resp.Body).Decode(&info); err != nil {
		return nil
	}

	return &info
}

// HandleTest /test [group] 命令
func (c *Commands) HandleTest(ctx tele.Context) error {
	if c.scheduler == nil {
		return ctx.Send("❌ 调度器未初始化")
	}

	group := ""
	args := ctx.Args()
	if len(args) > 0 {
		group = args[0]
	}

	_ = ctx.Send("🔄 正在执行测活...")

	err := c.scheduler.RunTestWithGroup(context.Background(), group)
	if err != nil {
		return ctx.Send(fmt.Sprintf("❌ 测活失败: %v", err))
	}

	return ctx.Send("✅ 测活完成")
}

// HandlePurge /purge 命令
func (c *Commands) HandlePurge(ctx tele.Context) error {
	deleted, err := c.store.DeleteMany(context.Background(), model.BulkDeleteRequest{
		Status: model.StatusDead,
	})
	if err != nil {
		return ctx.Send(fmt.Sprintf("❌ 清理失败: %v", err))
	}

	return ctx.Send(fmt.Sprintf("🗑️ 已清理 %d 个死代理", deleted))
}

// HandleImport /import [group] 命令
func (c *Commands) HandleImport(ctx tele.Context) error {
	group := "default"
	args := ctx.Args()
	if len(args) > 0 {
		group = args[0]
	}

	userID := ctx.Sender().ID
	c.importState[userID] = &importSession{
		Group: group,
		Tags:  []string{"telegram"},
	}

	return ctx.Send(fmt.Sprintf(`📥 *导入模式已开启*

分组: `+"`%s`"+`

请发送代理列表（文本或文件），支持格式:
• host:port
• host:port:user:pass
• protocol://host:port
• protocol://user:pass@host:port

发送 /cancel 取消导入`, group), &tele.SendOptions{ParseMode: tele.ModeMarkdown})
}

// HandleDocument 处理文件上传
func (c *Commands) HandleDocument(ctx tele.Context) error {
	userID := ctx.Sender().ID
	session, ok := c.importState[userID]
	if !ok {
		return nil // 不在导入模式，忽略
	}

	doc := ctx.Message().Document
	if doc == nil {
		return nil
	}

	// 下载文件
	reader, err := ctx.Bot().File(&doc.File)
	if err != nil {
		return ctx.Send(fmt.Sprintf("❌ 获取文件失败: %v", err))
	}
	defer reader.Close()

	content, err := io.ReadAll(reader)
	if err != nil {
		return ctx.Send(fmt.Sprintf("❌ 读取文件失败: %v", err))
	}

	return c.doImport(ctx, session, string(content))
}

// HandleText 处理文本消息（用于导入）
func (c *Commands) HandleText(ctx tele.Context) error {
	userID := ctx.Sender().ID
	session, ok := c.importState[userID]
	if !ok {
		return nil // 不在导入模式，忽略
	}

	text := ctx.Text()
	if text == "/cancel" {
		delete(c.importState, userID)
		return ctx.Send("❌ 已取消导入")
	}

	// 检查是否像代理格式
	if !strings.Contains(text, ":") {
		return nil // 不像代理，忽略
	}

	return c.doImport(ctx, session, text)
}

// doImport 执行导入
func (c *Commands) doImport(ctx tele.Context, session *importSession, text string) error {
	userID := ctx.Sender().ID
	defer delete(c.importState, userID)

	input := model.ImportInput{
		Group: session.Group,
		Tags:  session.Tags,
	}

	proxies, invalid := c.importer.ParseText(context.Background(), input, text)

	if len(proxies) == 0 {
		return ctx.Send(fmt.Sprintf("❌ 未解析到有效代理\n无效行: %d", len(invalid)))
	}

	imported, duplicated, err := c.store.UpsertMany(context.Background(), proxies)
	if err != nil {
		return ctx.Send(fmt.Sprintf("❌ 导入失败: %v", err))
	}

	msg := fmt.Sprintf(`✅ *导入完成*

• 新增: %d
• 重复: %d
• 无效: %d
• 分组: `+"`%s`",
		imported, duplicated, len(invalid), session.Group)

	return ctx.Send(msg, &tele.SendOptions{ParseMode: tele.ModeMarkdown})
}
