package main

import (
	"context"
	"net/http"
	"strings"
	"sync"
	"time"

	"github.com/tidbcloud/AgentTeam/internal/mailer"
)

type e2eMailbox struct {
	mu      sync.Mutex
	entries map[string]e2eMailboxEntry
}

type e2eMailboxEntry struct {
	Kind             string    `json:"kind"`
	Email            string    `json:"email"`
	Token            string    `json:"token"`
	WorkspaceName    string    `json:"workspaceName,omitempty"`
	OrganizationName string    `json:"organizationName,omitempty"`
	SentAt           time.Time `json:"sentAt"`
}

func newE2EMailbox() *e2eMailbox {
	return &e2eMailbox{
		entries: make(map[string]e2eMailboxEntry),
	}
}

func e2eMailboxKey(kind string, email string) string {
	return kind + "\n" + strings.ToLower(strings.TrimSpace(email))
}

func (mailbox *e2eMailbox) record(kind string, email string, token string, workspaceName string, organizationName string) {
	mailbox.mu.Lock()
	defer mailbox.mu.Unlock()
	mailbox.entries[e2eMailboxKey(kind, email)] = e2eMailboxEntry{
		Kind:             kind,
		Email:            strings.ToLower(strings.TrimSpace(email)),
		Token:            token,
		WorkspaceName:    strings.TrimSpace(workspaceName),
		OrganizationName: strings.TrimSpace(organizationName),
		SentAt:           time.Now(),
	}
}

func (mailbox *e2eMailbox) latest(kind string, email string) (e2eMailboxEntry, bool) {
	mailbox.mu.Lock()
	defer mailbox.mu.Unlock()
	entry, ok := mailbox.entries[e2eMailboxKey(kind, email)]
	return entry, ok
}

type e2eMailboxMailer struct {
	next    mailer.Mailer
	mailbox *e2eMailbox
}

func newE2EMailboxMailer(next mailer.Mailer, mailbox *e2eMailbox) mailer.Mailer {
	return &e2eMailboxMailer{next: next, mailbox: mailbox}
}

func (mailer *e2eMailboxMailer) SendVerificationEmail(ctx context.Context, email string, token string) error {
	if err := mailer.next.SendVerificationEmail(ctx, email, token); err != nil {
		return err
	}
	mailer.mailbox.record("verify", email, token, "", "")
	return nil
}

func (mailer *e2eMailboxMailer) SendPasswordResetEmail(ctx context.Context, email string, token string) error {
	if err := mailer.next.SendPasswordResetEmail(ctx, email, token); err != nil {
		return err
	}
	mailer.mailbox.record("reset", email, token, "", "")
	return nil
}

func (mailer *e2eMailboxMailer) SendWorkspaceInviteEmail(ctx context.Context, email string, workspaceName string, token string) error {
	if err := mailer.next.SendWorkspaceInviteEmail(ctx, email, workspaceName, token); err != nil {
		return err
	}
	mailer.mailbox.record("invite", email, token, workspaceName, "")
	return nil
}

func (mailer *e2eMailboxMailer) SendOrganizationInviteEmail(ctx context.Context, email string, organizationName string, token string) error {
	if err := mailer.next.SendOrganizationInviteEmail(ctx, email, organizationName, token); err != nil {
		return err
	}
	mailer.mailbox.record("org-invite", email, token, "", organizationName)
	return nil
}

func e2eMailboxLatestHandler(mailbox *e2eMailbox) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		if r.Method != http.MethodGet {
			w.WriteHeader(http.StatusMethodNotAllowed)
			return
		}

		kind := strings.TrimSpace(r.URL.Query().Get("kind"))
		email := strings.TrimSpace(r.URL.Query().Get("email"))
		if kind == "" || email == "" {
			writeE2EJSON(w, http.StatusBadRequest, e2eErrorResponse{Error: "kind and email are required"})
			return
		}
		if kind != "verify" && kind != "reset" && kind != "invite" && kind != "org-invite" {
			writeE2EJSON(w, http.StatusBadRequest, e2eErrorResponse{Error: "unsupported kind"})
			return
		}

		entry, ok := mailbox.latest(kind, email)
		if !ok {
			writeE2EJSON(w, http.StatusNotFound, e2eErrorResponse{Error: "not found"})
			return
		}
		writeE2EJSON(w, http.StatusOK, entry)
	}
}
