package telegram

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"net/http"
	"time"

	"git.yeij.top/AskaEth/Cyrene/platform-bridge/internal/bridge"
)

// Adapter implements PlatformAdapter for Telegram Bot API.
type Adapter struct {
	token      string
	webhookURL string
	client     *http.Client
	connected  bool
}

func NewAdapter(token, webhookURL string) *Adapter {
	return &Adapter{
		token:      token,
		webhookURL: webhookURL,
		client:     &http.Client{Timeout: 10 * time.Second},
	}
}

func (a *Adapter) PlatformName() string { return "telegram" }

func (a *Adapter) Capabilities() bridge.PlatformCapabilities {
	return bridge.PlatformCapabilities{
		MaxMessageLength:   4096,
		SupportsMarkdown:   true,
		SupportsImage:      true,
		SupportsVoice:      true,
		SupportsEmoji:      true,
		SupportsReaction:   true,
		SupportsTypingHint: true,
		RecommendBurstMax:  3,
	}
}

func (a *Adapter) Connect(ctx context.Context) error {
	if a.token == "" {
		return fmt.Errorf("telegram bot token not configured")
	}
	if a.webhookURL == "" {
		// Polling mode not implemented; webhook required.
		return fmt.Errorf("telegram webhook URL not configured")
	}
	// Set webhook.
	url := fmt.Sprintf("https://api.telegram.org/bot%s/setWebhook?url=%s/api/v1/webhook/telegram", a.token, a.webhookURL)
	resp, err := a.client.Post(url, "application/json", nil)
	if err != nil {
		return fmt.Errorf("failed to set telegram webhook: %w", err)
	}
	defer resp.Body.Close()
	a.connected = true
	fmt.Println("[telegram] webhook set, bot ready")
	return nil
}

func (a *Adapter) Disconnect(ctx context.Context) error {
	if a.token != "" {
		url := fmt.Sprintf("https://api.telegram.org/bot%s/deleteWebhook", a.token)
		a.client.Post(url, "application/json", nil)
	}
	a.connected = false
	return nil
}

func (a *Adapter) IsConnected() bool { return a.connected }

func (a *Adapter) HealthCheck() error {
	if a.token == "" {
		return fmt.Errorf("telegram token not configured")
	}
	url := fmt.Sprintf("https://api.telegram.org/bot%s/getMe", a.token)
	resp, err := a.client.Get(url)
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	if resp.StatusCode != 200 {
		return fmt.Errorf("telegram API returned %d", resp.StatusCode)
	}
	return nil
}

// TelegramUpdate is the webhook payload from Telegram.
type TelegramUpdate struct {
	UpdateID int64              `json:"update_id"`
	Message  *TelegramMessage   `json:"message"`
	Callback *TelegramCallback  `json:"callback_query"`
}

// TelegramMessage represents a Telegram message.
type TelegramMessage struct {
	MessageID int64            `json:"message_id"`
	From      TelegramUser     `json:"from"`
	Chat      TelegramChat     `json:"chat"`
	Text      string           `json:"text"`
	Date      int64            `json:"date"`
	ReplyTo   *TelegramMessage `json:"reply_to_message"`
	Entities  []TelegramEntity `json:"entities"`
}

// TelegramUser represents a Telegram user.
type TelegramUser struct {
	ID        int64  `json:"id"`
	Username  string `json:"username"`
	FirstName string `json:"first_name"`
	LastName  string `json:"last_name"`
}

// TelegramChat represents a Telegram chat.
type TelegramChat struct {
	ID   int64  `json:"id"`
	Type string `json:"type"` // "private", "group", "supergroup", "channel"
}

// TelegramEntity represents a text entity in a Telegram message.
type TelegramEntity struct {
	Type   string `json:"type"` // "mention", "bot_command", etc.
	Offset int    `json:"offset"`
	Length int    `json:"length"`
}

// TelegramCallback represents a callback query.
type TelegramCallback struct {
	ID      string          `json:"id"`
	From    TelegramUser    `json:"from"`
	Message *TelegramMessage `json:"message"`
	Data    string          `json:"data"`
}

// ToUnified converts a Telegram update to UnifiedMessage.
// Accepts both *TelegramUpdate and map[string]interface{} (from webhook).
func (a *Adapter) ToUnified(rawMessage interface{}) (*bridge.UnifiedMessage, error) {
	var msg *TelegramMessage
	switch v := rawMessage.(type) {
	case *TelegramUpdate:
		msg = v.Message
	case map[string]interface{}:
		// Parse from raw webhook payload.
		data, _ := json.Marshal(v)
		var update TelegramUpdate
		if err := json.Unmarshal(data, &update); err != nil {
			return nil, fmt.Errorf("parse telegram update: %w", err)
		}
		msg = update.Message
	default:
		return nil, fmt.Errorf("expected *TelegramUpdate or map, got %T", rawMessage)
	}

	if msg == nil {
		return nil, fmt.Errorf("no message in update")
	}

	channelType := "direct"
	channelID := fmt.Sprintf("%d", msg.Chat.ID)
	if msg.Chat.Type == "group" || msg.Chat.Type == "supergroup" {
		channelType = "group"
	} else if msg.Chat.Type == "channel" {
		channelType = "channel"
	}

	senderName := msg.From.FirstName
	if msg.From.LastName != "" {
		senderName += " " + msg.From.LastName
	}
	if msg.From.Username != "" {
		senderName = msg.From.Username
	}

	replyTo := ""
	if msg.ReplyTo != nil {
		replyTo = fmt.Sprintf("%d", msg.ReplyTo.MessageID)
	}

	return &bridge.UnifiedMessage{
		SenderID:    fmt.Sprintf("%d", msg.From.ID),
		SenderName:  senderName,
		Platform:    "telegram",
		ChannelID:   channelID,
		ChannelType: channelType,
		Content:     msg.Text,
		ContentType: "text",
		MessageID:   fmt.Sprintf("%d", msg.MessageID),
		ReplyTo:     replyTo,
		RawData:     rawMessage,
		Timestamp:   time.Unix(msg.Date, 0),
	}, nil
}

// FromUnified converts a unified response to Telegram messages.
func (a *Adapter) FromUnified(response *bridge.UnifiedResponse) ([]bridge.PlatformMessage, error) {
	var msgs []bridge.PlatformMessage
	for _, rm := range response.Messages {
		content := rm.Content
		format := rm.FormatMode
		if format == "" {
			format = "markdown"
		}
		msgs = append(msgs, bridge.PlatformMessage{
			Content:    content,
			FormatMode: format,
			ReplyTo:    response.ReplyTo,
		})
	}
	return msgs, nil
}

// SendMessage sends a message via Telegram Bot API.
func (a *Adapter) SendMessage(chatID int64, text, parseMode, replyTo string) error {
	body := map[string]interface{}{
		"chat_id": chatID,
		"text":    text,
	}
	if parseMode != "" {
		body["parse_mode"] = parseMode
	}
	if replyTo != "" {
		body["reply_to_message_id"] = replyTo
	}
	data, _ := json.Marshal(body)
	url := fmt.Sprintf("https://api.telegram.org/bot%s/sendMessage", a.token)
	resp, err := a.client.Post(url, "application/json", bytes.NewReader(data))
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	return nil
}

// SendChatAction sends a "typing..." indicator via Telegram Bot API.
func (a *Adapter) SendChatAction(chatID int64, action string) error {
	body, _ := json.Marshal(map[string]interface{}{
		"chat_id": chatID,
		"action":  action, // "typing", "upload_photo", etc.
	})
	url := fmt.Sprintf("https://api.telegram.org/bot%s/sendChatAction", a.token)
	resp, err := a.client.Post(url, "application/json", bytes.NewReader(body))
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	return nil
}
