package main

import (
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"mime"
	"mime/multipart"
	"net/mail"
	"os"
	"strings"
	"time"

	"gitea.inhome.blapointe.com/local-sandbox/contact"
	"gitea.inhome.blapointe.com/local/args"
)

type MultipartReaderReader struct {
	buff []byte
	r    *multipart.Reader
}

func (mrr *MultipartReaderReader) Read(b []byte) (int, error) {
	n := copy(b, mrr.buff)
	mrr.buff = mrr.buff[n:]
	for n < len(b) {
		part, err := mrr.r.NextPart()
		if err != nil {
			return n, err
		}
		defer part.Close()

		mrr.buff, err = io.ReadAll(part)
		if err != nil {
			return n, err
		}
		m := copy(b, mrr.buff)
		mrr.buff = mrr.buff[m:]
		n += m
	}
	return n, nil
}

func main() {
	emailer := contact.NewEmailer()
	as := args.NewArgSet()
	as.Append(args.STRING, "imap", "imap server:port", "imap.gmail.com:993")
	as.Append(args.STRING, "pop3", "pop3 server:port", "")
	as.Append(args.INT, "n", "limit (<1 for inf)", 10)
	as.Append(args.STRING, "u", "username", emailer.From)
	as.Append(args.STRING, "p", "password", emailer.Password)
	as.Append(args.INT, "b", "dont read more than this many characters", 4096)
	as.Append(args.BOOL, "json", "output as json", false)
	if err := as.Parse(); err != nil {
		panic(err)
	}

	emailer.IMAP = as.Get("imap").GetString()
	emailer.POP3 = as.Get("pop3").GetString()
	emailer.Limit = as.Get("n").GetInt()
	emailer.From = as.GetString("u")
	emailer.Password = as.GetString("p")

	var msgs <-chan *mail.Message
	var err error
	if emailer.POP3 != "" {
		msgs, err = emailer.ReadPOP3()
	} else {
		msgs, err = emailer.Read()
	}

	if err != nil {
		panic(err)
	}
	emails := make([]map[string]any, 0, emailer.Limit)
	for msg := range msgs {
		var r io.Reader
		if n := int64(as.GetInt("b")); n >= 0 {
			r = io.LimitReader(msg.Body, n)
		} else if mediaType, params, _ := mime.ParseMediaType(msg.Header.Get("Content-Type")); strings.HasPrefix(mediaType, "multipart/") {
			r = &MultipartReaderReader{
				r: multipart.NewReader(msg.Body, params["boundary"]),
			}
		} else {
			r = msg.Body
		}
		b, _ := ioutil.ReadAll(r)
		s := strings.ReplaceAll(string(b), "\r\n", "\n")
		s = strings.ReplaceAll(string(s), "\n", "\n")
		s = strings.ReplaceAll(string(s), "\r", "\n")
		if !strings.Contains(s, " ") {
			s = "..."
		}
		d, _ := msg.Header.Date()
		d = d.In(time.Local)
		if as.GetBool("json") {
			emails = append(emails, map[string]any{
				"t":       d.Format("06-01-02T15:04Z07"),
				"from":    msg.Header.Get("From"),
				"subject": msg.Header.Get("Subject"),
				"body":    s,
			})
		} else {
			fmt.Printf(
				"@%+v @%+v: \n\t%+v: \n\t%s\n",
				d.Format("06-01-02T15:04Z07"),
				msg.Header.Get("From"),
				msg.Header.Get("Subject"),
				s,
			)
		}
	}
	if as.GetBool("json") {
		enc := json.NewEncoder(os.Stdout)
		enc.SetIndent("", "   ")
		enc.Encode(emails)
	}
}
