package rest

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

	"github.com/gin-gonic/gin"
	"github.com/nexuscrm/shared/pkg/models"
	"github.com/stretchr/testify/assert"
)

// ---------------------------------------------------------------------------
// toFolderShareResponse — SObject → FolderShareResponse mapping
// ---------------------------------------------------------------------------

func TestToFolderShareResponse_Full(t *testing.T) {
	record := models.SObject{
		"Id":           "share-001",
		"SharedToId":   "user-001",
		"SharedToType": "User",
		"AccessLevel":  "View",
	}

	resp := toFolderShareResponse(record)

	assert.Equal(t, "share-001", resp.ID)
	assert.Equal(t, "user-001", resp.SharedToID)
	assert.Equal(t, "User", resp.SharedToType)
	assert.Equal(t, "View", resp.AccessLevel)
}

func TestToFolderShareResponse_Empty(t *testing.T) {
	resp := toFolderShareResponse(models.SObject{})
	assert.Equal(t, "", resp.ID)
	assert.Equal(t, "", resp.SharedToID)
	assert.Equal(t, "", resp.SharedToType)
	assert.Equal(t, "", resp.AccessLevel)
}

func TestToFolderShareResponse_NilValues(t *testing.T) {
	record := models.SObject{
		"Id":           nil,
		"SharedToId":   nil,
		"SharedToType": nil,
		"AccessLevel":  nil,
	}
	resp := toFolderShareResponse(record)
	assert.Equal(t, "", resp.ID)
}

// ---------------------------------------------------------------------------
// GetFolder — auth & validation
// ---------------------------------------------------------------------------

func TestGetFolder_Unauthenticated(t *testing.T) {
	handler := &FolderHandler{}
	w := httptest.NewRecorder()
	c, _ := gin.CreateTestContext(w)
	c.Request = httptest.NewRequest("GET", "/folders/abc", nil)
	c.Params = gin.Params{{Key: "id", Value: "abc"}}

	assert.Panics(t, func() { handler.GetFolder(c) })
}

func TestGetFolder_EmptyID(t *testing.T) {
	handler := &FolderHandler{}
	w := httptest.NewRecorder()
	c, _ := gin.CreateTestContext(w)
	c.Request = httptest.NewRequest("GET", "/folders/", nil)
	c.Params = gin.Params{{Key: "id", Value: ""}}
	setTestUser(c)

	handler.GetFolder(c)
	assert.Equal(t, http.StatusBadRequest, w.Code)
}

func TestGetFolder_InvalidID(t *testing.T) {
	handler := &FolderHandler{}
	w := httptest.NewRecorder()
	c, _ := gin.CreateTestContext(w)
	c.Request = httptest.NewRequest("GET", "/folders/invalid!id@here", nil)
	c.Params = gin.Params{{Key: "id", Value: "invalid!id@here"}}
	setTestUser(c)

	handler.GetFolder(c)
	assert.Equal(t, http.StatusBadRequest, w.Code)
	assert.Contains(t, w.Body.String(), "Invalid folder ID")
}

// ---------------------------------------------------------------------------
// GetFolderChildren — auth & validation
// ---------------------------------------------------------------------------

func TestGetFolderChildren_Unauthenticated(t *testing.T) {
	handler := &FolderHandler{}
	w := httptest.NewRecorder()
	c, _ := gin.CreateTestContext(w)
	c.Request = httptest.NewRequest("GET", "/folders/abc/children", nil)
	c.Params = gin.Params{{Key: "id", Value: "abc"}}

	assert.Panics(t, func() { handler.GetFolderChildren(c) })
}

func TestGetFolderChildren_EmptyID(t *testing.T) {
	handler := &FolderHandler{}
	w := httptest.NewRecorder()
	c, _ := gin.CreateTestContext(w)
	c.Request = httptest.NewRequest("GET", "/folders//children", nil)
	c.Params = gin.Params{{Key: "id", Value: ""}}
	setTestUser(c)

	handler.GetFolderChildren(c)
	assert.Equal(t, http.StatusBadRequest, w.Code)
}

func TestGetFolderChildren_InvalidID(t *testing.T) {
	handler := &FolderHandler{}
	w := httptest.NewRecorder()
	c, _ := gin.CreateTestContext(w)
	c.Request = httptest.NewRequest("GET", "/folders/bad!id/children", nil)
	c.Params = gin.Params{{Key: "id", Value: "bad!id"}}
	setTestUser(c)

	handler.GetFolderChildren(c)
	assert.Equal(t, http.StatusBadRequest, w.Code)
}

// ---------------------------------------------------------------------------
// CreateFolder — auth & validation
// ---------------------------------------------------------------------------

func TestCreateFolder_Unauthenticated(t *testing.T) {
	handler := &FolderHandler{}
	w := httptest.NewRecorder()
	c, _ := gin.CreateTestContext(w)
	c.Request = httptest.NewRequest("POST", "/folders", nil)

	assert.Panics(t, func() { handler.CreateFolder(c) })
}

func TestCreateFolder_InvalidJSON(t *testing.T) {
	handler := &FolderHandler{}
	w := httptest.NewRecorder()
	c, _ := gin.CreateTestContext(w)
	c.Request = httptest.NewRequest("POST", "/folders", strings.NewReader("{invalid"))
	c.Request.Header.Set("Content-Type", "application/json")
	setTestUser(c)

	handler.CreateFolder(c)
	assert.Equal(t, http.StatusBadRequest, w.Code)
}

func TestCreateFolder_MissingName(t *testing.T) {
	handler := &FolderHandler{}
	w := httptest.NewRecorder()
	c, _ := gin.CreateTestContext(w)
	body := `{"type": "Report"}`
	c.Request = httptest.NewRequest("POST", "/folders", strings.NewReader(body))
	c.Request.Header.Set("Content-Type", "application/json")
	setTestUser(c)

	handler.CreateFolder(c)
	assert.Equal(t, http.StatusBadRequest, w.Code)
}

func TestCreateFolder_InvalidParentID(t *testing.T) {
	handler := &FolderHandler{}
	w := httptest.NewRecorder()
	c, _ := gin.CreateTestContext(w)
	body := `{"name": "Test Folder", "parentFolderId": "bad!parent!id"}`
	c.Request = httptest.NewRequest("POST", "/folders", strings.NewReader(body))
	c.Request.Header.Set("Content-Type", "application/json")
	setTestUser(c)

	handler.CreateFolder(c)
	assert.Equal(t, http.StatusBadRequest, w.Code)
	assert.Contains(t, w.Body.String(), "Invalid parent folder ID")
}

// ---------------------------------------------------------------------------
// UpdateFolder — auth & validation
// ---------------------------------------------------------------------------

func TestUpdateFolder_Unauthenticated(t *testing.T) {
	handler := &FolderHandler{}
	w := httptest.NewRecorder()
	c, _ := gin.CreateTestContext(w)
	c.Request = httptest.NewRequest("PATCH", "/folders/abc", nil)
	c.Params = gin.Params{{Key: "id", Value: "abc"}}

	assert.Panics(t, func() { handler.UpdateFolder(c) })
}

func TestUpdateFolder_EmptyID(t *testing.T) {
	handler := &FolderHandler{}
	w := httptest.NewRecorder()
	c, _ := gin.CreateTestContext(w)
	c.Request = httptest.NewRequest("PATCH", "/folders/", nil)
	c.Params = gin.Params{{Key: "id", Value: ""}}
	setTestUser(c)

	handler.UpdateFolder(c)
	assert.Equal(t, http.StatusBadRequest, w.Code)
}

func TestUpdateFolder_InvalidID(t *testing.T) {
	handler := &FolderHandler{}
	w := httptest.NewRecorder()
	c, _ := gin.CreateTestContext(w)
	c.Request = httptest.NewRequest("PATCH", "/folders/bad!id", strings.NewReader(`{"name":"test"}`))
	c.Request.Header.Set("Content-Type", "application/json")
	c.Params = gin.Params{{Key: "id", Value: "bad!id"}}
	setTestUser(c)

	handler.UpdateFolder(c)
	assert.Equal(t, http.StatusBadRequest, w.Code)
}

func TestUpdateFolder_InvalidJSON(t *testing.T) {
	handler := &FolderHandler{}
	w := httptest.NewRecorder()
	c, _ := gin.CreateTestContext(w)
	c.Request = httptest.NewRequest("PATCH", "/folders/550e8400-e29b-41d4-a716-446655440000", strings.NewReader("{broken"))
	c.Request.Header.Set("Content-Type", "application/json")
	c.Params = gin.Params{{Key: "id", Value: "550e8400-e29b-41d4-a716-446655440000"}}
	setTestUser(c)

	handler.UpdateFolder(c)
	assert.Equal(t, http.StatusBadRequest, w.Code)
}

// ---------------------------------------------------------------------------
// DeleteFolder — auth & validation
// ---------------------------------------------------------------------------

func TestDeleteFolder_Unauthenticated(t *testing.T) {
	handler := &FolderHandler{}
	w := httptest.NewRecorder()
	c, _ := gin.CreateTestContext(w)
	c.Request = httptest.NewRequest("DELETE", "/folders/abc", nil)
	c.Params = gin.Params{{Key: "id", Value: "abc"}}

	assert.Panics(t, func() { handler.DeleteFolder(c) })
}

func TestDeleteFolder_EmptyID(t *testing.T) {
	handler := &FolderHandler{}
	w := httptest.NewRecorder()
	c, _ := gin.CreateTestContext(w)
	c.Request = httptest.NewRequest("DELETE", "/folders/", nil)
	c.Params = gin.Params{{Key: "id", Value: ""}}
	setTestUser(c)

	handler.DeleteFolder(c)
	assert.Equal(t, http.StatusBadRequest, w.Code)
}

func TestDeleteFolder_InvalidID(t *testing.T) {
	handler := &FolderHandler{}
	w := httptest.NewRecorder()
	c, _ := gin.CreateTestContext(w)
	c.Request = httptest.NewRequest("DELETE", "/folders/bad!id", nil)
	c.Params = gin.Params{{Key: "id", Value: "bad!id"}}
	setTestUser(c)

	handler.DeleteFolder(c)
	assert.Equal(t, http.StatusBadRequest, w.Code)
}

// ---------------------------------------------------------------------------
// GetFolderShares — auth & validation
// ---------------------------------------------------------------------------

func TestGetFolderShares_Unauthenticated(t *testing.T) {
	handler := &FolderHandler{}
	w := httptest.NewRecorder()
	c, _ := gin.CreateTestContext(w)
	c.Request = httptest.NewRequest("GET", "/folders/abc/shares", nil)
	c.Params = gin.Params{{Key: "id", Value: "abc"}}

	assert.Panics(t, func() { handler.GetFolderShares(c) })
}

func TestGetFolderShares_InvalidID(t *testing.T) {
	handler := &FolderHandler{}
	w := httptest.NewRecorder()
	c, _ := gin.CreateTestContext(w)
	c.Request = httptest.NewRequest("GET", "/folders/bad/shares", nil)
	c.Params = gin.Params{{Key: "id", Value: "b@d!"}}
	setTestUser(c)

	handler.GetFolderShares(c)
	assert.Equal(t, http.StatusBadRequest, w.Code)
}

func TestGetFolderShares_EmptyID(t *testing.T) {
	handler := &FolderHandler{}
	w := httptest.NewRecorder()
	c, _ := gin.CreateTestContext(w)
	c.Request = httptest.NewRequest("GET", "/folders//shares", nil)
	c.Params = gin.Params{{Key: "id", Value: ""}}
	setTestUser(c)

	handler.GetFolderShares(c)
	assert.Equal(t, http.StatusBadRequest, w.Code)
}

// ---------------------------------------------------------------------------
// AddFolderShares — auth & validation
// ---------------------------------------------------------------------------

func TestAddFolderShares_Unauthenticated(t *testing.T) {
	handler := &FolderHandler{}
	w := httptest.NewRecorder()
	c, _ := gin.CreateTestContext(w)
	c.Request = httptest.NewRequest("POST", "/folders/abc/shares", nil)
	c.Params = gin.Params{{Key: "id", Value: "abc"}}

	assert.Panics(t, func() { handler.AddFolderShares(c) })
}

func TestAddFolderShares_InvalidFolderID(t *testing.T) {
	handler := &FolderHandler{}
	w := httptest.NewRecorder()
	c, _ := gin.CreateTestContext(w)
	c.Request = httptest.NewRequest("POST", "/folders/bad/shares", nil)
	c.Params = gin.Params{{Key: "id", Value: "b@d!"}}
	setTestUser(c)

	handler.AddFolderShares(c)
	assert.Equal(t, http.StatusBadRequest, w.Code)
}

func TestAddFolderShares_InvalidJSON(t *testing.T) {
	handler := &FolderHandler{}
	w := httptest.NewRecorder()
	c, _ := gin.CreateTestContext(w)
	c.Request = httptest.NewRequest("POST", "/folders/550e8400-e29b-41d4-a716-446655440000/shares", strings.NewReader("{bad"))
	c.Request.Header.Set("Content-Type", "application/json")
	c.Params = gin.Params{{Key: "id", Value: "550e8400-e29b-41d4-a716-446655440000"}}
	setTestUser(c)

	handler.AddFolderShares(c)
	assert.Equal(t, http.StatusBadRequest, w.Code)
}

// ---------------------------------------------------------------------------
// UpdateFolderShares — auth & validation
// ---------------------------------------------------------------------------

func TestUpdateFolderShares_Unauthenticated(t *testing.T) {
	handler := &FolderHandler{}
	w := httptest.NewRecorder()
	c, _ := gin.CreateTestContext(w)
	c.Request = httptest.NewRequest("PUT", "/folders/abc/shares", nil)
	c.Params = gin.Params{{Key: "id", Value: "abc"}}

	assert.Panics(t, func() { handler.UpdateFolderShares(c) })
}

func TestUpdateFolderShares_InvalidFolderID(t *testing.T) {
	handler := &FolderHandler{}
	w := httptest.NewRecorder()
	c, _ := gin.CreateTestContext(w)
	c.Request = httptest.NewRequest("PUT", "/folders/bad/shares", nil)
	c.Params = gin.Params{{Key: "id", Value: "b@d!"}}
	setTestUser(c)

	handler.UpdateFolderShares(c)
	assert.Equal(t, http.StatusBadRequest, w.Code)
}

func TestUpdateFolderShares_InvalidJSON(t *testing.T) {
	handler := &FolderHandler{}
	w := httptest.NewRecorder()
	c, _ := gin.CreateTestContext(w)
	c.Request = httptest.NewRequest("PUT", "/folders/550e8400-e29b-41d4-a716-446655440000/shares", strings.NewReader("{bad"))
	c.Request.Header.Set("Content-Type", "application/json")
	c.Params = gin.Params{{Key: "id", Value: "550e8400-e29b-41d4-a716-446655440000"}}
	setTestUser(c)

	handler.UpdateFolderShares(c)
	assert.Equal(t, http.StatusBadRequest, w.Code)
}

// ---------------------------------------------------------------------------
// GetFolderShare — auth & validation
// ---------------------------------------------------------------------------

func TestGetFolderShare_Unauthenticated(t *testing.T) {
	handler := &FolderHandler{}
	w := httptest.NewRecorder()
	c, _ := gin.CreateTestContext(w)
	c.Request = httptest.NewRequest("GET", "/folders/abc/shares/def", nil)
	c.Params = gin.Params{{Key: "id", Value: "abc"}, {Key: "shareId", Value: "def"}}

	assert.Panics(t, func() { handler.GetFolderShare(c) })
}

func TestGetFolderShare_InvalidFolderID(t *testing.T) {
	handler := &FolderHandler{}
	w := httptest.NewRecorder()
	c, _ := gin.CreateTestContext(w)
	c.Request = httptest.NewRequest("GET", "/folders/bad/shares/def", nil)
	c.Params = gin.Params{{Key: "id", Value: "b@d!"}, {Key: "shareId", Value: "550e8400-e29b-41d4-a716-446655440000"}}
	setTestUser(c)

	handler.GetFolderShare(c)
	assert.Equal(t, http.StatusBadRequest, w.Code)
	assert.Contains(t, w.Body.String(), "Invalid folder ID")
}

func TestGetFolderShare_InvalidShareID(t *testing.T) {
	handler := &FolderHandler{}
	w := httptest.NewRecorder()
	c, _ := gin.CreateTestContext(w)
	c.Request = httptest.NewRequest("GET", "/folders/550e8400-e29b-41d4-a716-446655440000/shares/bad", nil)
	c.Params = gin.Params{{Key: "id", Value: "550e8400-e29b-41d4-a716-446655440000"}, {Key: "shareId", Value: "b@d!"}}
	setTestUser(c)

	handler.GetFolderShare(c)
	assert.Equal(t, http.StatusBadRequest, w.Code)
	assert.Contains(t, w.Body.String(), "Invalid share ID")
}

// ---------------------------------------------------------------------------
// UpdateFolderShare — auth & validation
// ---------------------------------------------------------------------------

func TestUpdateFolderShare_Unauthenticated(t *testing.T) {
	handler := &FolderHandler{}
	w := httptest.NewRecorder()
	c, _ := gin.CreateTestContext(w)
	c.Request = httptest.NewRequest("PATCH", "/folders/abc/shares/def", nil)
	c.Params = gin.Params{{Key: "id", Value: "abc"}, {Key: "shareId", Value: "def"}}

	assert.Panics(t, func() { handler.UpdateFolderShare(c) })
}

func TestUpdateFolderShare_InvalidFolderID(t *testing.T) {
	handler := &FolderHandler{}
	w := httptest.NewRecorder()
	c, _ := gin.CreateTestContext(w)
	c.Request = httptest.NewRequest("PATCH", "/folders/bad/shares/def", nil)
	c.Params = gin.Params{{Key: "id", Value: "b@d!"}, {Key: "shareId", Value: "550e8400-e29b-41d4-a716-446655440000"}}
	setTestUser(c)

	handler.UpdateFolderShare(c)
	assert.Equal(t, http.StatusBadRequest, w.Code)
}

func TestUpdateFolderShare_InvalidShareID(t *testing.T) {
	handler := &FolderHandler{}
	w := httptest.NewRecorder()
	c, _ := gin.CreateTestContext(w)
	c.Request = httptest.NewRequest("PATCH", "/folders/550e8400-e29b-41d4-a716-446655440000/shares/bad", nil)
	c.Params = gin.Params{{Key: "id", Value: "550e8400-e29b-41d4-a716-446655440000"}, {Key: "shareId", Value: "b@d!"}}
	setTestUser(c)

	handler.UpdateFolderShare(c)
	assert.Equal(t, http.StatusBadRequest, w.Code)
}

func TestUpdateFolderShare_InvalidJSON(t *testing.T) {
	handler := &FolderHandler{}
	w := httptest.NewRecorder()
	c, _ := gin.CreateTestContext(w)
	c.Request = httptest.NewRequest("PATCH", "/folders/550e8400-e29b-41d4-a716-446655440000/shares/550e8400-e29b-41d4-a716-446655440001", strings.NewReader("{bad"))
	c.Request.Header.Set("Content-Type", "application/json")
	c.Params = gin.Params{{Key: "id", Value: "550e8400-e29b-41d4-a716-446655440000"}, {Key: "shareId", Value: "550e8400-e29b-41d4-a716-446655440001"}}
	setTestUser(c)

	handler.UpdateFolderShare(c)
	assert.Equal(t, http.StatusBadRequest, w.Code)
}

// ---------------------------------------------------------------------------
// DeleteFolderShare — auth & validation
// ---------------------------------------------------------------------------

func TestDeleteFolderShare_Unauthenticated(t *testing.T) {
	handler := &FolderHandler{}
	w := httptest.NewRecorder()
	c, _ := gin.CreateTestContext(w)
	c.Request = httptest.NewRequest("DELETE", "/folders/abc/shares/def", nil)
	c.Params = gin.Params{{Key: "id", Value: "abc"}, {Key: "shareId", Value: "def"}}

	assert.Panics(t, func() { handler.DeleteFolderShare(c) })
}

func TestDeleteFolderShare_InvalidFolderID(t *testing.T) {
	handler := &FolderHandler{}
	w := httptest.NewRecorder()
	c, _ := gin.CreateTestContext(w)
	c.Request = httptest.NewRequest("DELETE", "/folders/bad/shares/def", nil)
	c.Params = gin.Params{{Key: "id", Value: "b@d!"}, {Key: "shareId", Value: "550e8400-e29b-41d4-a716-446655440000"}}
	setTestUser(c)

	handler.DeleteFolderShare(c)
	assert.Equal(t, http.StatusBadRequest, w.Code)
}

func TestDeleteFolderShare_InvalidShareID(t *testing.T) {
	handler := &FolderHandler{}
	w := httptest.NewRecorder()
	c, _ := gin.CreateTestContext(w)
	c.Request = httptest.NewRequest("DELETE", "/folders/550e8400-e29b-41d4-a716-446655440000/shares/bad", nil)
	c.Params = gin.Params{{Key: "id", Value: "550e8400-e29b-41d4-a716-446655440000"}, {Key: "shareId", Value: "b@d!"}}
	setTestUser(c)

	handler.DeleteFolderShare(c)
	assert.Equal(t, http.StatusBadRequest, w.Code)
}

// ---------------------------------------------------------------------------
// ListFolders — auth path
// ---------------------------------------------------------------------------

func TestListFolders_Unauthenticated(t *testing.T) {
	handler := &FolderHandler{}
	w := httptest.NewRecorder()
	c, _ := gin.CreateTestContext(w)
	c.Request = httptest.NewRequest("GET", "/folders", nil)

	assert.Panics(t, func() { handler.ListFolders(c) })
}
