package utils

import (
	"bytes"
	"crypto/rand"
	"encoding/base64"
	"io"
	"mime"
	"mime/quotedprintable"
	"net/mail"
	"strings"
)

type Email struct {
	MimeVersion string
	Date        string
	From        string
	To          string
	Subject     string
	ContentType string
	Body        string
}

func GenerateRandomString(length int) (string, error) {
	bytes := make([]byte, length)
	_, err := rand.Read(bytes)
	if err != nil {
		return "", err
	}
	return base64.URLEncoding.EncodeToString(bytes), nil
}

func GenerateVerificationToken() (string, error) {
	return GenerateRandomString(32)
}

func DecodeMail(message string) (*Email, error) {
	msg, err := mail.ReadMessage(strings.NewReader(message))
	if err != nil {
		return nil, err
	}
	decodedBody, err := io.ReadAll(msg.Body)
	if err != nil {
		return nil, err
	}
	decodedBodyString, err := DecodeQuotedPrintable(string(decodedBody))
	if err != nil {
		return nil, err
	}
	decodedSubject, err := DecodeRFC2047(msg.Header.Get("Subject"))
	if err != nil {
		return nil, err
	}

	email := &Email{}

	// Populate the headers
	email.MimeVersion = msg.Header.Get("Mime-Version")
	email.Date = msg.Header.Get("Date")
	email.From = msg.Header.Get("From")
	email.To = msg.Header.Get("To")
	email.Subject = decodedSubject
	email.Body = decodedBodyString
	email.ContentType = msg.Header.Get("Content-Type")

	return email, nil
}

func DecodeRFC2047(encoded string) (string, error) {
	decoder := new(mime.WordDecoder)
	decoded, err := decoder.DecodeHeader(encoded)
	if err != nil {
		return "", err
	}
	return decoded, nil
}

func DecodeQuotedPrintable(encodedString string) (string, error) {
	// Decode quoted-printable encoding
	reader := quotedprintable.NewReader(strings.NewReader(encodedString))
	decodedBytes := new(bytes.Buffer)
	_, err := decodedBytes.ReadFrom(reader)
	if err != nil {
		return "", err
	}
	return decodedBytes.String(), nil
}

func EncodeQuotedPrintable(s string) string {
	var buf bytes.Buffer

	// Use Quoted-Printable encoder
	qp := quotedprintable.NewWriter(&buf)

	// Write the UTF-8 encoded string to the Quoted-Printable encoder
	qp.Write([]byte(s))
	qp.Close()

	// Encode the result into a MIME header
	return mime.QEncoding.Encode("UTF-8", buf.String())
}
