package email

import (
	"io"
	"log"
	"os"
	"strings"
	"sync"
	"time"

	"github.com/bwmarrin/discordgo"
	"github.com/dustinpianalto/goff/pkg/puzzles"
	imap "github.com/emersion/go-imap"
	"github.com/emersion/go-imap/client"
	"github.com/emersion/go-message/mail"
)

const ()

var (
	emailUsername = os.Getenv("GOFF_EMAIL_USERNAME")
	emailPassword = os.Getenv("GOFF_EMAIL_PASSWORD")
	puzzleAddress = mail.Address{
		Name:    "Daily Coding Problem",
		Address: "founders@dailycodingproblem.com",
	}
)

var EmailClient client.Client

func RecieveEmail(dg *discordgo.Session) {
	for {
		log.Println("Connecting to Email server.")

		EmailClient, err := client.DialTLS("mail.djpianalto.com:993", nil)
		if err != nil {
			log.Println(err)
			return
		}
		if err = EmailClient.Login(emailUsername, emailPassword); err != nil {
			log.Println(err)
			return
		}
		log.Println("Connected to Email server.")

		mbox, err := EmailClient.Select("INBOX", false)
		if err != nil {
			log.Println(err)
			return
		}

		if mbox.Messages == 0 {
			log.Println("No Messages in Mailbox")
		}

		criteria := imap.NewSearchCriteria()
		criteria.WithoutFlags = []string{"\\Seen"}
		uids, err := EmailClient.Search(criteria)
		if err != nil {
			log.Println(err)
		}
		if len(uids) > 0 {
			seqset := new(imap.SeqSet)
			seqset.AddNum(uids...)
			section := &imap.BodySectionName{}
			items := []imap.FetchItem{section.FetchItem()}
			messages := make(chan *imap.Message, 10)
			go func() {
				if err = EmailClient.Fetch(seqset, items, messages); err != nil {
					log.Println(err)
					return
				}
			}()

			var wg sync.WaitGroup

			for msg := range messages {
				if msg == nil {
					log.Println("No New Messages")
					continue
				}
				r := msg.GetBody(section)
				if r == nil {
					log.Println("Server didn't send a message body")
					continue
				}
				wg.Add(1)
				go processEmail(r, dg, &wg)
			}
			wg.Wait()
		}

		EmailClient.Logout()
		time.Sleep(300 * time.Second)
	}
}

func processEmail(r io.Reader, dg *discordgo.Session, wg *sync.WaitGroup) {
	defer wg.Done()
	mr, err := mail.CreateReader(r)
	if err != nil {
		log.Println(err)
		return
	}
	header := mr.Header
	from, err := header.AddressList("From")
	if err != nil {
		log.Println(err)
		return
	}
	subject, err := header.Subject()
	if err != nil {
		log.Println(err)
		return
	}
	log.Println(from)
	log.Println(subject)
	if addressIn(from, puzzleAddress) &&
		strings.Contains(subject, "Daily Coding Problem:") {
		log.Println("Processing Puzzle")
		puzzles.ProcessPuzzleEmail(mr, dg)
	}

}

func addressIn(s []*mail.Address, a mail.Address) bool {
	for _, item := range s {
		if item.String() == a.String() {
			return true
		}
	}
	return false
}
