package webui

import (
	"net/http"
	"net/http/httptest"
	"net/url"
	"strconv"
	"strings"
	"testing"
)

// TestWebmailSignatureCreateEditDeleteAndDefaults exercises the full signature CRUD
// flow plus setting/clearing the default-for-new and default-for-reply flags.
func TestWebmailSignatureCreateEditDeleteAndDefaults(t *testing.T) {
	app := newTestApp(t)
	mux := app.Mux()
	domains, _ := app.DB.ListDomains()
	mailboxID := createTestMailboxWithPassword(t, app, "sigtest@example.com", domains[0].ID, "sigtest-password-1!")
	cookie := webmailLoginSession(t, app, mailboxID)

	save := func(id, name, html string) *httptest.ResponseRecorder {
		form := url.Values{"id": {id}, "name": {name}, "content_html": {html}}
		req := httptest.NewRequest(http.MethodPost, MailboxPrefix+"/signatures/save", strings.NewReader(form.Encode()))
		req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
		req.AddCookie(cookie)
		rec := httptest.NewRecorder()
		mux.ServeHTTP(rec, req)
		return rec
	}

	if rec := save("", "Work", "<p>Jane Doe<br>Acme Inc</p>"); rec.Code != http.StatusFound {
		t.Fatalf("create: status=%d body=%s", rec.Code, rec.Body.String())
	}
	sigs, err := app.DB.ListSignatures(mailboxID)
	if err != nil {
		t.Fatal(err)
	}
	if len(sigs) != 1 || sigs[0].Name != "Work" {
		t.Fatalf("expected 1 signature named Work, got %+v", sigs)
	}
	id := sigs[0].ID

	// Edit it.
	if rec := save(strconv.FormatInt(id, 10), "Work Updated", "<p>Jane Doe, CEO</p>"); rec.Code != http.StatusFound {
		t.Fatalf("edit: status=%d body=%s", rec.Code, rec.Body.String())
	}
	updated, err := app.DB.GetSignatureByID(mailboxID, id)
	if err != nil {
		t.Fatal(err)
	}
	if updated == nil || updated.Name != "Work Updated" || !strings.Contains(updated.ContentHTML, "CEO") {
		t.Fatalf("expected updated signature, got %+v", updated)
	}

	// Set as default for both new and reply.
	for _, which := range []string{"new", "reply"} {
		req := httptest.NewRequest(http.MethodPost, MailboxPrefix+"/signatures/"+strconv.FormatInt(id, 10)+"/default?which="+which, nil)
		req.AddCookie(cookie)
		rec := httptest.NewRecorder()
		mux.ServeHTTP(rec, req)
		if rec.Code != http.StatusFound {
			t.Fatalf("set default %s: status=%d body=%s", which, rec.Code, rec.Body.String())
		}
	}
	got, err := app.DB.GetSignatureByID(mailboxID, id)
	if err != nil {
		t.Fatal(err)
	}
	if !got.IsDefaultNew || !got.IsDefaultReply {
		t.Fatalf("expected both defaults set, got %+v", got)
	}
	def, err := app.DB.GetDefaultSignature(mailboxID, false, "")
	if err != nil || def == nil || def.ID != id {
		t.Fatalf("GetDefaultSignature(new) = %+v, err=%v", def, err)
	}

	// Delete it — defaults should just disappear along with the row.
	delReq := httptest.NewRequest(http.MethodPost, MailboxPrefix+"/signatures/"+strconv.FormatInt(id, 10)+"/delete", nil)
	delReq.AddCookie(cookie)
	delRec := httptest.NewRecorder()
	mux.ServeHTTP(delRec, delReq)
	if delRec.Code != http.StatusFound {
		t.Fatalf("delete: status=%d body=%s", delRec.Code, delRec.Body.String())
	}
	remaining, err := app.DB.ListSignatures(mailboxID)
	if err != nil {
		t.Fatal(err)
	}
	if len(remaining) != 0 {
		t.Fatalf("expected no signatures left, got %+v", remaining)
	}
}

// TestWebmailSignatureSaveSetsAliasDefault confirms the "also set as default for a
// specific alias" fields on the add/edit form (default_for_email/default_new/
// default_reply) actually persist an alias-scoped default via
// SetSignatureAliasDefault, and that GetDefaultSignature picks it up for that alias
// specifically (not the mailbox's own primary address).
func TestWebmailSignatureSaveSetsAliasDefault(t *testing.T) {
	app := newTestApp(t)
	mux := app.Mux()
	domains, _ := app.DB.ListDomains()
	mailboxID := createTestMailboxWithPassword(t, app, "sigalias@example.com", domains[0].ID, "sigalias-password-1!")
	if _, err := app.DB.CreateAlias(mailboxID, "support@example.com", domains[0].ID, true); err != nil {
		t.Fatal(err)
	}
	cookie := webmailLoginSession(t, app, mailboxID)

	form := url.Values{
		"id": {""}, "name": {"Support"}, "content_html": {"<p>Support team</p>"},
		"default_for_email": {"support@example.com"}, "default_new": {"1"}, "default_reply": {"1"},
	}
	req := httptest.NewRequest(http.MethodPost, MailboxPrefix+"/signatures/save", strings.NewReader(form.Encode()))
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	req.AddCookie(cookie)
	rec := httptest.NewRecorder()
	mux.ServeHTTP(rec, req)
	if rec.Code != http.StatusFound {
		t.Fatalf("save: status=%d body=%s", rec.Code, rec.Body.String())
	}

	sigs, err := app.DB.ListSignatures(mailboxID)
	if err != nil || len(sigs) != 1 {
		t.Fatalf("expected 1 signature, got %d (err=%v)", len(sigs), err)
	}
	sigID := sigs[0].ID

	forNew, err := app.DB.GetDefaultSignature(mailboxID, false, "support@example.com")
	if err != nil || forNew == nil || forNew.ID != sigID {
		t.Fatalf("expected support@example.com's new-message default to be the saved signature, got %+v (err=%v)", forNew, err)
	}
	forReply, err := app.DB.GetDefaultSignature(mailboxID, true, "support@example.com")
	if err != nil || forReply == nil || forReply.ID != sigID {
		t.Fatalf("expected support@example.com's reply default to be the saved signature, got %+v (err=%v)", forReply, err)
	}
	// The mailbox's own primary address is untouched — alias defaults are additive,
	// not a replacement for the mailbox-wide default.
	primary, err := app.DB.GetDefaultSignature(mailboxID, false, "sigalias@example.com")
	if err != nil {
		t.Fatal(err)
	}
	if primary != nil {
		t.Fatalf("expected no default for the mailbox's own primary address, got %+v", primary)
	}
}

// TestWebmailSignatureOnlyOneDefaultPerMailbox confirms setting a second signature as
// the default-for-new clears the flag from whichever one had it before.
func TestWebmailSignatureOnlyOneDefaultPerMailbox(t *testing.T) {
	app := newTestApp(t)
	domains, _ := app.DB.ListDomains()
	mailboxID := createTestMailboxWithPassword(t, app, "sigdefault@example.com", domains[0].ID, "sigdefault-password-1!")

	id1, err := app.DB.CreateSignature(mailboxID, "One", "<p>1</p>")
	if err != nil {
		t.Fatal(err)
	}
	id2, err := app.DB.CreateSignature(mailboxID, "Two", "<p>2</p>")
	if err != nil {
		t.Fatal(err)
	}
	if err := app.DB.SetDefaultSignature(mailboxID, id1, false); err != nil {
		t.Fatal(err)
	}
	if err := app.DB.SetDefaultSignature(mailboxID, id2, false); err != nil {
		t.Fatal(err)
	}
	s1, _ := app.DB.GetSignatureByID(mailboxID, id1)
	s2, _ := app.DB.GetSignatureByID(mailboxID, id2)
	if s1.IsDefaultNew {
		t.Error("expected signature 1 to no longer be the default")
	}
	if !s2.IsDefaultNew {
		t.Error("expected signature 2 to now be the default")
	}
}
