package mailer

import (
	"bytes"
	"context"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"strconv"
	"strings"
	"time"

	"golang.org/x/oauth2/clientcredentials"
)

type GraphMailer struct {
	httpClient *http.Client
	from       string // noreply@baggi.com.tr
	replyTo    string // opsiyonel
}

func NewGraphMailer() (*GraphMailer, error) {
	tenantID := strings.TrimSpace(os.Getenv("AZURE_TENANT_ID"))
	clientID := strings.TrimSpace(os.Getenv("AZURE_CLIENT_ID"))
	clientSecret := strings.TrimSpace(os.Getenv("AZURE_CLIENT_SECRET"))
	from := strings.TrimSpace(os.Getenv("MAIL_FROM"))
	replyTo := strings.TrimSpace(os.Getenv("MAIL_REPLY_TO")) // opsiyonel

	if tenantID == "" || clientID == "" || clientSecret == "" || from == "" {
		return nil, fmt.Errorf("azure graph mailer env missing (AZURE_TENANT_ID/AZURE_CLIENT_ID/AZURE_CLIENT_SECRET/MAIL_FROM)")
	}

	conf := clientcredentials.Config{
		ClientID:     clientID,
		ClientSecret: clientSecret,
		TokenURL:     fmt.Sprintf("https://login.microsoftonline.com/%s/oauth2/v2.0/token", tenantID),
		Scopes:       []string{"https://graph.microsoft.com/.default"},
	}

	httpClient := conf.Client(context.Background())
	httpClient.Timeout = 25 * time.Second

	log.Printf("✉️ Graph Mailer hazır (App-only token) | from=%s", from)

	return &GraphMailer{
		httpClient: httpClient,
		from:       from,
		replyTo:    replyTo,
	}, nil
}

func (g *GraphMailer) Send(ctx context.Context, msg Message) error {
	start := time.Now()

	// ---------- validate ----------
	cleanTo := make([]string, 0, len(msg.To))
	for _, t := range msg.To {
		t = strings.TrimSpace(t)
		if t != "" {
			cleanTo = append(cleanTo, t)
		}
	}
	if len(cleanTo) == 0 {
		return fmt.Errorf("recipient missing")
	}
	subject := strings.TrimSpace(msg.Subject)
	if subject == "" {
		return fmt.Errorf("subject missing")
	}

	// internal-safe adjustments
	isInternal := allRecipientsInDomain(cleanTo, "baggi.com.tr")
	if isInternal && !strings.HasPrefix(subject, "[BSSApp]") {
		subject = "[BSSApp] " + subject
	}

	html := strings.TrimSpace(msg.BodyHTML)
	text := strings.TrimSpace(msg.Body)

	// Eğer sadece HTML geldiyse text üret (spam skorunu düşürür)
	if text == "" && html != "" {
		text = stripHTMLVerySimple(html)
	}
	// Eğer sadece text geldiyse basit HTML üret
	if html == "" && text != "" {
		html = "<pre style=\"font-family:Segoe UI, Arial, sans-serif; white-space:pre-wrap;\">" +
			htmlEscape(text) + "</pre>"
	}
	if html == "" {
		return fmt.Errorf("body missing (Body or BodyHTML)")
	}

	log.Printf("✉️ [MAIL] SEND START | from=%s | to=%v | internal=%v | subject=%s", g.from, cleanTo, isInternal, subject)

	// ---------- build recipients ----------
	type recipient struct {
		EmailAddress struct {
			Address string `json:"address"`
		} `json:"emailAddress"`
	}
	toRecipients := make([]recipient, 0, len(cleanTo))
	for _, m := range cleanTo {
		r := recipient{}
		r.EmailAddress.Address = m
		toRecipients = append(toRecipients, r)
	}

	// ---------- headers to reduce auto-phish/spam signals ----------
	headers := []map[string]string{
		{
			"name":  "X-Mailer",
			"value": "BSSApp Graph Mailer",
		},
		{
			"name":  "X-BSSApp-Internal",
			"value": strconv.FormatBool(isInternal),
		},
	}

	// replyTo (opsiyonel)
	var replyToRecipients []recipient
	if strings.TrimSpace(g.replyTo) != "" {
		rt := recipient{}
		rt.EmailAddress.Address = strings.TrimSpace(g.replyTo)
		replyToRecipients = []recipient{rt}
	}

	// ---------- Graph payload ----------
	message := map[string]any{
		"subject": subject,
		"body": map[string]string{
			"contentType": "HTML",
			"content":     buildHTML(html, text, isInternal),
		},
		"toRecipients":           toRecipients,
		"internetMessageHeaders": headers,
		"importance":             "normal",
	}

	// replyTo SADECE doluysa ekle
	if len(replyToRecipients) > 0 {
		message["replyTo"] = replyToRecipients
	}

	if len(msg.Attachments) > 0 {
		atts := make([]map[string]any, 0, len(msg.Attachments))
		for _, a := range msg.Attachments {
			if len(a.Data) == 0 {
				continue
			}

			name := strings.TrimSpace(a.FileName)
			if name == "" {
				name = "attachment.bin"
			}

			contentType := strings.TrimSpace(a.ContentType)
			if contentType == "" {
				contentType = "application/octet-stream"
			}

			atts = append(atts, map[string]any{
				"@odata.type":  "#microsoft.graph.fileAttachment",
				"name":         name,
				"contentType":  contentType,
				"contentBytes": base64.StdEncoding.EncodeToString(a.Data),
			})
		}

		if len(atts) > 0 {
			message["attachments"] = atts
		}
	}

	payload := map[string]any{
		"message":         message,
		"saveToSentItems": true,
	}

	b, err := json.Marshal(payload)
	if err != nil {
		return fmt.Errorf("json marshal: %w", err)
	}

	url := fmt.Sprintf(
		"https://graph.microsoft.com/v1.0/users/%s/sendMail",
		g.from,
	)

	req, err := http.NewRequestWithContext(
		ctx,
		http.MethodPost,
		url,
		bytes.NewBuffer(b),
	)
	if err != nil {
		return fmt.Errorf("new request: %w", err)
	}
	req.Header.Set("Content-Type", "application/json")

	res, err := g.httpClient.Do(req)
	if err != nil {
		return fmt.Errorf("graph request: %w", err)
	}
	defer res.Body.Close()

	if res.StatusCode >= 300 {
		bodyBytes, _ := io.ReadAll(res.Body)
		log.Printf(
			"❌ [MAIL] SEND FAILED | status=%s | body=%s",
			res.Status,
			string(bodyBytes),
		)
		return fmt.Errorf("graph send mail failed: %s", res.Status)
	}

	log.Printf(
		"✅ [MAIL] SEND OK | to=%v | duration=%s",
		cleanTo,
		time.Since(start),
	)

	return nil
}

// ---------- helpers ----------

func allRecipientsInDomain(to []string, domain string) bool {
	domain = strings.ToLower(strings.TrimSpace(domain))
	for _, addr := range to {
		addr = strings.ToLower(strings.TrimSpace(addr))
		if !strings.HasSuffix(addr, "@"+domain) {
			return false
		}
	}
	return true
}

func buildHTML(htmlBody, textBody string, internal bool) string {
	// Internal ise daha sade, daha az “marketing-like”
	if internal {
		return `
<div style="font-family:Segoe UI, Arial, sans-serif; font-size:14px; color:#1f1f1f;">
  ` + htmlBody + `
  <hr style="border:none;border-top:1px solid #e5e5e5;margin:16px 0;" />
  <div style="font-size:12px;color:#666;">
    Bu e-posta BSSApp sistemi tarafından otomatik oluşturulmuştur.
  </div>
</div>`
	}

	// External
	return `
<div style="font-family:Segoe UI, Arial, sans-serif; font-size:14px; color:#1f1f1f;">
  ` + htmlBody + `
</div>`
}

// Çok basit “html -> text” (tam değil ama yeterli)
func stripHTMLVerySimple(s string) string {
	s = strings.ReplaceAll(s, "<br>", "\n")
	s = strings.ReplaceAll(s, "<br/>", "\n")
	s = strings.ReplaceAll(s, "<br />", "\n")
	s = strings.ReplaceAll(s, "</p>", "\n\n")
	// kaba temizlik
	for {
		i := strings.Index(s, "<")
		j := strings.Index(s, ">")
		if i >= 0 && j > i {
			s = s[:i] + s[j+1:]
			continue
		}
		break
	}
	return strings.TrimSpace(s)
}

func htmlEscape(s string) string {
	replacer := strings.NewReplacer(
		"&", "&amp;",
		"<", "&lt;",
		">", "&gt;",
		"\"", "&quot;",
		"'", "&#39;",
	)
	return replacer.Replace(s)
}
func (g *GraphMailer) SendMail(to string, subject string, html string) error {
	msg := Message{
		To:       []string{to},
		Subject:  subject,
		BodyHTML: html,
	}

	// context burada internal olarak veriliyor
	return g.Send(context.Background(), msg)
}
