// mautrix-telegram - A Matrix-Telegram puppeting bridge.
// Copyright (C) 2024 Sumner Evans
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.

package matrixfmt

import (
	"context"
	"fmt"

	"maunium.net/go/mautrix/bridgev2"
	"maunium.net/go/mautrix/event"

	"go.mau.fi/mautrix-telegram/pkg/connector/ids"
	"go.mau.fi/mautrix-telegram/pkg/connector/telegramfmt"
	"go.mau.fi/mautrix-telegram/pkg/gotd/tg"
)

func toTelegramEntity(br telegramfmt.BodyRange) tg.MessageEntityClass {
	switch val := br.Value.(type) {
	case telegramfmt.Mention:
		if val.Username != "" {
			return &tg.MessageEntityMention{Offset: br.Start, Length: br.Length}
		} else {
			peerType, userID, _ := ids.ParseUserID(val.UserID)
			if peerType != ids.PeerTypeUser {
				panic(fmt.Errorf("unexpected peer type in mention %T", peerType))
			}
			return &tg.InputMessageEntityMentionName{
				Offset: br.Start,
				Length: br.Length,
				UserID: &tg.InputUser{UserID: userID, AccessHash: val.AccessHash},
			}
		}
	case telegramfmt.Style:
		switch val.Type {
		case telegramfmt.StyleBold:
			return &tg.MessageEntityBold{Offset: br.Start, Length: br.Length}
		case telegramfmt.StyleItalic:
			return &tg.MessageEntityItalic{Offset: br.Start, Length: br.Length}
		case telegramfmt.StyleUnderline:
			return &tg.MessageEntityUnderline{Offset: br.Start, Length: br.Length}
		case telegramfmt.StyleStrikethrough:
			return &tg.MessageEntityStrike{Offset: br.Start, Length: br.Length}
		case telegramfmt.StyleBlockquote:
			return &tg.MessageEntityBlockquote{Offset: br.Start, Length: br.Length}
		case telegramfmt.StyleCode:
			return &tg.MessageEntityCode{Offset: br.Start, Length: br.Length}
		case telegramfmt.StylePre:
			return &tg.MessageEntityPre{Offset: br.Start, Length: br.Length, Language: val.Language}
		case telegramfmt.StyleEmail:
			return &tg.MessageEntityEmail{Offset: br.Start, Length: br.Length}
		case telegramfmt.StyleTextURL:
			return &tg.MessageEntityTextURL{Offset: br.Start, Length: br.Length, URL: val.URL}
		case telegramfmt.StyleURL:
			return &tg.MessageEntityURL{Offset: br.Start, Length: br.Length}
		case telegramfmt.StyleBotCommand:
			return &tg.MessageEntityBotCommand{Offset: br.Start, Length: br.Length}
		case telegramfmt.StyleHashtag:
			return &tg.MessageEntityHashtag{Offset: br.Start, Length: br.Length}
		case telegramfmt.StyleCashtag:
			return &tg.MessageEntityCashtag{Offset: br.Start, Length: br.Length}
		case telegramfmt.StylePhone:
			return &tg.MessageEntityPhone{Offset: br.Start, Length: br.Length}
		case telegramfmt.StyleSpoiler:
			return &tg.MessageEntitySpoiler{Offset: br.Start, Length: br.Length}
		case telegramfmt.StyleBankCard:
			return &tg.MessageEntityBankCard{Offset: br.Start, Length: br.Length}
		case telegramfmt.StyleCustomEmoji:
			return &tg.MessageEntityCustomEmoji{Offset: br.Start, Length: br.Length, DocumentID: val.EmojiInfo.DocumentID}
		default:
			panic("unsupported style type")
		}
	default:
		panic("unknown body range value")
	}
}

func Parse(ctx context.Context, parser *HTMLParser, content *event.MessageEventContent, portal *bridgev2.Portal) (string, []tg.MessageEntityClass) {
	if content.MsgType.IsMedia() && (content.FileName == "" || content.FileName == content.Body) {
		// The body is the filename.
		return "", nil
	}

	if content.Format != event.FormatHTML {
		return content.Body, nil
	}
	parseCtx := NewContext(ctx, portal)
	parseCtx.AllowedMentions = content.Mentions
	parsed := parser.Parse(content.FormattedBody, parseCtx)
	if parsed == nil {
		return "", nil
	}
	var entities []tg.MessageEntityClass
	if len(parsed.Entities) > 0 {
		entities = make([]tg.MessageEntityClass, len(parsed.Entities))
		for i, ent := range parsed.Entities {
			entities[i] = toTelegramEntity(ent)
		}
	}
	return parsed.String.String(), entities
}
