package customerprofile

import (
	"bytes"
	"encoding/json"
	"errors"
	"net/http"
	"net/http/httptest"
	"strings"
	"testing"

	"system-altrak/internal/domain"

	"github.com/gofiber/fiber/v2"
)

type customerProfileServiceMock struct {
	saveDraftErr  error
	saveLockedErr error
	getErr        error
	listErr       error
	deleteErr     error
	exportHTMLErr error

	getData   *domain.CustomerProfile
	listData  []domain.CustomerProfile
	listTotal int64

	saveDraftCalls  int
	saveLockedCalls int
	getCalls        int
	listCalls       int
	deleteCalls     int
	exportHTMLCalls int

	lastDraftProfile  *domain.CustomerProfile
	lastLockedProfile *domain.CustomerProfile

	lastDraftBranch uint
	lastDraftRole   string

	lastLockedBranch uint
	lastLockedRole   string

	lastGetID     uint
	lastGetBranch uint
	lastGetRole   string

	lastListPage   int
	lastListLimit  int
	lastListSearch string
	lastListTab    string
	lastListBranch uint
	lastListRole   string

	lastDeleteID     uint
	lastDeleteBranch uint
	lastDeleteRole   string

	lastExportHTML          string
	lastExportExcelProfiles []domain.CustomerProfile
	lastExportPDFProfiles   []domain.CustomerProfile
}

func cloneCustomerProfile(p *domain.CustomerProfile) *domain.CustomerProfile {
	if p == nil {
		return nil
	}
	copy := *p
	return &copy
}

func filterCustomerProfilesByTabForMock(profiles []domain.CustomerProfile, tab string) []domain.CustomerProfile {
	filtered := make([]domain.CustomerProfile, 0, len(profiles))
	switch strings.ToLower(strings.TrimSpace(tab)) {
	case "wapu":
		for _, profile := range profiles {
			if profile.WapuStatus {
				filtered = append(filtered, profile)
			}
		}
	case "non_wapu":
		for _, profile := range profiles {
			if !profile.WapuStatus {
				filtered = append(filtered, profile)
			}
		}
	default:
		filtered = append(filtered, profiles...)
	}
	return filtered
}

func (m *customerProfileServiceMock) SaveDraft(profile *domain.CustomerProfile, branchID uint, role string) error {
	m.saveDraftCalls++
	m.lastDraftProfile = cloneCustomerProfile(profile)
	m.lastDraftBranch = branchID
	m.lastDraftRole = role
	if m.saveDraftErr != nil {
		return m.saveDraftErr
	}
	return nil
}

func (m *customerProfileServiceMock) SaveLocked(profile *domain.CustomerProfile, branchID uint, role string) error {
	m.saveLockedCalls++
	m.lastLockedProfile = cloneCustomerProfile(profile)
	m.lastLockedBranch = branchID
	m.lastLockedRole = role
	if m.saveLockedErr != nil {
		return m.saveLockedErr
	}
	return nil
}

func (m *customerProfileServiceMock) GetProfile(id uint, branchID uint, role string) (*domain.CustomerProfile, error) {
	m.getCalls++
	m.lastGetID = id
	m.lastGetBranch = branchID
	m.lastGetRole = role
	if m.getErr != nil {
		return nil, m.getErr
	}
	if m.getData != nil {
		return m.getData, nil
	}
	return &domain.CustomerProfile{}, nil
}

func (m *customerProfileServiceMock) ListProfiles(page, limit int, search, tab string, branchID uint, role string) ([]domain.CustomerProfile, int64, error) {
	m.listCalls++
	m.lastListPage = page
	m.lastListLimit = limit
	m.lastListSearch = search
	m.lastListTab = tab
	m.lastListBranch = branchID
	m.lastListRole = role
	if m.listErr != nil {
		return nil, 0, m.listErr
	}
	filtered := filterCustomerProfilesByTabForMock(m.listData, tab)
	return filtered, int64(len(filtered)), nil
}

func (m *customerProfileServiceMock) DeleteProfile(id uint, branchID uint, role string, userID uint, username string) error {
	m.deleteCalls++
	m.lastDeleteID = id
	m.lastDeleteBranch = branchID
	m.lastDeleteRole = role
	if m.deleteErr != nil {
		return m.deleteErr
	}
	return nil
}

func (m *customerProfileServiceMock) ExportToExcel(profiles []domain.CustomerProfile) ([]byte, error) {
	m.lastExportExcelProfiles = append([]domain.CustomerProfile(nil), profiles...)
	return []byte("xlsx"), nil
}

func (m *customerProfileServiceMock) ExportToPDF(profiles []domain.CustomerProfile) ([]byte, error) {
	m.lastExportPDFProfiles = append([]domain.CustomerProfile(nil), profiles...)
	return []byte("pdf"), nil
}

func (m *customerProfileServiceMock) ExportHTMLToPDF(html string) ([]byte, error) {
	m.exportHTMLCalls++
	m.lastExportHTML = html
	if m.exportHTMLErr != nil {
		return nil, m.exportHTMLErr
	}
	return []byte("pdf"), nil
}

func buildCustomerProfileHandlerTestApp(h *Handler, withLocals bool, branchID uint, role string) *fiber.App {
	app := fiber.New()
	if withLocals {
		app.Use(func(c *fiber.Ctx) error {
			c.Locals("current_branch_id", branchID)
			c.Locals("role", role)
			return c.Next()
		})
	}

	app.Post("/profiles", h.SaveProfile)
	app.Put("/profiles/:id", h.SaveProfile)
	app.Get("/profiles/:id", h.GetProfile)
	app.Delete("/profiles/:id", h.DeleteProfile)
	app.Get("/profiles", h.ListProfiles)
	app.Get("/profiles/export/excel", h.ExportExcel)
	app.Get("/profiles/export/pdf", h.ExportPDF)
	app.Post("/profiles/export/pdf", h.ExportPreviewPDF)

	return app
}

func decodeCustomerProfileResponseMap(t *testing.T, resp *http.Response) map[string]interface{} {
	t.Helper()
	var body map[string]interface{}
	if err := json.NewDecoder(resp.Body).Decode(&body); err != nil {
		t.Fatalf("decode response failed: %v", err)
	}
	return body
}

func TestSaveProfileDraftDelegatesAndMapsIDFromPath(t *testing.T) {
	svc := &customerProfileServiceMock{}
	h := NewHandler(svc)
	app := buildCustomerProfileHandlerTestApp(h, true, 7, "admin")

	payload := `{"customer_name":"PT Atlas"}`
	req := httptest.NewRequest(http.MethodPut, "/profiles/42?mode=draft", bytes.NewBufferString(payload))
	req.Header.Set("Content-Type", "application/json")

	resp, err := app.Test(req)
	if err != nil {
		t.Fatalf("request failed: %v", err)
	}
	if resp.StatusCode != fiber.StatusOK {
		t.Fatalf("expected %d, got %d", fiber.StatusOK, resp.StatusCode)
	}

	if svc.saveDraftCalls != 1 || svc.saveLockedCalls != 0 {
		t.Fatalf("unexpected save call counts draft=%d locked=%d", svc.saveDraftCalls, svc.saveLockedCalls)
	}
	if svc.lastDraftBranch != 7 || svc.lastDraftRole != "admin" {
		t.Fatalf("unexpected draft context forwarding branch=%d role=%q", svc.lastDraftBranch, svc.lastDraftRole)
	}
	if svc.lastDraftProfile == nil || svc.lastDraftProfile.ID != 42 {
		t.Fatalf("expected mapped profile id=42, got profile=%+v", svc.lastDraftProfile)
	}

	body := decodeCustomerProfileResponseMap(t, resp)
	if body["success"] != true {
		t.Fatalf("expected success=true, got=%v", body["success"])
	}
}

func TestSaveProfileCompletedDelegatesToLocked(t *testing.T) {
	svc := &customerProfileServiceMock{}
	h := NewHandler(svc)
	app := buildCustomerProfileHandlerTestApp(h, true, 7, "admin")

	payload := `{"customer_name":"PT Atlas","status":"completed"}`
	req := httptest.NewRequest(http.MethodPost, "/profiles?mode=completed", bytes.NewBufferString(payload))
	req.Header.Set("Content-Type", "application/json")

	resp, err := app.Test(req)
	if err != nil {
		t.Fatalf("request failed: %v", err)
	}
	if resp.StatusCode != fiber.StatusOK {
		t.Fatalf("expected %d, got %d", fiber.StatusOK, resp.StatusCode)
	}

	if svc.saveDraftCalls != 0 || svc.saveLockedCalls != 1 {
		t.Fatalf("unexpected save call counts draft=%d locked=%d", svc.saveDraftCalls, svc.saveLockedCalls)
	}
	if svc.lastLockedProfile == nil || svc.lastLockedProfile.Status != "locked" {
		t.Fatalf("expected locked status to be normalized, got profile=%+v", svc.lastLockedProfile)
	}

	body := decodeCustomerProfileResponseMap(t, resp)
	if body["success"] != true {
		t.Fatalf("expected success=true, got=%v", body["success"])
	}
}

func TestSaveProfileDraftRequiresCustomerName(t *testing.T) {
	svc := &customerProfileServiceMock{}
	h := NewHandler(svc)
	app := buildCustomerProfileHandlerTestApp(h, true, 7, "admin")

	payload := `{"status":"draft"}`
	req := httptest.NewRequest(http.MethodPost, "/profiles?mode=draft", bytes.NewBufferString(payload))
	req.Header.Set("Content-Type", "application/json")

	resp, err := app.Test(req)
	if err != nil {
		t.Fatalf("request failed: %v", err)
	}
	if resp.StatusCode != fiber.StatusBadRequest {
		t.Fatalf("expected %d, got %d", fiber.StatusBadRequest, resp.StatusCode)
	}
	if svc.saveDraftCalls != 0 || svc.saveLockedCalls != 0 {
		t.Fatalf("did not expect service call, draft=%d locked=%d", svc.saveDraftCalls, svc.saveLockedCalls)
	}

	body := decodeCustomerProfileResponseMap(t, resp)
	if body["success"] != false {
		t.Fatalf("expected success=false, got=%v", body["success"])
	}
	if body["code"] != "VALIDATION_ERROR" {
		t.Fatalf("expected validation error code, got=%v", body["code"])
	}
}

func TestSaveProfileDropsEmptyDecisionMakerRowsBeforeValidation(t *testing.T) {
	svc := &customerProfileServiceMock{}
	h := NewHandler(svc)
	app := buildCustomerProfileHandlerTestApp(h, true, 7, "admin")

	payload := `{
		"customer_name":"PT Atlas",
		"status":"locked",
		"decision_makers":[
			{"name":"","position":"Direktur","contact_info":"","level":"Management"},
			{"name":"Budi","position":"Purchasing","contact_info":"08123456789","level":"Purchasing"}
		]
	}`
	req := httptest.NewRequest(http.MethodPost, "/profiles?mode=locked", strings.NewReader(payload))
	req.Header.Set("Content-Type", "application/json")

	resp, err := app.Test(req)
	if err != nil {
		t.Fatalf("request failed: %v", err)
	}
	if resp.StatusCode != fiber.StatusOK {
		t.Fatalf("expected %d, got %d", fiber.StatusOK, resp.StatusCode)
	}

	if svc.saveLockedCalls != 1 {
		t.Fatalf("expected locked save to be called once, got %d", svc.saveLockedCalls)
	}
	if svc.lastLockedProfile == nil {
		t.Fatal("expected locked profile to be forwarded")
	}
	if got := len(svc.lastLockedProfile.DecisionMakers); got != 1 {
		t.Fatalf("expected one meaningful decision maker row, got %d", got)
	}
	if svc.lastLockedProfile.DecisionMakers[0].Name != "Budi" {
		t.Fatalf("expected surviving row to keep named entry, got %+v", svc.lastLockedProfile.DecisionMakers[0])
	}
}

func TestSaveProfileMapsDuplicateNameConflictTo409(t *testing.T) {
	svc := &customerProfileServiceMock{saveLockedErr: errCustomerProfileNameConflict}
	h := NewHandler(svc)
	app := buildCustomerProfileHandlerTestApp(h, true, 7, "admin")

	payload := `{"customer_name":"PT Atlas","status":"locked"}`
	req := httptest.NewRequest(http.MethodPost, "/profiles?mode=locked", bytes.NewBufferString(payload))
	req.Header.Set("Content-Type", "application/json")

	resp, err := app.Test(req)
	if err != nil {
		t.Fatalf("request failed: %v", err)
	}
	if resp.StatusCode != fiber.StatusConflict {
		t.Fatalf("expected %d, got %d", fiber.StatusConflict, resp.StatusCode)
	}

	body := decodeCustomerProfileResponseMap(t, resp)
	if body["success"] != false {
		t.Fatalf("expected success=false, got=%v", body["success"])
	}
	if body["code"] != "CONFLICT" {
		t.Fatalf("expected conflict code, got=%v", body["code"])
	}
}

func TestSaveProfileRejectsInvalidJSON(t *testing.T) {
	svc := &customerProfileServiceMock{}
	h := NewHandler(svc)
	app := buildCustomerProfileHandlerTestApp(h, true, 1, "manager")

	req := httptest.NewRequest(http.MethodPost, "/profiles?mode=draft", bytes.NewBufferString("{invalid-json"))
	req.Header.Set("Content-Type", "application/json")

	resp, err := app.Test(req)
	if err != nil {
		t.Fatalf("request failed: %v", err)
	}
	if resp.StatusCode != fiber.StatusBadRequest {
		t.Fatalf("expected %d, got %d", fiber.StatusBadRequest, resp.StatusCode)
	}
	if svc.saveDraftCalls != 0 || svc.saveLockedCalls != 0 {
		t.Fatalf("did not expect service call on invalid json, draft=%d locked=%d", svc.saveDraftCalls, svc.saveLockedCalls)
	}
}

func TestSaveProfileLockedValidationFailureDoesNotCallService(t *testing.T) {
	svc := &customerProfileServiceMock{}
	h := NewHandler(svc)
	app := buildCustomerProfileHandlerTestApp(h, true, 2, "admin")

	payload := `{}`
	req := httptest.NewRequest(http.MethodPost, "/profiles?mode=locked", bytes.NewBufferString(payload))
	req.Header.Set("Content-Type", "application/json")

	resp, err := app.Test(req)
	if err != nil {
		t.Fatalf("request failed: %v", err)
	}
	if resp.StatusCode != fiber.StatusBadRequest {
		t.Fatalf("expected %d, got %d", fiber.StatusBadRequest, resp.StatusCode)
	}
	if svc.saveDraftCalls != 0 || svc.saveLockedCalls != 0 {
		t.Fatalf("did not expect service call on validation failure, draft=%d locked=%d", svc.saveDraftCalls, svc.saveLockedCalls)
	}
}

func TestGetProfileRejectsInvalidID(t *testing.T) {
	svc := &customerProfileServiceMock{}
	h := NewHandler(svc)
	app := buildCustomerProfileHandlerTestApp(h, true, 4, "staff")

	req := httptest.NewRequest(http.MethodGet, "/profiles/not-a-number", nil)
	resp, err := app.Test(req)
	if err != nil {
		t.Fatalf("request failed: %v", err)
	}
	if resp.StatusCode != fiber.StatusBadRequest {
		t.Fatalf("expected %d, got %d", fiber.StatusBadRequest, resp.StatusCode)
	}
	if svc.getCalls != 0 {
		t.Fatalf("did not expect GetProfile call on invalid id, got=%d", svc.getCalls)
	}
}

func TestGetProfileReturnsSuccessAndDelegatesContext(t *testing.T) {
	svc := &customerProfileServiceMock{getData: &domain.CustomerProfile{CustomerName: "PT Delta", BranchID: 3}}
	h := NewHandler(svc)
	app := buildCustomerProfileHandlerTestApp(h, true, 3, "manager")

	req := httptest.NewRequest(http.MethodGet, "/profiles/9", nil)
	resp, err := app.Test(req)
	if err != nil {
		t.Fatalf("request failed: %v", err)
	}
	if resp.StatusCode != fiber.StatusOK {
		t.Fatalf("expected %d, got %d", fiber.StatusOK, resp.StatusCode)
	}
	if svc.getCalls != 1 || svc.lastGetID != 9 || svc.lastGetBranch != 3 || svc.lastGetRole != "manager" {
		t.Fatalf("unexpected get args calls=%d id=%d branch=%d role=%q", svc.getCalls, svc.lastGetID, svc.lastGetBranch, svc.lastGetRole)
	}
}

func TestGetProfileReturnsNotFoundWhenServiceFails(t *testing.T) {
	svc := &customerProfileServiceMock{getErr: errors.New("not found")}
	h := NewHandler(svc)
	app := buildCustomerProfileHandlerTestApp(h, true, 1, "admin")

	req := httptest.NewRequest(http.MethodGet, "/profiles/99", nil)
	resp, err := app.Test(req)
	if err != nil {
		t.Fatalf("request failed: %v", err)
	}
	if resp.StatusCode != fiber.StatusNotFound {
		t.Fatalf("expected %d, got %d", fiber.StatusNotFound, resp.StatusCode)
	}
}

func TestDeleteProfileRejectsInvalidID(t *testing.T) {
	svc := &customerProfileServiceMock{}
	h := NewHandler(svc)
	app := buildCustomerProfileHandlerTestApp(h, true, 5, "manager")

	req := httptest.NewRequest(http.MethodDelete, "/profiles/invalid", nil)
	resp, err := app.Test(req)
	if err != nil {
		t.Fatalf("request failed: %v", err)
	}
	if resp.StatusCode != fiber.StatusBadRequest {
		t.Fatalf("expected %d, got %d", fiber.StatusBadRequest, resp.StatusCode)
	}
	if svc.deleteCalls != 0 {
		t.Fatalf("did not expect delete call on invalid id, got=%d", svc.deleteCalls)
	}
}

func TestDeleteProfileReturnsInternalErrorWhenServiceFails(t *testing.T) {
	svc := &customerProfileServiceMock{deleteErr: errors.New("db failed")}
	h := NewHandler(svc)
	app := buildCustomerProfileHandlerTestApp(h, true, 6, "admin")

	req := httptest.NewRequest(http.MethodDelete, "/profiles/12", nil)
	resp, err := app.Test(req)
	if err != nil {
		t.Fatalf("request failed: %v", err)
	}
	if resp.StatusCode != fiber.StatusInternalServerError {
		t.Fatalf("expected %d, got %d", fiber.StatusInternalServerError, resp.StatusCode)
	}
	if svc.deleteCalls != 1 || svc.lastDeleteID != 12 || svc.lastDeleteBranch != 6 || svc.lastDeleteRole != "admin" {
		t.Fatalf("unexpected delete args calls=%d id=%d branch=%d role=%q", svc.deleteCalls, svc.lastDeleteID, svc.lastDeleteBranch, svc.lastDeleteRole)
	}
}

func TestListProfilesUsesDefaultQueryValues(t *testing.T) {
	svc := &customerProfileServiceMock{
		listData:  []domain.CustomerProfile{{CustomerName: "PT A", Npwp: "123"}},
		listTotal: 1,
	}
	h := NewHandler(svc)
	app := buildCustomerProfileHandlerTestApp(h, true, 9, "staff")

	req := httptest.NewRequest(http.MethodGet, "/profiles", nil)
	resp, err := app.Test(req)
	if err != nil {
		t.Fatalf("request failed: %v", err)
	}
	if resp.StatusCode != fiber.StatusOK {
		t.Fatalf("expected %d, got %d", fiber.StatusOK, resp.StatusCode)
	}
	if svc.listCalls != 1 || svc.lastListPage != 1 || svc.lastListLimit != 10 || svc.lastListSearch != "" || svc.lastListTab != "all" || svc.lastListBranch != 9 || svc.lastListRole != "staff" {
		t.Fatalf("unexpected list args calls=%d page=%d limit=%d search=%q tab=%q branch=%d role=%q", svc.listCalls, svc.lastListPage, svc.lastListLimit, svc.lastListSearch, svc.lastListTab, svc.lastListBranch, svc.lastListRole)
	}
}

func TestListProfilesUsesProvidedQueryValues(t *testing.T) {
	svc := &customerProfileServiceMock{listData: []domain.CustomerProfile{}, listTotal: 0}
	h := NewHandler(svc)
	app := buildCustomerProfileHandlerTestApp(h, true, 10, "manager")

	req := httptest.NewRequest(http.MethodGet, "/profiles?page=3&limit=25&search=atlas", nil)
	resp, err := app.Test(req)
	if err != nil {
		t.Fatalf("request failed: %v", err)
	}
	if resp.StatusCode != fiber.StatusOK {
		t.Fatalf("expected %d, got %d", fiber.StatusOK, resp.StatusCode)
	}
	if svc.lastListPage != 3 || svc.lastListLimit != 25 || svc.lastListSearch != "atlas" || svc.lastListTab != "all" || svc.lastListBranch != 10 || svc.lastListRole != "manager" {
		t.Fatalf("unexpected list args page=%d limit=%d search=%q tab=%q branch=%d role=%q", svc.lastListPage, svc.lastListLimit, svc.lastListSearch, svc.lastListTab, svc.lastListBranch, svc.lastListRole)
	}
}

func TestListProfilesReturnsInternalErrorWhenServiceFails(t *testing.T) {
	svc := &customerProfileServiceMock{listErr: errors.New("query failed")}
	h := NewHandler(svc)
	app := buildCustomerProfileHandlerTestApp(h, true, 1, "admin")

	req := httptest.NewRequest(http.MethodGet, "/profiles", nil)
	resp, err := app.Test(req)
	if err != nil {
		t.Fatalf("request failed: %v", err)
	}
	if resp.StatusCode != fiber.StatusInternalServerError {
		t.Fatalf("expected %d, got %d", fiber.StatusInternalServerError, resp.StatusCode)
	}
}

func TestExportPreviewPDFReturnsPDFAndForwardsHTMLPayload(t *testing.T) {
	svc := &customerProfileServiceMock{}
	h := NewHandler(svc)
	app := buildCustomerProfileHandlerTestApp(h, true, 1, "admin")

	payload := `{"html":"<html><body><div id='doc-print-root'>preview</div></body></html>"}`
	req := httptest.NewRequest(http.MethodPost, `/profiles/export/pdf`, bytes.NewBufferString(payload))
	req.Header.Set("Content-Type", "application/json")

	resp, err := app.Test(req)
	if err != nil {
		t.Fatalf("request failed: %v", err)
	}
	if resp.StatusCode != fiber.StatusOK {
		t.Fatalf("expected %d, got %d", fiber.StatusOK, resp.StatusCode)
	}
	if got := resp.Header.Get("Content-Type"); got != "application/pdf" {
		t.Fatalf("expected application/pdf, got %q", got)
	}
	if svc.exportHTMLCalls != 1 || svc.lastExportHTML == "" {
		t.Fatalf("expected export html to be forwarded, calls=%d html=%q", svc.exportHTMLCalls, svc.lastExportHTML)
	}
}

func TestExportPreviewPDFRejectsUnsafeHTML(t *testing.T) {
	svc := &customerProfileServiceMock{}
	h := NewHandler(svc)
	app := buildCustomerProfileHandlerTestApp(h, true, 1, "admin")

	payload := `{"html":"<html><body><script>alert(1)</script></body></html>"}`
	req := httptest.NewRequest(http.MethodPost, `/profiles/export/pdf`, bytes.NewBufferString(payload))
	req.Header.Set("Content-Type", "application/json")

	resp, err := app.Test(req)
	if err != nil {
		t.Fatalf("request failed: %v", err)
	}
	if resp.StatusCode != fiber.StatusBadRequest {
		t.Fatalf("expected %d, got %d", fiber.StatusBadRequest, resp.StatusCode)
	}
	if svc.exportHTMLCalls != 0 {
		t.Fatalf("did not expect export html call for unsafe payload, got=%d", svc.exportHTMLCalls)
	}
}

func TestExportExcelUsesRequestedScopeAndFiltersTab(t *testing.T) {
	svc := &customerProfileServiceMock{
		listData: []domain.CustomerProfile{
			{CustomerName: "PT Wapu", WapuStatus: true},
			{CustomerName: "PT Non", WapuStatus: false},
		},
		listTotal: 2,
	}
	h := NewHandler(svc)
	app := buildCustomerProfileHandlerTestApp(h, true, 1, "admin")

	req := httptest.NewRequest(http.MethodGet, "/profiles/export/excel?page=3&limit=5&search=atlas&tab=wapu", nil)
	resp, err := app.Test(req)
	if err != nil {
		t.Fatalf("request failed: %v", err)
	}
	if resp.StatusCode != fiber.StatusOK {
		t.Fatalf("expected %d, got %d", fiber.StatusOK, resp.StatusCode)
	}
	if svc.lastListPage != 3 || svc.lastListLimit != 5 || svc.lastListSearch != "atlas" {
		t.Fatalf("unexpected list scope page=%d limit=%d search=%q", svc.lastListPage, svc.lastListLimit, svc.lastListSearch)
	}
	if svc.lastListTab != "wapu" {
		t.Fatalf("expected tab wapu to be forwarded, got %q", svc.lastListTab)
	}
	if len(svc.lastExportExcelProfiles) != 1 || svc.lastExportExcelProfiles[0].CustomerName != "PT Wapu" {
		t.Fatalf("expected wapu-only export, got %#v", svc.lastExportExcelProfiles)
	}
}

func TestExportPDFUsesRequestedScopeAndFiltersTab(t *testing.T) {
	svc := &customerProfileServiceMock{
		listData: []domain.CustomerProfile{
			{CustomerName: "PT Wapu", WapuStatus: true},
			{CustomerName: "PT Non", WapuStatus: false},
		},
		listTotal: 2,
	}
	h := NewHandler(svc)
	app := buildCustomerProfileHandlerTestApp(h, true, 1, "admin")

	req := httptest.NewRequest(http.MethodGet, "/profiles/export/pdf?page=2&limit=7&search=atlas&tab=non_wapu", nil)
	resp, err := app.Test(req)
	if err != nil {
		t.Fatalf("request failed: %v", err)
	}
	if resp.StatusCode != fiber.StatusOK {
		t.Fatalf("expected %d, got %d", fiber.StatusOK, resp.StatusCode)
	}
	if svc.lastListPage != 2 || svc.lastListLimit != 7 || svc.lastListSearch != "atlas" {
		t.Fatalf("unexpected list scope page=%d limit=%d search=%q", svc.lastListPage, svc.lastListLimit, svc.lastListSearch)
	}
	if svc.lastListTab != "non_wapu" {
		t.Fatalf("expected tab non_wapu to be forwarded, got %q", svc.lastListTab)
	}
	if len(svc.lastExportPDFProfiles) != 1 || svc.lastExportPDFProfiles[0].CustomerName != "PT Non" {
		t.Fatalf("expected non-wapu-only export, got %#v", svc.lastExportPDFProfiles)
	}
}
