package handler

import (
	"bytes"
	"context"
	"errors"
	"net/http"
	"net/http/httptest"
	"strings"
	"testing"
	"time"

	"github.com/gofrs/uuid/v5"
	"github.com/saveinmed/backend-go/internal/domain"
	"github.com/saveinmed/backend-go/internal/usecase"
)

// MockRepository implements the Repository interface for testing without database
type MockRepository struct {
	companies []domain.Company
	products  []domain.Product
	users     []domain.User
	orders    []domain.Order
	shipping  []domain.ShippingMethod
}

func NewMockRepository() *MockRepository {
	return &MockRepository{
		companies: make([]domain.Company, 0),
		products:  make([]domain.Product, 0),
		users:     make([]domain.User, 0),
		orders:    make([]domain.Order, 0),
		shipping:  make([]domain.ShippingMethod, 0),
	}
}

// Company methods
func (m *MockRepository) CreateCompany(ctx context.Context, company *domain.Company) error {
	id, _ := uuid.NewV4()
	company.ID = id
	company.CreatedAt = time.Now()
	company.UpdatedAt = time.Now()
	m.companies = append(m.companies, *company)
	return nil
}

func (m *MockRepository) ListCompanies(ctx context.Context, filter domain.CompanyFilter) ([]domain.Company, int64, error) {
	return m.companies, int64(len(m.companies)), nil
}

func (m *MockRepository) GetCompany(ctx context.Context, id uuid.UUID) (*domain.Company, error) {
	for _, c := range m.companies {
		if c.ID == id {
			return &c, nil
		}
	}
	return nil, errors.New("company not found")
}

func (m *MockRepository) UpdateCompany(ctx context.Context, company *domain.Company) error {
	for i, c := range m.companies {
		if c.ID == company.ID {
			m.companies[i] = *company
			return nil
		}
	}
	return nil
}

func (m *MockRepository) DeleteCompany(ctx context.Context, id uuid.UUID) error {
	for i, c := range m.companies {
		if c.ID == id {
			m.companies = append(m.companies[:i], m.companies[i+1:]...)
			return nil
		}
	}
	return nil
}

// Product methods
func (m *MockRepository) CreateProduct(ctx context.Context, product *domain.Product) error {
	id, _ := uuid.NewV4()
	product.ID = id
	product.CreatedAt = time.Now()
	product.UpdatedAt = time.Now()
	m.products = append(m.products, *product)
	return nil
}

func (m *MockRepository) ListProducts(ctx context.Context, filter domain.ProductFilter) ([]domain.Product, int64, error) {
	return m.products, int64(len(m.products)), nil
}

func (m *MockRepository) ListRecords(ctx context.Context, filter domain.RecordSearchFilter) ([]domain.Product, int64, error) {
	return m.products, int64(len(m.products)), nil
}

func (m *MockRepository) GetProduct(ctx context.Context, id uuid.UUID) (*domain.Product, error) {
	for _, p := range m.products {
		if p.ID == id {
			return &p, nil
		}
	}
	return nil, errors.New("product not found")
}

func (m *MockRepository) UpdateProduct(ctx context.Context, product *domain.Product) error {
	for i, p := range m.products {
		if p.ID == product.ID {
			m.products[i] = *product
			return nil
		}
	}
	return nil
}

func (m *MockRepository) DeleteProduct(ctx context.Context, id uuid.UUID) error {
	for i, p := range m.products {
		if p.ID == id {
			m.products = append(m.products[:i], m.products[i+1:]...)
			return nil
		}
	}
	return nil
}

// Stub methods for other interfaces
func (m *MockRepository) AdjustInventory(ctx context.Context, productID uuid.UUID, delta int64, reason string) (*domain.InventoryItem, error) {
	return &domain.InventoryItem{}, nil
}

func (m *MockRepository) ListInventory(ctx context.Context, filter domain.InventoryFilter) ([]domain.InventoryItem, int64, error) {
	return []domain.InventoryItem{}, 0, nil
}

func (m *MockRepository) SearchProducts(ctx context.Context, filter domain.ProductSearchFilter) ([]domain.ProductWithDistance, int64, error) {
	return []domain.ProductWithDistance{}, 0, nil
}

func (m *MockRepository) CreateOrder(ctx context.Context, order *domain.Order) error {
	id, _ := uuid.NewV4()
	order.ID = id
	m.orders = append(m.orders, *order)
	return nil
}

func (m *MockRepository) ListOrders(ctx context.Context, filter domain.OrderFilter) ([]domain.Order, int64, error) {
	return m.orders, int64(len(m.orders)), nil
}

func (m *MockRepository) GetOrder(ctx context.Context, id uuid.UUID) (*domain.Order, error) {
	for _, o := range m.orders {
		if o.ID == id {
			return &o, nil
		}
	}
	return nil, errors.New("order not found")
}

func (m *MockRepository) UpdateOrderStatus(ctx context.Context, id uuid.UUID, status domain.OrderStatus) error {
	return nil
}

func (m *MockRepository) DeleteOrder(ctx context.Context, id uuid.UUID) error {
	return nil
}

func (m *MockRepository) CreateShipment(ctx context.Context, shipment *domain.Shipment) error {
	return nil
}

func (m *MockRepository) GetShipmentByOrderID(ctx context.Context, orderID uuid.UUID) (*domain.Shipment, error) {
	return nil, nil
}

func (m *MockRepository) CreateUser(ctx context.Context, user *domain.User) error {
	id, _ := uuid.NewV4()
	user.ID = id
	m.users = append(m.users, *user)
	return nil
}

func (m *MockRepository) ListUsers(ctx context.Context, filter domain.UserFilter) ([]domain.User, int64, error) {
	return m.users, int64(len(m.users)), nil
}

func (m *MockRepository) GetUser(ctx context.Context, id uuid.UUID) (*domain.User, error) {
	for _, u := range m.users {
		if u.ID == id {
			return &u, nil
		}
	}
	return nil, errors.New("user not found")
}

func (m *MockRepository) GetUserByUsername(ctx context.Context, username string) (*domain.User, error) {
	for _, u := range m.users {
		if u.Username == username {
			return &u, nil
		}
	}
	return nil, errors.New("user not found")
}

func (m *MockRepository) GetUserByEmail(ctx context.Context, email string) (*domain.User, error) {
	for _, u := range m.users {
		if u.Email == email {
			return &u, nil
		}
	}
	return nil, errors.New("user not found") // Simulate repository behavior
}

func (m *MockRepository) UpdateUser(ctx context.Context, user *domain.User) error {
	return nil
}

func (m *MockRepository) DeleteUser(ctx context.Context, id uuid.UUID) error {
	return nil
}

func (m *MockRepository) AddCartItem(ctx context.Context, item *domain.CartItem) (*domain.CartItem, error) {
	return item, nil
}

func (m *MockRepository) ListCartItems(ctx context.Context, buyerID uuid.UUID) ([]domain.CartItem, error) {
	return []domain.CartItem{}, nil
}

func (m *MockRepository) DeleteCartItem(ctx context.Context, id uuid.UUID, buyerID uuid.UUID) error {
	return nil
}

func (m *MockRepository) CreateReview(ctx context.Context, review *domain.Review) error {
	return nil
}

func (m *MockRepository) GetCompanyRating(ctx context.Context, companyID uuid.UUID) (*domain.CompanyRating, error) {
	return &domain.CompanyRating{}, nil
}

func (m *MockRepository) SellerDashboard(ctx context.Context, sellerID uuid.UUID) (*domain.SellerDashboard, error) {
	return &domain.SellerDashboard{}, nil
}

func (m *MockRepository) AdminDashboard(ctx context.Context, since time.Time) (*domain.AdminDashboard, error) {
	return &domain.AdminDashboard{}, nil
}

func (m *MockRepository) GetShippingMethodsByVendor(ctx context.Context, vendorID uuid.UUID) ([]domain.ShippingMethod, error) {
	var methods []domain.ShippingMethod
	for _, method := range m.shipping {
		if method.VendorID == vendorID {
			methods = append(methods, method)
		}
	}
	return methods, nil
}

func (m *MockRepository) UpsertShippingMethods(ctx context.Context, methods []domain.ShippingMethod) error {
	for _, method := range methods {
		updated := false
		for i, existing := range m.shipping {
			if existing.VendorID == method.VendorID && existing.Type == method.Type {
				m.shipping[i] = method
				updated = true
				break
			}
		}
		if !updated {
			m.shipping = append(m.shipping, method)
		}
	}
	return nil
}

// MockPaymentGateway implements the PaymentGateway interface for testing
type MockPaymentGateway struct{}

func (m *MockPaymentGateway) CreatePreference(ctx context.Context, order *domain.Order) (*domain.PaymentPreference, error) {
	return &domain.PaymentPreference{}, nil
}

func (m *MockPaymentGateway) ParseWebhook(ctx context.Context, payload []byte) (*domain.PaymentSplitResult, error) {
	return &domain.PaymentSplitResult{}, nil
}

// Create a test handler for testing
func newTestHandler() *Handler {
	repo := NewMockRepository()
	gateway := &MockPaymentGateway{}
	svc := usecase.NewService(repo, gateway, 0.05, "test-secret", time.Hour, "test-pepper")
	return New(svc)
}

func TestListProducts(t *testing.T) {
	h := newTestHandler()

	req := httptest.NewRequest(http.MethodGet, "/api/v1/products", nil)
	rec := httptest.NewRecorder()

	h.ListProducts(rec, req)

	if rec.Code != http.StatusOK {
		t.Errorf("expected status %d, got %d", http.StatusOK, rec.Code)
	}

	// Should return page with empty products array
	body := strings.TrimSpace(rec.Body.String())
	if !strings.Contains(body, `"products":[]`) || !strings.Contains(body, `"total":0`) {
		t.Errorf("expected paginated response with empty products, got %s", body)
	}
}

func TestListCompanies(t *testing.T) {
	h := newTestHandler()

	req := httptest.NewRequest(http.MethodGet, "/api/v1/companies", nil)
	rec := httptest.NewRecorder()

	h.ListCompanies(rec, req)

	if rec.Code != http.StatusOK {
		t.Errorf("expected status %d, got %d", http.StatusOK, rec.Code)
	}
}

func TestCreateCompany(t *testing.T) {
	h := newTestHandler()

	payload := `{"category":"farmacia","cnpj":"12345678901234","corporate_name":"Test Pharmacy","license_number":"LIC-001"}`
	req := httptest.NewRequest(http.MethodPost, "/api/v1/companies", bytes.NewReader([]byte(payload)))
	req.Header.Set("Content-Type", "application/json")
	rec := httptest.NewRecorder()

	h.CreateCompany(rec, req)

	if rec.Code != http.StatusCreated {
		t.Errorf("expected status %d, got %d: %s", http.StatusCreated, rec.Code, rec.Body.String())
	}
}

func TestCreateProduct(t *testing.T) {
	h := newTestHandler()

	sellerID, _ := uuid.NewV4()
	payload := `{"seller_id":"` + sellerID.String() + `","name":"Aspirin","description":"Pain relief","batch":"BATCH-001","expires_at":"2025-12-31T00:00:00Z","price_cents":1000,"stock":100}`
	req := httptest.NewRequest(http.MethodPost, "/api/v1/products", bytes.NewReader([]byte(payload)))
	req.Header.Set("Content-Type", "application/json")
	rec := httptest.NewRecorder()

	h.CreateProduct(rec, req)

	if rec.Code != http.StatusCreated {
		t.Errorf("expected status %d, got %d: %s", http.StatusCreated, rec.Code, rec.Body.String())
	}
}

func TestLoginInvalidCredentials(t *testing.T) {
	h := newTestHandler()

	payload := `{"username":"nonexistent","password":"wrongpassword"}`
	req := httptest.NewRequest(http.MethodPost, "/api/v1/auth/login", bytes.NewReader([]byte(payload)))
	req.Header.Set("Content-Type", "application/json")
	rec := httptest.NewRecorder()

	h.Login(rec, req)

	// Should fail because user doesn't exist
	if rec.Code != http.StatusUnauthorized {
		t.Errorf("expected status %d, got %d", http.StatusUnauthorized, rec.Code)
	}
}

func TestAdminLogin_Success(t *testing.T) {
	repo := NewMockRepository()
	gateway := &MockPaymentGateway{}
	svc := usecase.NewService(repo, gateway, 0.05, "test-secret", time.Hour, "test-pepper")
	h := New(svc)

	// Create admin user through service (which hashes password)
	companyID, _ := uuid.NewV4()
	user := &domain.User{
		CompanyID: companyID,
		Role:      "admin",
		Name:      "Admin User",
		Username:  "admin",
		Email:     "admin@test.com",
	}
	err := svc.CreateUser(context.Background(), user, "admin123")
	if err != nil {
		t.Fatalf("failed to create user: %v", err)
	}
	// Update mock with hashed user
	repo.users[0] = *user

	// Login with correct credentials
	payload := `{"username":"admin","password":"admin123"}`
	req := httptest.NewRequest(http.MethodPost, "/api/v1/auth/login", bytes.NewReader([]byte(payload)))
	req.Header.Set("Content-Type", "application/json")
	rec := httptest.NewRecorder()

	h.Login(rec, req)

	if rec.Code != http.StatusOK {
		t.Errorf("expected status %d, got %d: %s", http.StatusOK, rec.Code, rec.Body.String())
	}

	// Verify response contains token
	body := rec.Body.String()
	if !strings.Contains(body, "token") {
		t.Errorf("expected response to contain token, got: %s", body)
	}
	if !strings.Contains(body, "expires_at") {
		t.Errorf("expected response to contain expires_at, got: %s", body)
	}
}

func TestAdminLogin_WrongPassword(t *testing.T) {
	repo := NewMockRepository()
	gateway := &MockPaymentGateway{}
	svc := usecase.NewService(repo, gateway, 0.05, "test-secret", time.Hour, "test-pepper")
	h := New(svc)

	// Create admin user
	companyID, _ := uuid.NewV4()
	user := &domain.User{
		CompanyID: companyID,
		Role:      "admin",
		Name:      "Admin User",
		Username:  "admin",
		Email:     "admin@test.com",
	}
	svc.CreateUser(context.Background(), user, "correctpassword")
	repo.users[0] = *user

	// Login with wrong password
	payload := `{"username":"admin","password":"wrongpassword"}`
	req := httptest.NewRequest(http.MethodPost, "/api/v1/auth/login", bytes.NewReader([]byte(payload)))
	req.Header.Set("Content-Type", "application/json")
	rec := httptest.NewRecorder()

	h.Login(rec, req)

	if rec.Code != http.StatusUnauthorized {
		t.Errorf("expected status %d, got %d", http.StatusUnauthorized, rec.Code)
	}
}

func TestListOrders(t *testing.T) {
	h := newTestHandler()

	req := httptest.NewRequest(http.MethodGet, "/api/v1/orders", nil)
	rec := httptest.NewRecorder()

	h.ListOrders(rec, req)

	if rec.Code != http.StatusOK {
		t.Errorf("expected status %d, got %d", http.StatusOK, rec.Code)
	}
}

// --- Auth Handler Tests ---

func TestLogin_InvalidJSON(t *testing.T) {
	h := newTestHandler()
	req := httptest.NewRequest(http.MethodPost, "/api/v1/auth/login", bytes.NewReader([]byte("invalid")))
	rec := httptest.NewRecorder()
	h.Login(rec, req)
	if rec.Code != http.StatusBadRequest {
		t.Errorf("expected %d, got %d", http.StatusBadRequest, rec.Code)
	}
}

func TestRegister_InvalidJSON(t *testing.T) {
	h := newTestHandler()
	req := httptest.NewRequest(http.MethodPost, "/api/v1/auth/register", bytes.NewReader([]byte("{")))
	rec := httptest.NewRecorder()
	h.Register(rec, req)
	if rec.Code != http.StatusBadRequest {
		t.Errorf("expected %d, got %d", http.StatusBadRequest, rec.Code)
	}
}

func TestRegister_MissingCompany(t *testing.T) {
	h := newTestHandler()
	payload := `{"role":"admin","name":"Test","email":"test@test.com","password":"pass123"}`
	req := httptest.NewRequest(http.MethodPost, "/api/v1/auth/register", bytes.NewReader([]byte(payload)))
	rec := httptest.NewRecorder()
	h.Register(rec, req)
	if rec.Code != http.StatusBadRequest {
		t.Errorf("expected %d, got %d", http.StatusBadRequest, rec.Code)
	}
}

// --- Company Handler Tests ---

func TestGetCompany_NotFound(t *testing.T) {
	h := newTestHandler()
	id, _ := uuid.NewV4()
	req := httptest.NewRequest(http.MethodGet, "/api/v1/companies/"+id.String(), nil)
	rec := httptest.NewRecorder()
	h.GetCompany(rec, req)
	if rec.Code != http.StatusNotFound {
		t.Errorf("expected %d, got %d", http.StatusNotFound, rec.Code)
	}
}

func TestGetCompany_InvalidUUID(t *testing.T) {
	h := newTestHandler()
	req := httptest.NewRequest(http.MethodGet, "/api/v1/companies/invalid", nil)
	rec := httptest.NewRecorder()
	h.GetCompany(rec, req)
	if rec.Code != http.StatusBadRequest {
		t.Errorf("expected %d, got %d", http.StatusBadRequest, rec.Code)
	}
}

func TestUpdateCompany_InvalidJSON(t *testing.T) {
	h := newTestHandler()
	id, _ := uuid.NewV4()
	req := httptest.NewRequest(http.MethodPatch, "/api/v1/companies/"+id.String(), bytes.NewReader([]byte("{")))
	rec := httptest.NewRecorder()
	h.UpdateCompany(rec, req)
	if rec.Code != http.StatusBadRequest {
		t.Errorf("expected %d, got %d", http.StatusBadRequest, rec.Code)
	}
}

func TestDeleteCompany_InvalidUUID(t *testing.T) {
	h := newTestHandler()
	req := httptest.NewRequest(http.MethodDelete, "/api/v1/companies/invalid", nil)
	rec := httptest.NewRecorder()
	h.DeleteCompany(rec, req)
	if rec.Code != http.StatusBadRequest {
		t.Errorf("expected %d, got %d", http.StatusBadRequest, rec.Code)
	}
}

func TestVerifyCompany_InvalidPath(t *testing.T) {
	h := newTestHandler()
	req := httptest.NewRequest(http.MethodPatch, "/api/v1/companies/something", nil)
	rec := httptest.NewRecorder()
	h.VerifyCompany(rec, req)
	if rec.Code != http.StatusNotFound {
		t.Errorf("expected %d, got %d", http.StatusNotFound, rec.Code)
	}
}

// --- Product Handler Tests ---

func TestGetProduct_NotFound(t *testing.T) {
	h := newTestHandler()
	id, _ := uuid.NewV4()
	req := httptest.NewRequest(http.MethodGet, "/api/v1/products/"+id.String(), nil)
	rec := httptest.NewRecorder()
	h.GetProduct(rec, req)
	if rec.Code != http.StatusNotFound {
		t.Errorf("expected %d, got %d", http.StatusNotFound, rec.Code)
	}
}

func TestUpdateProduct_InvalidJSON(t *testing.T) {
	h := newTestHandler()
	id, _ := uuid.NewV4()
	req := httptest.NewRequest(http.MethodPatch, "/api/v1/products/"+id.String(), bytes.NewReader([]byte("{")))
	rec := httptest.NewRecorder()
	h.UpdateProduct(rec, req)
	if rec.Code != http.StatusBadRequest {
		t.Errorf("expected %d, got %d", http.StatusBadRequest, rec.Code)
	}
}

func TestDeleteProduct_InvalidUUID(t *testing.T) {
	h := newTestHandler()
	req := httptest.NewRequest(http.MethodDelete, "/api/v1/products/invalid", nil)
	rec := httptest.NewRecorder()
	h.DeleteProduct(rec, req)
	if rec.Code != http.StatusBadRequest {
		t.Errorf("expected %d, got %d", http.StatusBadRequest, rec.Code)
	}
}

// --- Inventory Handler Tests ---

func TestListInventory_Success(t *testing.T) {
	h := newTestHandler()
	req := httptest.NewRequest(http.MethodGet, "/api/v1/inventory", nil)
	rec := httptest.NewRecorder()
	h.ListInventory(rec, req)
	if rec.Code != http.StatusOK {
		t.Errorf("expected %d, got %d", http.StatusOK, rec.Code)
	}
}

func TestListInventory_InvalidDays(t *testing.T) {
	h := newTestHandler()
	req := httptest.NewRequest(http.MethodGet, "/api/v1/inventory?expires_in_days=abc", nil)
	rec := httptest.NewRecorder()
	h.ListInventory(rec, req)
	if rec.Code != http.StatusBadRequest {
		t.Errorf("expected %d, got %d", http.StatusBadRequest, rec.Code)
	}
}

func TestAdjustInventory_InvalidJSON(t *testing.T) {
	h := newTestHandler()
	req := httptest.NewRequest(http.MethodPost, "/api/v1/inventory/adjust", bytes.NewReader([]byte("{")))
	rec := httptest.NewRecorder()
	h.AdjustInventory(rec, req)
	if rec.Code != http.StatusBadRequest {
		t.Errorf("expected %d, got %d", http.StatusBadRequest, rec.Code)
	}
}

func TestAdjustInventory_ZeroDelta(t *testing.T) {
	h := newTestHandler()
	id, _ := uuid.NewV4()
	payload := `{"product_id":"` + id.String() + `","delta":0,"reason":"test"}`
	req := httptest.NewRequest(http.MethodPost, "/api/v1/inventory/adjust", bytes.NewReader([]byte(payload)))
	rec := httptest.NewRecorder()
	h.AdjustInventory(rec, req)
	if rec.Code != http.StatusBadRequest {
		t.Errorf("expected %d, got %d", http.StatusBadRequest, rec.Code)
	}
}

// --- Order Handler Tests ---

func TestCreateOrder_InvalidJSON(t *testing.T) {
	h := newTestHandler()
	req := httptest.NewRequest(http.MethodPost, "/api/v1/orders", bytes.NewReader([]byte("{")))
	rec := httptest.NewRecorder()
	h.CreateOrder(rec, req)
	if rec.Code != http.StatusBadRequest {
		t.Errorf("expected %d, got %d", http.StatusBadRequest, rec.Code)
	}
}

func TestGetOrder_NotFound(t *testing.T) {
	h := newTestHandler()
	id, _ := uuid.NewV4()
	req := httptest.NewRequest(http.MethodGet, "/api/v1/orders/"+id.String(), nil)
	rec := httptest.NewRecorder()
	h.GetOrder(rec, req)
	if rec.Code != http.StatusNotFound {
		t.Errorf("expected %d, got %d", http.StatusNotFound, rec.Code)
	}
}

func TestUpdateOrderStatus_InvalidStatus(t *testing.T) {
	h := newTestHandler()
	id, _ := uuid.NewV4()
	payload := `{"status":"invalid_status"}`
	req := httptest.NewRequest(http.MethodPatch, "/api/v1/orders/"+id.String()+"/status", bytes.NewReader([]byte(payload)))
	rec := httptest.NewRecorder()
	h.UpdateOrderStatus(rec, req)
	if rec.Code != http.StatusBadRequest {
		t.Errorf("expected %d, got %d", http.StatusBadRequest, rec.Code)
	}
}

func TestDeleteOrder_InvalidUUID(t *testing.T) {
	h := newTestHandler()
	req := httptest.NewRequest(http.MethodDelete, "/api/v1/orders/invalid", nil)
	rec := httptest.NewRecorder()
	h.DeleteOrder(rec, req)
	if rec.Code != http.StatusBadRequest {
		t.Errorf("expected %d, got %d", http.StatusBadRequest, rec.Code)
	}
}

// --- Payment Handler Tests ---

func TestCreatePaymentPreference_InvalidPath(t *testing.T) {
	h := newTestHandler()
	req := httptest.NewRequest(http.MethodPost, "/api/v1/orders/something/other", nil)
	rec := httptest.NewRecorder()
	h.CreatePaymentPreference(rec, req)
	if rec.Code != http.StatusNotFound {
		t.Errorf("expected %d, got %d", http.StatusNotFound, rec.Code)
	}
}

func TestHandlePaymentWebhook_InvalidJSON(t *testing.T) {
	h := newTestHandler()
	req := httptest.NewRequest(http.MethodPost, "/api/v1/payments/webhook", bytes.NewReader([]byte("{")))
	rec := httptest.NewRecorder()
	h.HandlePaymentWebhook(rec, req)
	if rec.Code != http.StatusBadRequest {
		t.Errorf("expected %d, got %d", http.StatusBadRequest, rec.Code)
	}
}

func TestCreateShipment_InvalidJSON(t *testing.T) {
	h := newTestHandler()
	req := httptest.NewRequest(http.MethodPost, "/api/v1/shipments", bytes.NewReader([]byte("{")))
	rec := httptest.NewRecorder()
	h.CreateShipment(rec, req)
	if rec.Code != http.StatusBadRequest {
		t.Errorf("expected %d, got %d", http.StatusBadRequest, rec.Code)
	}
}

func TestGetShipmentByOrderID_InvalidUUID(t *testing.T) {
	h := newTestHandler()
	req := httptest.NewRequest(http.MethodGet, "/api/v1/shipments/invalid", nil)
	rec := httptest.NewRecorder()
	h.GetShipmentByOrderID(rec, req)
	if rec.Code != http.StatusBadRequest {
		t.Errorf("expected %d, got %d", http.StatusBadRequest, rec.Code)
	}
}

// --- Dashboard Handler Tests ---

func TestGetSellerDashboard_NoContext(t *testing.T) {
	h := newTestHandler()
	req := httptest.NewRequest(http.MethodGet, "/api/v1/dashboard/seller", nil)
	rec := httptest.NewRecorder()
	h.GetSellerDashboard(rec, req)
	if rec.Code != http.StatusBadRequest {
		t.Errorf("expected %d, got %d", http.StatusBadRequest, rec.Code)
	}
}

func TestGetAdminDashboard_NotAdmin(t *testing.T) {
	h := newTestHandler()
	req := httptest.NewRequest(http.MethodGet, "/api/v1/dashboard/admin", nil)
	req.Header.Set("X-User-Role", "Seller")
	rec := httptest.NewRecorder()
	h.GetAdminDashboard(rec, req)
	if rec.Code != http.StatusForbidden {
		t.Errorf("expected %d, got %d", http.StatusForbidden, rec.Code)
	}
}

func TestGetAdminDashboard_Success(t *testing.T) {
	h := newTestHandler()
	req := httptest.NewRequest(http.MethodGet, "/api/v1/dashboard/admin", nil)
	req.Header.Set("X-User-Role", "Admin")
	rec := httptest.NewRecorder()
	h.GetAdminDashboard(rec, req)
	if rec.Code != http.StatusOK {
		t.Errorf("expected %d, got %d", http.StatusOK, rec.Code)
	}
}

// --- User Handler Tests ---

func TestListUsers_Success(t *testing.T) {
	h := newTestHandler()
	req := httptest.NewRequest(http.MethodGet, "/api/v1/users", nil)
	req.Header.Set("X-User-Role", "Admin")
	rec := httptest.NewRecorder()
	h.ListUsers(rec, req)
	if rec.Code != http.StatusOK {
		t.Errorf("expected %d, got %d", http.StatusOK, rec.Code)
	}
}

func TestGetUser_NotFound(t *testing.T) {
	h := newTestHandler()
	id, _ := uuid.NewV4()
	req := httptest.NewRequest(http.MethodGet, "/api/v1/users/"+id.String(), nil)
	req.Header.Set("X-User-Role", "Admin")
	rec := httptest.NewRecorder()
	h.GetUser(rec, req)
	if rec.Code != http.StatusNotFound {
		t.Errorf("expected %d, got %d", http.StatusNotFound, rec.Code)
	}
}

func TestCreateUser_InvalidJSON(t *testing.T) {
	h := newTestHandler()
	req := httptest.NewRequest(http.MethodPost, "/api/v1/users", bytes.NewReader([]byte("{")))
	req.Header.Set("X-User-Role", "Admin")
	rec := httptest.NewRecorder()
	h.CreateUser(rec, req)
	if rec.Code != http.StatusBadRequest {
		t.Errorf("expected %d, got %d", http.StatusBadRequest, rec.Code)
	}
}

func TestUpdateUser_InvalidJSON(t *testing.T) {
	h := newTestHandler()
	id, _ := uuid.NewV4()
	req := httptest.NewRequest(http.MethodPut, "/api/v1/users/"+id.String(), bytes.NewReader([]byte("{")))
	req.Header.Set("X-User-Role", "Admin")
	rec := httptest.NewRecorder()
	h.UpdateUser(rec, req)
	if rec.Code != http.StatusBadRequest {
		t.Errorf("expected %d, got %d", http.StatusBadRequest, rec.Code)
	}
}

func TestDeleteUser_InvalidUUID(t *testing.T) {
	h := newTestHandler()
	req := httptest.NewRequest(http.MethodDelete, "/api/v1/users/invalid", nil)
	req.Header.Set("X-User-Role", "Admin")
	rec := httptest.NewRecorder()
	h.DeleteUser(rec, req)
	if rec.Code != http.StatusBadRequest {
		t.Errorf("expected %d, got %d", http.StatusBadRequest, rec.Code)
	}
}

// --- Cart Handler Tests ---

func TestGetCart_NoContext(t *testing.T) {
	h := newTestHandler()
	req := httptest.NewRequest(http.MethodGet, "/api/v1/cart", nil)
	rec := httptest.NewRecorder()
	h.GetCart(rec, req)
	if rec.Code != http.StatusBadRequest {
		t.Errorf("expected %d, got %d", http.StatusBadRequest, rec.Code)
	}
}

func TestAddToCart_InvalidJSON(t *testing.T) {
	h := newTestHandler()
	req := httptest.NewRequest(http.MethodPost, "/api/v1/cart", bytes.NewReader([]byte("{")))
	rec := httptest.NewRecorder()
	h.AddToCart(rec, req)
	if rec.Code != http.StatusBadRequest {
		t.Errorf("expected %d, got %d", http.StatusBadRequest, rec.Code)
	}
}

func TestDeleteCartItem_NoContext(t *testing.T) {
	h := newTestHandler()
	id, _ := uuid.NewV4()
	req := httptest.NewRequest(http.MethodDelete, "/api/v1/cart/"+id.String(), nil)
	rec := httptest.NewRecorder()
	h.DeleteCartItem(rec, req)
	if rec.Code != http.StatusBadRequest {
		t.Errorf("expected %d, got %d", http.StatusBadRequest, rec.Code)
	}
}

// --- Review Handler Tests ---

func TestCreateReview_InvalidJSON(t *testing.T) {
	h := newTestHandler()
	req := httptest.NewRequest(http.MethodPost, "/api/v1/reviews", bytes.NewReader([]byte("{")))
	rec := httptest.NewRecorder()
	h.CreateReview(rec, req)
	if rec.Code != http.StatusBadRequest {
		t.Errorf("expected %d, got %d", http.StatusBadRequest, rec.Code)
	}
}

// --- GetCompanyRating Handler Tests ---

func TestGetCompanyRating_InvalidPath(t *testing.T) {
	h := newTestHandler()
	req := httptest.NewRequest(http.MethodGet, "/api/v1/companies/something", nil)
	rec := httptest.NewRecorder()
	h.GetCompanyRating(rec, req)
	if rec.Code != http.StatusNotFound {
		t.Errorf("expected %d, got %d", http.StatusNotFound, rec.Code)
	}
}

// --- GetMyCompany Handler Tests ---

func TestGetMyCompany_NoContext(t *testing.T) {
	h := newTestHandler()
	req := httptest.NewRequest(http.MethodGet, "/api/v1/companies/me", nil)
	rec := httptest.NewRecorder()
	h.GetMyCompany(rec, req)
	if rec.Code != http.StatusBadRequest {
		t.Errorf("expected %d, got %d", http.StatusBadRequest, rec.Code)
	}
}
