package handler

import (
	"encoding/json"
	"errors"
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/gin-gonic/gin"
	"github.com/stretchr/testify/mock"
	"github.com/stretchr/testify/require"

	coremodel "security-center-backend/internal/model"
	"security-center-backend/internal/modules/caasm/mocks"
	caasmmodel "security-center-backend/internal/modules/caasm/model"
	"security-center-backend/internal/modules/caasm/service"
)

func TestPhase5RelationshipGraphReturnsGraph(t *testing.T) {
	gin.SetMode(gin.TestMode)
	router := gin.New()
	repo := &mocks.MockAssetRepository{}
	repo.On("ListRelationships", mock.Anything, mock.Anything).
		Return([]caasmmodel.AssetRelationship{
			{SourceAssetID: 900001, TargetAssetID: 900002, RelationshipType: "e2e-seed-connects_to"},
		}, nil)
	repo.On("ListByIDs", mock.Anything, mock.Anything).
		Return([]caasmmodel.Asset{
			{Base: coremodel.Base{ID: 900001}, Name: "e2e-seed-gateway", AssetType: caasmmodel.AssetTypeCompute},
			{Base: coremodel.Base{ID: 900002}, Name: "e2e-seed-db", AssetType: caasmmodel.AssetTypeDatabase},
		}, nil)
	assetService := service.NewAssetService(repo, nil)
	h := New(assetService, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil)
	router.GET("/relationships/graph", h.GetRelationshipGraph)

	req := httptest.NewRequest(http.MethodGet, "/relationships/graph", nil)
	w := httptest.NewRecorder()

	router.ServeHTTP(w, req)

	require.Equal(t, http.StatusOK, w.Code)
	var body struct {
		Code int `json:"code"`
		Data struct {
			Nodes []struct {
				ID    string `json:"id"`
				Label string `json:"label"`
				Type  string `json:"type"`
			} `json:"nodes"`
			Edges []struct {
				Source string `json:"source"`
				Target string `json:"target"`
				Label  string `json:"label"`
			} `json:"edges"`
		} `json:"data"`
	}
	require.NoError(t, json.Unmarshal(w.Body.Bytes(), &body))
	require.Equal(t, 0, body.Code)
	require.Len(t, body.Data.Nodes, 2)
	require.Len(t, body.Data.Edges, 1)
	require.Equal(t, "900001", body.Data.Edges[0].Source)
	require.Equal(t, "900002", body.Data.Edges[0].Target)
	require.Equal(t, "e2e-seed-connects_to", body.Data.Edges[0].Label)
	repo.AssertExpectations(t)
}

func TestPhase5RelationshipGraphRepositoryErrorReturnsInternalError(t *testing.T) {
	gin.SetMode(gin.TestMode)
	router := gin.New()
	repo := &mocks.MockAssetRepository{}
	repo.On("ListRelationships", mock.Anything, mock.Anything).
		Return(nil, errors.New("db down"))
	assetService := service.NewAssetService(repo, nil)
	h := New(assetService, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil)
	router.GET("/relationships/graph", h.GetRelationshipGraph)

	req := httptest.NewRequest(http.MethodGet, "/relationships/graph", nil)
	w := httptest.NewRecorder()

	router.ServeHTTP(w, req)

	require.Equal(t, http.StatusOK, w.Code)
	var body struct {
		Code int `json:"code"`
	}
	require.NoError(t, json.Unmarshal(w.Body.Bytes(), &body))
	require.Equal(t, http.StatusInternalServerError, body.Code)
	repo.AssertExpectations(t)
}
