package telegram

import (
	"context"
	"fmt"
	"io"
	"net/http"
	"strings"
	"time"

	"go.uber.org/zap"
	tele "gopkg.in/telebot.v3"
	"gopkg.in/telebot.v3/middleware"

	"rmser/config"
	"rmser/internal/services/ocr"
	"rmser/pkg/logger"
)

type Bot struct {
	b          *tele.Bot
	ocrService *ocr.Service
	adminIDs   map[int64]struct{}
}

func NewBot(cfg config.TelegramConfig, ocrService *ocr.Service) (*Bot, error) {
	pref := tele.Settings{
		Token:  cfg.Token,
		Poller: &tele.LongPoller{Timeout: 10 * time.Second},
		OnError: func(err error, c tele.Context) {
			logger.Log.Error("Telegram error", zap.Error(err))
		},
	}

	b, err := tele.NewBot(pref)
	if err != nil {
		return nil, err
	}

	admins := make(map[int64]struct{})
	for _, id := range cfg.AdminIDs {
		admins[id] = struct{}{}
	}

	bot := &Bot{
		b:          b,
		ocrService: ocrService,
		adminIDs:   admins,
	}

	bot.initHandlers()
	return bot, nil
}

func (bot *Bot) Start() {
	logger.Log.Info("Запуск Telegram бота...")
	bot.b.Start()
}

func (bot *Bot) Stop() {
	bot.b.Stop()
}

// Middleware для проверки прав (только админы)
func (bot *Bot) authMiddleware(next tele.HandlerFunc) tele.HandlerFunc {
	return func(c tele.Context) error {
		if len(bot.adminIDs) > 0 {
			if _, ok := bot.adminIDs[c.Sender().ID]; !ok {
				return c.Send("⛔ У вас нет доступа к этому боту.")
			}
		}
		return next(c)
	}
}

func (bot *Bot) initHandlers() {
	bot.b.Use(middleware.Logger())
	bot.b.Use(bot.authMiddleware)

	bot.b.Handle("/start", func(c tele.Context) error {
		return c.Send("👋 Привет! Я RMSER Bot.\nОтправь мне фото накладной или чека, и я попробую его распознать.")
	})

	bot.b.Handle(tele.OnPhoto, bot.handlePhoto)
}

func (bot *Bot) handlePhoto(c tele.Context) error {
	// 1. Скачиваем фото
	photo := c.Message().Photo
	// Берем файл самого высокого качества (последний в массиве, но telebot дает удобный доступ)
	file, err := bot.b.FileByID(photo.FileID)
	if err != nil {
		return c.Send("Ошибка доступа к файлу.")
	}

	// Читаем тело файла
	fileURL := fmt.Sprintf("https://api.telegram.org/file/bot%s/%s", bot.b.Token, file.FilePath)
	resp, err := http.Get(fileURL)
	if err != nil {
		return c.Send("Ошибка скачивания файла.")
	}
	defer resp.Body.Close()

	imgData, err := io.ReadAll(resp.Body)
	if err != nil {
		return c.Send("Ошибка чтения файла.")
	}

	c.Send("⏳ Обрабатываю чек через OCR...")

	// 2. Отправляем в сервис
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	items, err := bot.ocrService.ProcessReceiptImage(ctx, imgData)
	if err != nil {
		logger.Log.Error("OCR processing failed", zap.Error(err))
		return c.Send("❌ Ошибка распознавания: " + err.Error())
	}

	// 3. Формируем отчет
	var sb strings.Builder
	sb.WriteString(fmt.Sprintf("🧾 <b>Результат (%d поз.):</b>\n\n", len(items)))

	matchedCount := 0
	for _, item := range items {
		if item.IsMatched {
			matchedCount++
			sb.WriteString(fmt.Sprintf("✅ %s\n   └ <code>%s</code> x %s = %s\n",
				item.RawName, item.Amount, item.Price, item.Sum))
		} else {
			sb.WriteString(fmt.Sprintf("❓ <b>%s</b>\n   └ Нет привязки!\n", item.RawName))
		}
	}

	sb.WriteString(fmt.Sprintf("\nРаспознано: %d/%d", matchedCount, len(items)))

	// Тут можно добавить кнопки, если что-то не распознано
	// Но для начала просто текст
	return c.Send(sb.String(), tele.ModeHTML)
}
