package service

import (
	"context"
	"testing"
	"time"

	"github.com/stretchr/testify/require"

	"security-center-backend/internal/modules/department/model"
)

type fakeOrgSyncRunRepository struct {
	latest *model.OrgSyncRun
}

func (f *fakeOrgSyncRunRepository) Create(ctx context.Context, run *model.OrgSyncRun) error {
	return nil
}

func (f *fakeOrgSyncRunRepository) Update(ctx context.Context, run *model.OrgSyncRun) error {
	return nil
}

func (f *fakeOrgSyncRunRepository) ListRecent(ctx context.Context, limit int) ([]model.OrgSyncRun, error) {
	return []model.OrgSyncRun{}, nil
}

func (f *fakeOrgSyncRunRepository) LatestSuccessful(ctx context.Context) (*model.OrgSyncRun, error) {
	if f.latest == nil {
		return nil, nil
	}
	copy := *f.latest
	return &copy, nil
}

func TestRuntimeStatusUsesDefaultFreshnessPolicy(t *testing.T) {
	runtime := NewOrgSyncRuntimeControl(NewDepartmentService(nil, nil, nil, nil), nil)

	status := runtime.Status()

	require.Equal(t, 24, status.StaleAfterHours)
	require.Equal(t, 72, status.ExpiredAfterHours)
}

func TestRuntimeStatusUsesConfiguredFreshnessPolicy(t *testing.T) {
	runtime := NewOrgSyncRuntimeControl(NewDepartmentService(nil, nil, nil, nil), nil)
	runtime.SetFreshnessPolicy(FreshnessPolicy{StaleAfterHours: 48, ExpiredAfterHours: 168})

	status := runtime.Status()

	require.Equal(t, 48, status.StaleAfterHours)
	require.Equal(t, 168, status.ExpiredAfterHours)
}

func TestEvaluateFreshnessUsesConfiguredPolicy(t *testing.T) {
	now := time.Date(2026, 5, 13, 12, 0, 0, 0, time.UTC)
	finishedAt := now.Add(-36 * time.Hour)
	runRepo := &fakeOrgSyncRunRepository{
		latest: &model.OrgSyncRun{FinishedAt: &finishedAt},
	}
	runtime := NewOrgSyncRuntimeControl(NewDepartmentService(nil, nil, runRepo, nil), nil)

	defaultPolicyEval, err := runtime.evaluateFreshness(context.Background(), now, DefaultFreshnessPolicy())
	require.NoError(t, err)
	require.Equal(t, freshnessStale, defaultPolicyEval.FreshnessState)
	require.Equal(t, []string{"department_fanout", "team_fanout"}, defaultPolicyEval.BlockingScopes)

	extendedPolicyEval, err := runtime.evaluateFreshness(context.Background(), now, FreshnessPolicy{
		StaleAfterHours:   48,
		ExpiredAfterHours: 168,
	})
	require.NoError(t, err)
	require.Equal(t, freshnessFresh, extendedPolicyEval.FreshnessState)
	require.Empty(t, extendedPolicyEval.BlockingScopes)
}

func TestRuntimeStatusExpiresUsingConfiguredPolicy(t *testing.T) {
	now := time.Now().UTC()
	finishedAt := now.Add(-100 * time.Hour)
	runRepo := &fakeOrgSyncRunRepository{
		latest: &model.OrgSyncRun{FinishedAt: &finishedAt},
	}
	runtime := NewOrgSyncRuntimeControl(NewDepartmentService(nil, nil, runRepo, nil), nil)
	runtime.SetFreshnessPolicy(FreshnessPolicy{StaleAfterHours: 48, ExpiredAfterHours: 168})

	status := runtime.Status()

	require.Equal(t, freshnessStale, status.FreshnessState)
	require.Equal(t, 48, status.StaleAfterHours)
	require.Equal(t, 168, status.ExpiredAfterHours)
	require.NotContains(t, status.BlockingScopes, "picker_reads")
}
