package backend

import (
	"bytes"
	"crypto/tls"
	"fmt"
	"log"
	"net/smtp"
	"net/url"
	"strings"

	"github.com/emersion/go-ical"
)

// sendInvitation sends an iMIP (RFC 6047) invitation email.
// It includes a plain-text fallback and a METHOD:REQUEST iCalendar attachment
// that calendar clients (Thunderbird, Apple, etc.) will recognize.
func (b *DBBackend) sendInvitation(senderName, recipientEmail, summary, description, start, end, objectPath, originalICS string) error {
	fromAddr := fmt.Sprintf("%s@%s", senderName, b.emailDomain)
	if b.smtp.User != "" {
		fromAddr = b.smtp.User
	}
	fromHeader := fmt.Sprintf("%s <%s>", senderName, fromAddr)
	
	baseURL := strings.TrimSuffix(b.publicURL, "/")
	acceptURL := fmt.Sprintf("%s/respond?path=%s&attendee=%s&status=ACCEPTED", baseURL, url.QueryEscape(objectPath), url.QueryEscape(recipientEmail))
	declineURL := fmt.Sprintf("%s/respond?path=%s&attendee=%s&status=DECLINED", baseURL, url.QueryEscape(objectPath), url.QueryEscape(recipientEmail))

	// 1. Prepare plain-text fallback - with prominent links
	textPart := "PLEASE RESPOND TO THIS INVITATION:\r\n"
	textPart += fmt.Sprintf("✅ ACCEPT:  %s\r\n", acceptURL)
	textPart += fmt.Sprintf("❌ DECLINE: %s\r\n", declineURL)
	textPart += "\r\n------------------------------------------\r\n\r\n"
	textPart += fmt.Sprintf("You have been invited to an event by %s.\r\n\r\n", senderName)
	textPart += fmt.Sprintf("Event: %s\r\n", summary)

	// 2. Prepare iCalendar part with METHOD:REQUEST
	var icsContent string
	calendar, err := ical.NewDecoder(strings.NewReader(originalICS)).Decode()
	if err == nil {
		calendar.Props.SetText("METHOD", "REQUEST")
		// Discourage clients from sending their own response emails
		for _, event := range calendar.Events() {
			for _, attendee := range event.Props["ATTENDEE"] {
				attendee.Params.Set("RSVP", "FALSE")
			}
		}
		var buf bytes.Buffer
		if err := ical.NewEncoder(&buf).Encode(calendar); err == nil {
			icsContent = buf.String()
		}
	}
	if icsContent == "" {
		icsContent = originalICS // Fallback to raw if decoding failed
	}

	// 3. Construct Multipart MIME Email
	boundary := "nxcaldav_invite_boundary"
	subject := fmt.Sprintf("Invitation: %s", summary)
	
	header := fmt.Sprintf("Subject: %s\r\n", subject)
	header += fmt.Sprintf("From: %s\r\n", fromHeader)
	header += fmt.Sprintf("To: %s\r\n", recipientEmail)
	header += "MIME-Version: 1.0\r\n"
	header += fmt.Sprintf("Content-Type: multipart/mixed; boundary=\"%s\"\r\n", boundary)
	header += "\r\n"

	body := fmt.Sprintf("--%s\r\n", boundary)
	body += "Content-Type: text/plain; charset=UTF-8\r\n"
	body += "Content-Transfer-Encoding: 7bit\r\n"
	body += "\r\n"
	body += textPart + "\r\n"

	body += fmt.Sprintf("--%s\r\n", boundary)
	body += "Content-Type: text/calendar; method=REQUEST; charset=UTF-8\r\n"
	body += "Content-Transfer-Encoding: 7bit\r\n"
	body += "\r\n"
	body += icsContent + "\r\n"
	body += fmt.Sprintf("--%s--\r\n", boundary)

	// 4. Send the mail
	addr := fmt.Sprintf("%s:%d", b.smtp.Host, b.smtp.Port)
	tlsConfig := &tls.Config{InsecureSkipVerify: true, ServerName: b.smtp.Host}
	
	var c *smtp.Client
	if b.smtp.Port == 465 {
		conn, err := tls.Dial("tcp", addr, tlsConfig)
		if err != nil { return err }
		c, err = smtp.NewClient(conn, b.smtp.Host)
	} else {
		c, err = smtp.Dial(addr)
	}
	if err != nil { return err }
	defer c.Close()

	if err = c.Hello("localhost"); err != nil { return err }
	if b.smtp.Port != 465 {
		if ok, _ := c.Extension("STARTTLS"); ok {
			if err = c.StartTLS(tlsConfig); err != nil { return err }
		}
	}
	if b.smtp.User != "" && b.smtp.Password != "" {
		auth := smtp.PlainAuth("", b.smtp.User, b.smtp.Password, b.smtp.Host)
		if err = c.Auth(auth); err != nil { return err }
	}

	if err = c.Mail(fromAddr); err != nil { return err }
	if err = c.Rcpt(recipientEmail); err != nil { return err }

	w, err := c.Data()
	if err != nil { return err }
	_, err = w.Write([]byte(header + body))
	if err != nil { return err }
	err = w.Close()
	if err != nil { return err }

	log.Printf("[email] Successfully sent iMIP invitation to %s", recipientEmail)
	return c.Quit()
}
