package api_test

import (
	"context"
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"github.com/yaoapp/yao/agent/robot/api"
	"github.com/yaoapp/yao/agent/robot/types"
	"github.com/yaoapp/yao/agent/testutils"
)

// TestGetRobotValidation tests parameter validation for GetRobot
func TestGetRobotValidation(t *testing.T) {
	if testing.Short() {
		t.Skip("Skipping integration test")
	}

	testutils.Prepare(t)
	defer testutils.Clean(t)

	t.Run("returns error for empty member_id", func(t *testing.T) {
		ctx := types.NewContext(context.Background(), nil)
		robot, err := api.GetRobot(ctx, "")
		assert.Error(t, err)
		assert.Nil(t, robot)
		assert.Contains(t, err.Error(), "member_id is required")
	})

	t.Run("returns error for non-existent robot", func(t *testing.T) {
		ctx := types.NewContext(context.Background(), nil)
		robot, err := api.GetRobot(ctx, "non_existent_member_id_xyz")
		assert.Error(t, err)
		assert.Nil(t, robot)
	})
}

// TestListAllRobotsValidation tests parameter validation for ListAllRobots
func TestListAllRobotsValidation(t *testing.T) {
	if testing.Short() {
		t.Skip("Skipping integration test")
	}

	testutils.Prepare(t)
	defer testutils.Clean(t)

	ctx := types.NewContext(context.Background(), nil)

	t.Run("applies default pagination when query is nil", func(t *testing.T) {
		result, err := api.ListAllRobots(ctx, nil)
		assert.NoError(t, err)
		assert.NotNil(t, result)
		assert.Equal(t, 1, result.Page)
		assert.Equal(t, 20, result.PageSize)
	})

	t.Run("applies default pagination when values are zero", func(t *testing.T) {
		result, err := api.ListAllRobots(ctx, &api.ListQuery{
			Page:     0,
			PageSize: 0,
		})
		assert.NoError(t, err)
		assert.NotNil(t, result)
		assert.Equal(t, 1, result.Page)
		assert.Equal(t, 20, result.PageSize)
	})

	t.Run("caps pagesize at 100", func(t *testing.T) {
		result, err := api.ListAllRobots(ctx, &api.ListQuery{
			Page:     1,
			PageSize: 500,
		})
		assert.NoError(t, err)
		assert.NotNil(t, result)
		assert.Equal(t, 100, result.PageSize)
	})
}

// TestGetRobotStatusValidation tests parameter validation for GetRobotStatus
func TestGetRobotStatusValidation(t *testing.T) {
	if testing.Short() {
		t.Skip("Skipping integration test")
	}

	testutils.Prepare(t)
	defer testutils.Clean(t)

	t.Run("returns error for empty member_id", func(t *testing.T) {
		ctx := types.NewContext(context.Background(), nil)
		status, err := api.GetRobotStatus(ctx, "")
		assert.Error(t, err)
		assert.Nil(t, status)
		assert.Contains(t, err.Error(), "member_id is required")
	})

	t.Run("returns error for non-existent robot", func(t *testing.T) {
		ctx := types.NewContext(context.Background(), nil)
		status, err := api.GetRobotStatus(ctx, "non_existent_member_id_xyz")
		assert.Error(t, err)
		assert.Nil(t, status)
	})
}

// ==================== Robot CRUD API Tests ====================

// TestCreateRobotValidation tests parameter validation for CreateRobot
func TestCreateRobotValidation(t *testing.T) {
	if testing.Short() {
		t.Skip("Skipping integration test")
	}

	testutils.Prepare(t)
	defer testutils.Clean(t)

	ctx := types.NewContext(context.Background(), nil)

	t.Run("auto_generates_member_id_when_empty", func(t *testing.T) {
		req := &api.CreateRobotRequest{
			MemberID:    "",
			TeamID:      "team_001",
			DisplayName: "Test Robot Auto ID",
		}
		result, err := api.CreateRobot(ctx, req)
		require.NoError(t, err)
		require.NotNil(t, result)

		// Verify member_id was auto-generated (12-digit numeric)
		assert.NotEmpty(t, result.MemberID)
		assert.Len(t, result.MemberID, 12, "Auto-generated member_id should be 12 digits")

		// Cleanup
		_ = api.RemoveRobot(ctx, result.MemberID)
	})

	t.Run("returns_error_for_empty_team_id", func(t *testing.T) {
		req := &api.CreateRobotRequest{
			MemberID:    "robot_test_001",
			TeamID:      "",
			DisplayName: "Test Robot",
		}
		result, err := api.CreateRobot(ctx, req)
		assert.Error(t, err)
		assert.Nil(t, result)
		assert.Contains(t, err.Error(), "team_id is required")
	})

	t.Run("returns_error_for_empty_display_name", func(t *testing.T) {
		req := &api.CreateRobotRequest{
			MemberID:    "robot_test_001",
			TeamID:      "team_001",
			DisplayName: "",
		}
		result, err := api.CreateRobot(ctx, req)
		assert.Error(t, err)
		assert.Nil(t, result)
		assert.Contains(t, err.Error(), "display_name is required")
	})
}

// TestCreateRobot tests the CreateRobot API function
func TestCreateRobot(t *testing.T) {
	if testing.Short() {
		t.Skip("Skipping integration test")
	}

	testutils.Prepare(t)
	defer testutils.Clean(t)

	// Cleanup before and after
	cleanupAPITestRobots(t)
	defer cleanupAPITestRobots(t)

	ctx := types.NewContext(context.Background(), nil)

	t.Run("creates_robot_with_required_fields", func(t *testing.T) {
		req := &api.CreateRobotRequest{
			MemberID:    "api_robot_create_001",
			TeamID:      "api_team_001",
			DisplayName: "API Test Robot",
		}

		result, err := api.CreateRobot(ctx, req)
		require.NoError(t, err)
		require.NotNil(t, result)

		assert.Equal(t, "api_robot_create_001", result.MemberID)
		assert.Equal(t, "api_team_001", result.TeamID)
		assert.Equal(t, "API Test Robot", result.DisplayName)
		assert.Equal(t, "active", result.Status)
		assert.Equal(t, "idle", result.RobotStatus)
	})

	t.Run("creates_robot_with_all_fields", func(t *testing.T) {
		autonomousMode := true
		req := &api.CreateRobotRequest{
			MemberID:       "api_robot_create_002",
			TeamID:         "api_team_002",
			DisplayName:    "Full Robot",
			Bio:            "A fully configured robot",
			SystemPrompt:   "You are a helpful assistant",
			Avatar:         "https://example.com/avatar.png",
			RoleID:         "admin",
			ManagerID:      "user_001",
			AutonomousMode: &autonomousMode,
			RobotEmail:     "fullrobot@test.com",
			LanguageModel:  "gpt-4",
			CostLimit:      100.0,
			RobotConfig: map[string]interface{}{
				"clock_mode":     "on",
				"max_concurrent": 3,
			},
		}

		result, err := api.CreateRobot(ctx, req)
		require.NoError(t, err)
		require.NotNil(t, result)

		assert.Equal(t, "api_robot_create_002", result.MemberID)
		assert.Equal(t, "Full Robot", result.DisplayName)
		assert.Equal(t, "A fully configured robot", result.Bio)
		assert.Equal(t, "You are a helpful assistant", result.SystemPrompt)
		assert.Equal(t, "admin", result.RoleID)
		assert.True(t, result.AutonomousMode)
		assert.Equal(t, "fullrobot@test.com", result.RobotEmail)
		assert.Equal(t, "gpt-4", result.LanguageModel)
		assert.Equal(t, 100.0, result.CostLimit)
	})

	t.Run("creates_robot_with_auth_scope", func(t *testing.T) {
		req := &api.CreateRobotRequest{
			MemberID:    "api_robot_create_003",
			TeamID:      "api_team_003",
			DisplayName: "Robot with Auth",
			AuthScope: &api.AuthScope{
				CreatedBy: "user_123",
				TeamID:    "perm_team_001",
				TenantID:  "tenant_001",
			},
		}

		result, err := api.CreateRobot(ctx, req)
		require.NoError(t, err)
		require.NotNil(t, result)

		assert.Equal(t, "api_robot_create_003", result.MemberID)
		// InvitedBy should be set from AuthScope.CreatedBy
		assert.Equal(t, "user_123", result.InvitedBy)
	})

	t.Run("returns_error_for_duplicate_member_id", func(t *testing.T) {
		req := &api.CreateRobotRequest{
			MemberID:    "api_robot_create_001", // Already created above
			TeamID:      "api_team_001",
			DisplayName: "Duplicate Robot",
		}

		result, err := api.CreateRobot(ctx, req)
		assert.Error(t, err)
		assert.Nil(t, result)
		assert.Contains(t, err.Error(), "already exists")
	})
}

// TestUpdateRobot tests the UpdateRobot API function
func TestUpdateRobot(t *testing.T) {
	if testing.Short() {
		t.Skip("Skipping integration test")
	}

	testutils.Prepare(t)
	defer testutils.Clean(t)

	cleanupAPITestRobots(t)
	defer cleanupAPITestRobots(t)

	ctx := types.NewContext(context.Background(), nil)

	// Create a robot to update
	createReq := &api.CreateRobotRequest{
		MemberID:    "api_robot_update_001",
		TeamID:      "api_team_update",
		DisplayName: "Original Name",
		Bio:         "Original bio",
	}
	_, err := api.CreateRobot(ctx, createReq)
	require.NoError(t, err)

	t.Run("returns_error_for_empty_member_id", func(t *testing.T) {
		req := &api.UpdateRobotRequest{}
		result, err := api.UpdateRobot(ctx, "", req)
		assert.Error(t, err)
		assert.Nil(t, result)
		assert.Contains(t, err.Error(), "member_id is required")
	})

	t.Run("returns_error_for_non_existent_robot", func(t *testing.T) {
		newName := "New Name"
		req := &api.UpdateRobotRequest{
			DisplayName: &newName,
		}
		result, err := api.UpdateRobot(ctx, "non_existent_robot", req)
		assert.Error(t, err)
		assert.Nil(t, result)
	})

	t.Run("updates_display_name", func(t *testing.T) {
		newName := "Updated Name"
		req := &api.UpdateRobotRequest{
			DisplayName: &newName,
		}

		result, err := api.UpdateRobot(ctx, "api_robot_update_001", req)
		require.NoError(t, err)
		require.NotNil(t, result)

		assert.Equal(t, "Updated Name", result.DisplayName)
		// Bio should be unchanged
		assert.Equal(t, "Original bio", result.Bio)
	})

	t.Run("updates_multiple_fields", func(t *testing.T) {
		newBio := "New bio description"
		newPrompt := "Updated system prompt"
		autonomousMode := true

		req := &api.UpdateRobotRequest{
			Bio:            &newBio,
			SystemPrompt:   &newPrompt,
			AutonomousMode: &autonomousMode,
		}

		result, err := api.UpdateRobot(ctx, "api_robot_update_001", req)
		require.NoError(t, err)
		require.NotNil(t, result)

		assert.Equal(t, "New bio description", result.Bio)
		assert.Equal(t, "Updated system prompt", result.SystemPrompt)
		assert.True(t, result.AutonomousMode)
	})

	t.Run("updates_robot_status", func(t *testing.T) {
		newStatus := "working"
		req := &api.UpdateRobotRequest{
			RobotStatus: &newStatus,
		}

		result, err := api.UpdateRobot(ctx, "api_robot_update_001", req)
		require.NoError(t, err)
		require.NotNil(t, result)

		assert.Equal(t, "working", result.RobotStatus)
	})

	t.Run("updates_config", func(t *testing.T) {
		newConfig := map[string]interface{}{
			"clock_mode":     "off",
			"max_concurrent": 5,
		}
		req := &api.UpdateRobotRequest{
			RobotConfig: newConfig,
		}

		result, err := api.UpdateRobot(ctx, "api_robot_update_001", req)
		require.NoError(t, err)
		require.NotNil(t, result)

		assert.NotNil(t, result.RobotConfig)
	})
}

// TestRemoveRobot tests the RemoveRobot API function
func TestRemoveRobot(t *testing.T) {
	if testing.Short() {
		t.Skip("Skipping integration test")
	}

	testutils.Prepare(t)
	defer testutils.Clean(t)

	cleanupAPITestRobots(t)
	defer cleanupAPITestRobots(t)

	ctx := types.NewContext(context.Background(), nil)

	t.Run("returns_error_for_empty_member_id", func(t *testing.T) {
		err := api.RemoveRobot(ctx, "")
		assert.Error(t, err)
		assert.Contains(t, err.Error(), "member_id is required")
	})

	t.Run("returns_error_for_non_existent_robot", func(t *testing.T) {
		err := api.RemoveRobot(ctx, "non_existent_robot")
		assert.Error(t, err)
	})

	t.Run("removes_existing_robot", func(t *testing.T) {
		// Create a robot
		createReq := &api.CreateRobotRequest{
			MemberID:    "api_robot_remove_001",
			TeamID:      "api_team_remove",
			DisplayName: "Robot to Remove",
		}
		_, err := api.CreateRobot(ctx, createReq)
		require.NoError(t, err)

		// Verify it exists
		robot, err := api.GetRobot(ctx, "api_robot_remove_001")
		require.NoError(t, err)
		require.NotNil(t, robot)

		// Remove it
		err = api.RemoveRobot(ctx, "api_robot_remove_001")
		require.NoError(t, err)

		// Verify it's gone
		robot, err = api.GetRobot(ctx, "api_robot_remove_001")
		assert.Error(t, err) // Should return error for non-existent
	})
}

// TestGetRobotResponse tests the GetRobotResponse API function
func TestGetRobotResponse(t *testing.T) {
	if testing.Short() {
		t.Skip("Skipping integration test")
	}

	testutils.Prepare(t)
	defer testutils.Clean(t)

	cleanupAPITestRobots(t)
	defer cleanupAPITestRobots(t)

	ctx := types.NewContext(context.Background(), nil)

	// Create a robot
	autonomousMode := true
	createReq := &api.CreateRobotRequest{
		MemberID:       "api_robot_response_001",
		TeamID:         "api_team_response",
		DisplayName:    "Response Test Robot",
		Bio:            "Test bio for response",
		SystemPrompt:   "Test prompt",
		AutonomousMode: &autonomousMode,
		RobotEmail:     "response@test.com",
		CostLimit:      50.0,
	}
	_, err := api.CreateRobot(ctx, createReq)
	require.NoError(t, err)

	t.Run("returns_robot_response_format", func(t *testing.T) {
		result, err := api.GetRobotResponse(ctx, "api_robot_response_001")
		require.NoError(t, err)
		require.NotNil(t, result)

		// Verify all fields are present in response
		assert.Equal(t, "api_robot_response_001", result.MemberID)
		assert.Equal(t, "api_team_response", result.TeamID)
		assert.Equal(t, "Response Test Robot", result.DisplayName)
		assert.Equal(t, "Test bio for response", result.Bio)
		assert.Equal(t, "Test prompt", result.SystemPrompt)
		assert.True(t, result.AutonomousMode)
		assert.Equal(t, "response@test.com", result.RobotEmail)
		assert.Equal(t, 50.0, result.CostLimit)
		assert.Equal(t, "active", result.Status)
		assert.Equal(t, "idle", result.RobotStatus)
	})

	t.Run("returns_error_for_non_existent", func(t *testing.T) {
		result, err := api.GetRobotResponse(ctx, "non_existent")
		assert.Error(t, err)
		assert.Nil(t, result)
	})
}

// Note: cleanupAPITestRobots is defined in api_test.go (shared helper)
