package webui

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

// TestWebmailFolderCreateShowsUpEvenWhenEmpty confirms a freshly created folder is
// listed in the sidebar before it holds any messages — the reason
// esrv_mailbox_folders exists at all (DistinctFoldersForMailbox alone can't prove a
// folder exists until something's actually stored in it).
func TestWebmailFolderCreateShowsUpEvenWhenEmpty(t *testing.T) {
	app := newTestApp(t)
	mux := app.Mux()
	domains, _ := app.DB.ListDomains()
	mailboxID := createTestMailboxWithPassword(t, app, "organizer2@example.com", domains[0].ID, "organizer-password-1!")
	cookie := webmailLoginSession(t, app, mailboxID)

	req := httptest.NewRequest(http.MethodPost, MailboxPrefix+"/mail/folders/add", strings.NewReader("name=Receipts"))
	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("add folder: status=%d body=%s", rec.Code, rec.Body.String())
	}

	folders, err := app.DB.ListMailboxFolders(mailboxID)
	if err != nil || len(folders) != 1 || folders[0] != "Receipts" {
		t.Fatalf("expected [Receipts] in ListMailboxFolders, got %v (err=%v)", folders, err)
	}

	inboxReq := httptest.NewRequest(http.MethodGet, MailboxPrefix+"/mail/INBOX", nil)
	inboxReq.AddCookie(cookie)
	inboxRec := httptest.NewRecorder()
	mux.ServeHTTP(inboxRec, inboxReq)
	if !strings.Contains(inboxRec.Body.String(), `data-folder="Receipts"`) {
		t.Error("expected the empty new folder to appear in the sidebar")
	}
}

// TestWebmailFolderCreateRejectsStandardAndDuplicateNames confirms you can't create a
// folder that collides with a standard folder or an existing custom one.
func TestWebmailFolderCreateRejectsStandardAndDuplicateNames(t *testing.T) {
	app := newTestApp(t)
	mux := app.Mux()
	domains, _ := app.DB.ListDomains()
	mailboxID := createTestMailboxWithPassword(t, app, "organizer3@example.com", domains[0].ID, "organizer-password-1!")
	cookie := webmailLoginSession(t, app, mailboxID)

	create := func(name string) {
		t.Helper()
		req := httptest.NewRequest(http.MethodPost, MailboxPrefix+"/mail/folders/add", strings.NewReader("name="+name))
		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("create %s: status=%d", name, rec.Code)
		}
	}

	create("Sent") // standard folder name — should be rejected, not duplicated
	create("Work")
	create("Work") // duplicate — should be rejected, not duplicated

	folders, err := app.DB.ListMailboxFolders(mailboxID)
	if err != nil {
		t.Fatal(err)
	}
	if len(folders) != 1 || folders[0] != "Work" {
		t.Fatalf("expected exactly [Work] (Sent rejected as standard, duplicate Work rejected), got %v", folders)
	}
}

// TestWebmailFolderDeleteMovesToTrashAndCannotDeleteStandard confirms deleting a
// custom folder re-parents it (and its messages, untouched under the same flat name)
// under Trash rather than relocating messages to INBOX — the folder itself becomes a
// subfolder of Trash, not gone — and that a standard folder can't be deleted via the
// same route even if requested directly.
func TestWebmailFolderDeleteMovesToTrashAndCannotDeleteStandard(t *testing.T) {
	app := newTestApp(t)
	mux := app.Mux()
	domains, _ := app.DB.ListDomains()
	mailboxID := createTestMailboxWithPassword(t, app, "organizer4@example.com", domains[0].ID, "organizer-password-1!")
	cookie := webmailLoginSession(t, app, mailboxID)

	if err := app.DB.CreateMailboxFolder(mailboxID, "Newsletters"); err != nil {
		t.Fatal(err)
	}
	raw := "From: a@example.com\r\nTo: organizer4@example.com\r\nSubject: hi\r\n\r\nbody"
	if _, err := app.Mailstore.StoreMessage(mailboxID, "Newsletters", []byte(raw), "m@example.com", "a@example.com", "hi"); err != nil {
		t.Fatal(err)
	}

	req := httptest.NewRequest(http.MethodPost, MailboxPrefix+"/mail/folders/Newsletters/remove", nil)
	req.AddCookie(cookie)
	rec := httptest.NewRecorder()
	mux.ServeHTTP(rec, req)
	if rec.Code != http.StatusFound {
		t.Fatalf("delete folder: status=%d", rec.Code)
	}

	root, err := app.DB.FolderRoot(mailboxID, "Newsletters")
	if err != nil || root != "Trash" {
		t.Fatalf("expected Newsletters to now resolve under Trash, got root=%q (err=%v)", root, err)
	}
	// The message stays tagged with its own flat folder name, not moved to "Trash" —
	// that's what makes it show up nested under Trash instead of dumped at its root.
	msgs, err := app.DB.ListMessagesInFolder(mailboxID, "Newsletters")
	if err != nil || len(msgs) != 1 {
		t.Fatalf("expected the message to stay in Newsletters, got %d (err=%v)", len(msgs), err)
	}
	inboxMsgs, err := app.DB.ListMessagesInFolder(mailboxID, "INBOX")
	if err != nil || len(inboxMsgs) != 0 {
		t.Fatalf("expected nothing relocated to INBOX, got %d (err=%v)", len(inboxMsgs), err)
	}

	// Attempting to delete a standard folder must be rejected, not silently succeed.
	stdReq := httptest.NewRequest(http.MethodPost, MailboxPrefix+"/mail/folders/Sent/remove", nil)
	stdReq.AddCookie(cookie)
	stdRec := httptest.NewRecorder()
	mux.ServeHTTP(stdRec, stdReq)
	if stdRec.Code != http.StatusFound {
		t.Fatalf("delete standard folder: status=%d", stdRec.Code)
	}
	sentReq := httptest.NewRequest(http.MethodGet, MailboxPrefix+"/mail/Sent", nil)
	sentReq.AddCookie(cookie)
	sentRec := httptest.NewRecorder()
	mux.ServeHTTP(sentRec, sentReq)
	if sentRec.Code != http.StatusOK {
		t.Fatalf("Sent folder should still exist and render normally, status=%d", sentRec.Code)
	}
}
