package screens
import (
"context"
"fmt"
"strings"
"example.com/m/adapter/backend"
"example.com/m/bot"
"github.com/NicoNex/echotron/v3"
"github.com/rs/zerolog/log"
)
type PlacementPurchasePlan struct {
WorkspaceID string
ProjectID string
AddPlacementState *AddPlacement
}
func (s *PlacementPurchasePlan) Enter(b *bot.Bot, mode bot.RenderMode) {
jwt, err := s.ensureJWT(b)
if err != nil {
log.Error().Err(err).Msg("Failed to get JWT")
b.SendNew("❌ Ошибка авторизации. Попробуйте /start", bot.Keyboard())
return
}
s.renderChannels(b, mode, jwt)
}
func (s *PlacementPurchasePlan) renderChannels(b *bot.Bot, mode bot.RenderMode, jwt string) {
channels, err := b.Backend.GetPurchasePlanChannels(
context.Background(),
jwt,
s.WorkspaceID,
s.ProjectID,
)
if err != nil {
log.Error().Err(err).Msg("Failed to get purchase plan channels")
b.SendNew("❌ Не удалось загрузить каналы", bot.Keyboard())
return
}
text := "📋 План закупа — Каналы\n\n"
var buttons [][]echotron.InlineKeyboardButton
if len(channels) == 0 {
text += "Список каналов пуст.\n\n"
} else {
text += "Нажмите на канал для удаления:\n\n"
for _, ch := range channels {
channelName := "Без названия"
if ch.Channel.Title != nil {
channelName = *ch.Channel.Title
} else if ch.Channel.Username != nil {
channelName = "@" + *ch.Channel.Username
}
// Показываем статус и стоимость
statusEmoji := "📌"
switch ch.Status {
case "planned":
statusEmoji = "📝"
case "approved":
statusEmoji = "✅"
case "rejected":
statusEmoji = "❌"
case "in_progress":
statusEmoji = "🔄"
case "completed":
statusEmoji = "✔️"
}
buttonText := fmt.Sprintf("%s %s", statusEmoji, channelName)
if ch.PlannedCost != nil {
buttonText += fmt.Sprintf(" (%.0f₽)", *ch.PlannedCost)
}
buttons = append(buttons, bot.Row(
bot.Button(buttonText, fmt.Sprintf("remove:%s", ch.ID)),
))
}
}
// Инструкция по добавлению канала
text += "\nДобавление канала:\nОтправьте username канала (без @)"
// Навигация
var navRow []echotron.InlineKeyboardButton
navRow = append(navRow, bot.Button("« Назад", "back"))
navRow = append(navRow, bot.Button("Далее →", "next"))
buttons = append(buttons, navRow)
keyboard := bot.Keyboard(buttons...)
b.Render(text, keyboard, mode)
}
func (s *PlacementPurchasePlan) ensureJWT(b *bot.Bot) (string, error) {
if b.Session.JWT != "" {
return b.Session.JWT, nil
}
jwt, err := b.Backend.GetJWTByTelegramID(context.Background(), b.ChatID)
if err != nil {
return "", err
}
b.Session.JWT = jwt
return jwt, nil
}
func (s *PlacementPurchasePlan) HandleCallback(b *bot.Bot, u *echotron.Update) {
if u.CallbackQuery == nil || u.CallbackQuery.Data == "" {
return
}
data := u.CallbackQuery.Data
switch {
case data == "back":
if s.AddPlacementState != nil {
b.SetState(s.AddPlacementState, bot.EditMessage)
}
case data == "next":
// TODO: переход к следующему шагу (детали размещения)
b.Edit("🚧 Следующий шаг в разработке", bot.Keyboard(
bot.Row(bot.Button("« Назад", "back_to_purchase_plan")),
))
case data == "back_to_purchase_plan":
s.Enter(b, bot.EditMessage)
case strings.HasPrefix(data, "remove:"):
parts := strings.Split(data, ":")
if len(parts) == 2 {
purchasePlanChannelID := parts[1] // ID записи PurchasePlanChannel
jwt, err := s.ensureJWT(b)
if err != nil {
log.Error().Err(err).Msg("Failed to get JWT")
return
}
// Удаляем канал из плана закупа
err = b.Backend.RemoveChannelFromPurchasePlan(
context.Background(),
jwt,
s.WorkspaceID,
s.ProjectID,
purchasePlanChannelID,
)
if err != nil {
log.Error().Err(err).Str("purchase_plan_channel_id", purchasePlanChannelID).Msg("Failed to remove channel")
b.Edit("❌ Не удалось удалить канал", bot.Keyboard(
bot.Row(bot.Button("« Назад", "back_to_purchase_plan")),
))
return
}
// Обновляем экран
s.Enter(b, bot.EditMessage)
}
default:
s.Enter(b, bot.NewMessage)
}
}
func (s *PlacementPurchasePlan) HandleMessage(b *bot.Bot, u *echotron.Update) {
if u.Message == nil || u.Message.Text == "" {
return
}
username := strings.TrimSpace(u.Message.Text)
// Убираем @ если пользователь его добавил
username = strings.TrimPrefix(username, "@")
if username == "" {
return
}
jwt, err := s.ensureJWT(b)
if err != nil {
log.Error().Err(err).Msg("Failed to get JWT")
b.SendNew("❌ Ошибка авторизации. Попробуйте /start", bot.Keyboard())
return
}
// Отправляем запрос на добавление канала
input := backend.AttachChannelToPurchasePlanInput{
Username: username,
}
_, err = b.Backend.AttachChannelToPurchasePlan(
context.Background(),
jwt,
s.WorkspaceID,
s.ProjectID,
input,
)
if err != nil {
log.Error().Err(err).Str("username", username).Msg("Failed to attach channel")
// Проверяем, содержит ли ошибка информацию о том, что канал не найден
if strings.Contains(err.Error(), "not found") || strings.Contains(err.Error(), "404") {
b.SendNew(fmt.Sprintf("❌ Канал @%s не найден в Telegram.\n\nПроверьте правильность username и попробуйте еще раз.", username), bot.Keyboard())
} else {
b.SendNew("❌ Не удалось добавить канал. Попробуйте позже.", bot.Keyboard())
}
return
}
// Обновляем экран со списком каналов
s.Enter(b, bot.NewMessage)
}
func (s *PlacementPurchasePlan) Handle(_ *bot.Bot, _ *echotron.Update) { return }