package senders

import (
	"bytes"
	_ "embed"
	"encoding/json"
	"fmt"
	"golang.org/x/net/html"
	"html/template"
	"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/model"
	"strings"
)

type LeadSender interface {
	SendLead(leadData LeadData) error
	Name() string
}

type LeadData struct {
	To           interface{}
	Subject      string
	Template     string
	TemplateData TemplateData
}

type TemplateData struct {
	QuizConfig    model.ResultInfo
	AnswerContent model.ResultContent
	AllAnswers    []model.ResultAnswer
	QuestionsMap  map[uint64]string
	AnswerTime    string
}

func generateTextFromTemplate(data TemplateData, tpl string) (string, error) {
	t, err := template.New("email").Funcs(tmplFuncs).Parse(tpl)
	if err != nil {
		return "", fmt.Errorf("error parsing template: %w", err)
	}

	var text bytes.Buffer
	if err := t.Execute(&text, TemplateData{
		QuizConfig:    data.QuizConfig,
		AnswerContent: data.AnswerContent,
		AllAnswers:    data.AllAnswers,
		QuestionsMap:  data.QuestionsMap,
		AnswerTime:    data.AnswerTime,
	}); err != nil {
		return "", fmt.Errorf("error executing template: %w", err)
	}

	return text.String(), nil
}

var tmplFuncs = template.FuncMap{
	"renderImage": RenderImage,
}

func RenderImage(content string) template.HTML {
	var res model.ImageContent
	err := json.Unmarshal([]byte(content), &res)
	if err != nil {
		return SplitContent(content)
	}
	tpl := template.HTML(fmt.Sprintf("<td>%s<br><img class=\"image\" style=\"width:100%%; max-width:250px; max-height:250px\" src=\"%s\"/></td>", res.Description, res.Image))
	return tpl
}

func SplitContent(content string) template.HTML {
	parts := strings.Split(content, "|")
	if len(parts) == 2 {
		url := strings.TrimSpace(parts[0])
		filename := strings.TrimSpace(parts[1])
		return template.HTML(fmt.Sprintf(`<a href="%s" download>%s</a>`, url, filename))
	}
	return template.HTML(content)
}

func sanitizeHTMLData(data TemplateData) TemplateData {
	sanitized := TemplateData{
		QuizConfig:    stripHTMLResultInfo(data.QuizConfig),
		AnswerContent: stripHTMLResultContent(data.AnswerContent),
		AllAnswers:    stripHTMLResultAnswers(data.AllAnswers),
		QuestionsMap:  stripHTMLResultMap(data.QuestionsMap),
		AnswerTime:    StripHTML(data.AnswerTime),
	}
	return sanitized
}

func stripHTMLResultInfo(input model.ResultInfo) model.ResultInfo {
	return model.ResultInfo{
		When:     StripHTML(input.When),
		Theme:    StripHTML(input.Theme),
		Reply:    StripHTML(input.Reply),
		ReplName: StripHTML(input.ReplName),
	}
}

func stripHTMLResultContent(input model.ResultContent) model.ResultContent {
	return model.ResultContent{
		Text:      StripHTML(input.Text),
		Name:      StripHTML(input.Name),
		Email:     StripHTML(input.Email),
		Phone:     StripHTML(input.Phone),
		Address:   StripHTML(input.Address),
		Telegram:  StripHTML(input.Telegram),
		Wechat:    StripHTML(input.Wechat),
		Viber:     StripHTML(input.Viber),
		Vk:        StripHTML(input.Vk),
		Skype:     StripHTML(input.Skype),
		Whatsup:   StripHTML(input.Whatsup),
		Messenger: StripHTML(input.Messenger),
		Custom:    stripHTMLCustom(input.Custom),
	}
}

func stripHTMLResultAnswers(answers []model.ResultAnswer) []model.ResultAnswer {
	sanitized := make([]model.ResultAnswer, len(answers))
	for i, j := range answers {
		sanitized[i] = model.ResultAnswer{
			Content:    StripHTML(j.Content),
			CreatedAt:  j.CreatedAt,
			QuestionID: j.QuestionID,
			AnswerID:   j.AnswerID,
		}
	}
	return sanitized
}

func stripHTMLResultMap(questionsMap map[uint64]string) map[uint64]string {
	sanitized := make(map[uint64]string)
	for i, j := range questionsMap {
		sanitized[i] = StripHTML(j)
	}
	return sanitized
}

func stripHTMLCustom(custom map[string]string) map[string]string {
	sanitized := make(map[string]string)
	for i, j := range custom {
		sanitized[i] = StripHTML(j)
	}
	return sanitized
}

func StripHTML(htmlString string) string {
	tokenizer := html.NewTokenizer(bytes.NewBufferString(htmlString))
	var result bytes.Buffer
	for {
		tokenType := tokenizer.Next()
		switch tokenType {
		case html.ErrorToken:
			return strings.TrimSpace(result.String())
		case html.TextToken:
			result.WriteString(tokenizer.Token().Data)
			result.WriteString("\n")
		case html.StartTagToken, html.EndTagToken:
			tagName, _ := tokenizer.TagName()
			if string(tagName) == "a" {
				_, attrVal, _ := tokenizer.TagAttr()
				result.WriteString(string(attrVal))
				result.WriteString("\n")
			}
		}
	}
}
