package testutil

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

	"github.com/labstack/echo/v4"
)

func TestSetupTestDB_Works(t *testing.T) {
	db := SetupTestDB(t)
	if db == nil {
		t.Fatal("expected non-nil db")
	}
	sqlDB, err := db.DB()
	if err != nil {
		t.Fatalf("failed to get sql.DB: %v", err)
	}
	if err := sqlDB.Ping(); err != nil {
		t.Fatalf("ping failed: %v", err)
	}
}

func TestSetupTestRouter_HasValidator(t *testing.T) {
	e := SetupTestRouter()
	if e == nil {
		t.Fatal("expected non-nil router")
	}
	if e.Validator == nil {
		t.Error("expected validator to be set")
	}
}

func TestCreateTestUser_ReturnsUser(t *testing.T) {
	db := SetupTestDB(t)
	user := CreateTestUser(t, db, "testuser", "test@example.com", "password123")
	if user == nil {
		t.Fatal("expected non-nil user")
	}
	if user.ID == 0 {
		t.Error("expected user to have an ID")
	}
	if user.Username != "testuser" {
		t.Errorf("username = %q, want testuser", user.Username)
	}
	if user.Email != "test@example.com" {
		t.Errorf("email = %q, want test@example.com", user.Email)
	}
}

func TestSeedLookupData_PopulatesData(t *testing.T) {
	db := SetupTestDB(t)
	SeedLookupData(t, db)

	// Verify residence types seeded
	var rtCount int64
	db.Table("residence_residencetype").Count(&rtCount)
	if rtCount < 4 {
		t.Errorf("residence types = %d, want ≥4", rtCount)
	}

	// Verify task categories seeded
	var catCount int64
	db.Table("task_taskcategory").Count(&catCount)
	if catCount < 4 {
		t.Errorf("task categories = %d, want ≥4", catCount)
	}

	// Verify task priorities seeded
	var priCount int64
	db.Table("task_taskpriority").Count(&priCount)
	if priCount < 4 {
		t.Errorf("task priorities = %d, want ≥4", priCount)
	}

	// Verify task frequencies seeded
	var freqCount int64
	db.Table("task_taskfrequency").Count(&freqCount)
	if freqCount < 3 {
		t.Errorf("task frequencies = %d, want ≥3", freqCount)
	}

	// Verify contractor specialties seeded
	var specCount int64
	db.Table("task_contractorspecialty").Count(&specCount)
	if specCount < 4 {
		t.Errorf("contractor specialties = %d, want ≥4", specCount)
	}
}

func TestMockAuthMiddleware_SetsUser(t *testing.T) {
	db := SetupTestDB(t)
	user := CreateTestUser(t, db, "authuser", "auth@example.com", "pass")

	e := echo.New()
	mw := MockAuthMiddleware(user)

	var capturedUser interface{}
	handler := mw(func(c echo.Context) error {
		capturedUser = c.Get("auth_user")
		return c.NoContent(http.StatusOK)
	})

	req := httptest.NewRequest(http.MethodGet, "/", nil)
	rec := httptest.NewRecorder()
	c := e.NewContext(req, rec)

	if err := handler(c); err != nil {
		t.Fatalf("handler error: %v", err)
	}

	if capturedUser == nil {
		t.Fatal("expected auth_user to be set in context")
	}
}

func TestCreateTestResidence_ReturnsResidence(t *testing.T) {
	db := SetupTestDB(t)
	user := CreateTestUser(t, db, "owner", "owner@example.com", "pass")
	residence := CreateTestResidence(t, db, user.ID, "Test Home")

	if residence == nil {
		t.Fatal("expected non-nil residence")
	}
	if residence.ID == 0 {
		t.Error("expected residence to have an ID")
	}
	if residence.Name != "Test Home" {
		t.Errorf("name = %q, want Test Home", residence.Name)
	}
}

func TestCreateTestTask_ReturnsTask(t *testing.T) {
	db := SetupTestDB(t)
	user := CreateTestUser(t, db, "taskowner", "task@example.com", "pass")
	residence := CreateTestResidence(t, db, user.ID, "Task Home")
	task := CreateTestTask(t, db, residence.ID, user.ID, "Fix the sink")

	if task == nil {
		t.Fatal("expected non-nil task")
	}
	if task.ID == 0 {
		t.Error("expected task to have an ID")
	}
	if task.Title != "Fix the sink" {
		t.Errorf("title = %q, want Fix the sink", task.Title)
	}
}

func TestParseJSON_Valid(t *testing.T) {
	data := []byte(`{"name":"test","count":42}`)
	result := ParseJSON(t, data)
	if result["name"] != "test" {
		t.Errorf("name = %v, want test", result["name"])
	}
}

func TestParseJSONArray_Valid(t *testing.T) {
	data := []byte(`[{"id":1},{"id":2}]`)
	result := ParseJSONArray(t, data)
	if len(result) != 2 {
		t.Errorf("len = %d, want 2", len(result))
	}
}

func TestMakeRequestT_ReturnsRecorder(t *testing.T) {
	e := SetupTestRouter()
	e.GET("/test", func(c echo.Context) error {
		return c.JSON(http.StatusOK, map[string]string{"status": "ok"})
	})

	rec := MakeRequestT(t, e, http.MethodGet, "/test", nil, "")
	if rec.Code != http.StatusOK {
		t.Errorf("status = %d, want 200", rec.Code)
	}
}
