package bot

import (
	"context"
	"fmt"
	"log"
	"strings"
	"time"

	xchart "ops-assistant/internal/chart"
	"ops-assistant/internal/core/ops"
	"ops-assistant/internal/service"
	"ops-assistant/models"

	tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5"
	"gorm.io/gorm"
)

// DefaultUserID 统一用户ID，使所有平台共享同一份账本
const DefaultUserID int64 = 1

type TGBot struct {
	api     *tgbotapi.BotAPI
	finance *service.FinanceService
	db      *gorm.DB
	opsSvc  *ops.Service
}

func NewTGBot(db *gorm.DB, token string, finance *service.FinanceService, opsSvc *ops.Service) (*TGBot, error) {
	bot, err := tgbotapi.NewBotAPI(token)
	if err != nil {
		return nil, err
	}
	return &TGBot{api: bot, finance: finance, db: db, opsSvc: opsSvc}, nil
}

func (b *TGBot) Start(ctx context.Context) {
	u := tgbotapi.NewUpdate(0)
	u.Timeout = 60
	updates := b.api.GetUpdatesChan(u)

	log.Println("🚀 Telegram Bot 已启动")

	for {
		select {
		case <-ctx.Done():
			log.Println("⏳ Telegram Bot 正在停止...")
			b.api.StopReceivingUpdates()
			return
		case update, ok := <-updates:
			if !ok {
				return
			}
			if update.Message == nil || update.Message.Text == "" {
				continue
			}

			eventID := fmt.Sprintf("tg:%d", update.UpdateID)
			if b.isDuplicate(eventID) {
				continue
			}
			log.Printf("📩 inbound platform=telegram event=%s chat=%d user=%d text=%q", eventID, update.Message.Chat.ID, update.Message.From.ID, strings.TrimSpace(update.Message.Text))
			b.handleMessage(update.Message)
		}
	}
}

func (b *TGBot) isDuplicate(eventID string) bool {
	if b.db == nil || strings.TrimSpace(eventID) == "" {
		return false
	}
	var existed models.MessageDedup
	if err := b.db.Where("platform = ? AND event_id = ?", "telegram", eventID).First(&existed).Error; err == nil {
		return true
	}
	_ = b.db.Create(&models.MessageDedup{Platform: "telegram", EventID: eventID, ProcessedAt: time.Now()}).Error
	return false
}

func (b *TGBot) handleMessage(msg *tgbotapi.Message) {
	text := msg.Text
	chatID := msg.Chat.ID

	if b.opsSvc != nil {
		if handled, out := b.opsSvc.Handle(DefaultUserID, text); handled {
			m := tgbotapi.NewMessage(chatID, out)
			if _, err := b.api.Send(m); err != nil {
				log.Printf("发送OPS消息失败 chat=%d: %v", chatID, err)
			}
			return
		}
	}

	var reply string

	switch {
	case text == "/start":
		reply = "🛠️ 欢迎使用 Ops-Assistant！\n\n直接发送消费描述即可记账，例如：\n• 午饭 25元\n• 打车 ¥30\n• 买咖啡15块\n\n命令：\n/list - 查看最近记录\n/today - 今日汇总\n/chart - 本月图表\n/help - 帮助"

	case text == "/help":
		reply = "📖 使用说明：\n\n直接发送带金额的文本即可自动记账。\n系统会自动识别金额和消费分类。\n\n支持格式：\n• 午饭 25元\n• ¥30 打车\n• 买水果15块\n\n命令：\n/list - 最近10条记录\n/today - 今日汇总\n/chart - 本月消费图表\n/week - 近7天每日趋势\n/start - 欢迎信息"

	case text == "/today":
		today := time.Now().Format("2006-01-02")
		items, err := b.finance.GetTransactionsByDate(DefaultUserID, today)
		if err != nil {
			reply = "❌ 查询失败"
		} else if len(items) == 0 {
			reply = fmt.Sprintf("📭 %s 暂无消费记录", today)
		} else {
			var sb strings.Builder
			var total int64
			sb.WriteString(fmt.Sprintf("📊 今日（%s）消费：\n\n", today))
			for _, item := range items {
				sb.WriteString(fmt.Sprintf("• %s：%.2f元\n", item.Category, item.AmountYuan()))
				total += item.Amount
			}
			sb.WriteString(fmt.Sprintf("\n💰 共 %d 笔，合计 %.2f 元", len(items), float64(total)/100.0))
			reply = sb.String()
		}

	case text == "/chart":
		b.sendMonthlyChart(chatID)
		return

	case text == "/week":
		b.sendWeeklyChart(chatID)
		return

	case text == "/list":
		items, err := b.finance.GetTransactions(DefaultUserID, 10)
		if err != nil {
			reply = "❌ 查询失败"
		} else if len(items) == 0 {
			reply = "📭 暂无记录"
		} else {
			var sb strings.Builder
			sb.WriteString("📋 最近记录：\n\n")
			for _, item := range items {
				sb.WriteString(fmt.Sprintf("• [%s] %s：%.2f元\n", item.Date, item.Category, item.AmountYuan()))
			}
			reply = sb.String()
		}

	case strings.HasPrefix(text, "/"):
		reply = "❓ 未知命令，输入 /help 查看帮助"

	default:
		amount, category, err := b.finance.AddTransaction(DefaultUserID, text)
		if err != nil {
			reply = "❌ 记账失败，请稍后重试"
			log.Printf("记账失败: %v", err)
		} else if amount == 0 {
			reply = "📍 没看到金额，这笔花了多少钱？"
		} else {
			amountYuan := float64(amount) / 100.0
			reply = fmt.Sprintf("✅ 已记入【%s】：%.2f元\n📝 备注：%s", category, amountYuan, text)
		}
	}

	m := tgbotapi.NewMessage(chatID, reply)
	if _, err := b.api.Send(m); err != nil {
		log.Printf("发送消息失败 chat=%d: %v", chatID, err)
	}
}

func (b *TGBot) sendMonthlyChart(chatID int64) {
	now := time.Now()
	dateFrom := now.Format("2006-01") + "-01"
	dateTo := now.Format("2006-01-02")
	title := fmt.Sprintf("%d年%d月消费分类", now.Year(), now.Month())

	stats, err := b.finance.GetCategoryStats(DefaultUserID, dateFrom, dateTo)
	if err != nil || len(stats) == 0 {
		m := tgbotapi.NewMessage(chatID, "📭 本月暂无消费数据")
		b.api.Send(m)
		return
	}

	imgData, err := xchart.GeneratePieChart(stats, title)
	if err != nil {
		log.Printf("生成饼图失败: %v", err)
		m := tgbotapi.NewMessage(chatID, "❌ 图表生成失败")
		b.api.Send(m)
		return
	}

	var total int64
	var totalCount int
	for _, s := range stats {
		total += s.Total
		totalCount += s.Count
	}
	caption := fmt.Sprintf("📊 %s\n💰 共 %d 笔，合计 %.2f 元", title, totalCount, float64(total)/100.0)

	photo := tgbotapi.NewPhoto(chatID, tgbotapi.FileBytes{Name: "chart.png", Bytes: imgData})
	photo.Caption = caption
	if _, err := b.api.Send(photo); err != nil {
		log.Printf("发送图表失败 chat=%d: %v", chatID, err)
	}
}

func (b *TGBot) sendWeeklyChart(chatID int64) {
	now := time.Now()
	dateFrom := now.AddDate(0, 0, -6).Format("2006-01-02")
	dateTo := now.Format("2006-01-02")
	title := fmt.Sprintf("近7天消费趋势 (%s ~ %s)", dateFrom[5:], dateTo[5:])

	stats, err := b.finance.GetDailyStats(DefaultUserID, dateFrom, dateTo)
	if err != nil || len(stats) == 0 {
		m := tgbotapi.NewMessage(chatID, "📭 近7天暂无消费数据")
		b.api.Send(m)
		return
	}

	imgData, err := xchart.GenerateBarChart(stats, title)
	if err != nil {
		log.Printf("生成柱状图失败: %v", err)
		m := tgbotapi.NewMessage(chatID, "❌ 图表生成失败")
		b.api.Send(m)
		return
	}

	var total int64
	var totalCount int
	for _, s := range stats {
		total += s.Total
		totalCount += s.Count
	}
	caption := fmt.Sprintf("📈 %s\n💰 共 %d 笔，合计 %.2f 元", title, totalCount, float64(total)/100.0)

	photo := tgbotapi.NewPhoto(chatID, tgbotapi.FileBytes{Name: "chart.png", Bytes: imgData})
	photo.Caption = caption
	if _, err := b.api.Send(photo); err != nil {
		log.Printf("发送图表失败 chat=%d: %v", chatID, err)
	}
}
