package exec

import (
	"context"
	"encoding/json"
	"io"
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/stretchr/testify/require"

	"github.com/tidbcloud/AgentTeam/desktop/internal/wire/apiclient"
)

func TestScheduledMessageRealRuntimeAndExecDataContract(t *testing.T) {
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		switch {
		case r.URL.Path == "/api/v1/workspaces/ws/agents/ag/runtime/schedules/validate":
			_, _ = io.WriteString(w, `{
				"current":{"id":"sch_1","name":"before","status":"active","sourceKind":"time","timeMode":"interval","intervalSeconds":60,"target":{"kind":"channel","ref":"chn_1"},"messageTemplate":"before","humanNotificationMode":"none","createdAt":"2026-07-25T00:00:00Z","updatedAt":"2026-07-25T00:01:00Z","validation":{"valid":true}},
				"proposed":{"id":"sch_1","name":"after","status":"active","sourceKind":"time","timeMode":"interval","intervalSeconds":120,"target":{"kind":"channel","ref":"chn_1"},"messageTemplate":"after","humanNotificationMode":"none","createdAt":"2026-07-25T00:00:00Z","updatedAt":"2026-07-25T00:02:00Z","validation":{"valid":true}},
				"estimatedScheduledAt":"2026-07-25T00:04:00Z"
			}`)
		case r.URL.Path == "/api/v1/workspaces/ws/agents/ag/runtime/schedules/sch_1/runs":
			_, _ = io.WriteString(w, `[{
				"id":"run_1","scheduleId":"sch_1","workspaceId":"ws","idempotencyKey":"idem_1",
				"sourceOccurrenceRef":"occ_1","sourceKind":"time","timeMode":"interval","status":"succeeded",
				"scheduledFor":"2026-07-25T00:03:00Z","occurredAt":"2026-07-25T00:03:01Z",
				"attemptedAt":"2026-07-25T00:03:02Z","completedAt":"2026-07-25T00:03:03Z",
				"messageId":"msg_1","renderedContentPreview":"hello","attemptCount":1,
				"target":{"kind":"channel","ref":"chn_1"},"scheduleName":"after"
			}]`)
		default:
			_, _ = io.WriteString(w, `{
				"id":"sch_1","name":"after","status":"active","sourceKind":"time","timeMode":"interval",
				"intervalSeconds":120,"target":{"kind":"channel","ref":"chn_1","label":"Ops"},
				"messageTemplate":"after","alsoStartThread":true,"humanNotificationMode":"none",
				"nextOccurrenceAt":"2026-07-25T00:04:00Z","createdAt":"2026-07-25T00:00:00Z",
				"updatedAt":"2026-07-25T00:02:00Z","validation":{"valid":true}
			}`)
		}
	}))
	t.Cleanup(server.Close)

	authorized := runtimeAuthorization{Server: &apiclient.Client{
		ServerURL: server.URL, RouteWorkspaceID: "ws", AgentID: "ag",
		AuthToken: "token", HTTPClient: server.Client(),
	}}
	handler := scheduledMessageHandler{}

	get, err := handler.get(context.Background(), actionScopedJSON[scheduledMessageIDRequest]{
		Authorized: authorized,
		Body:       scheduledMessageIDRequest{ID: "sch_1"},
	})
	require.NoError(t, err)
	getData := scheduledMessageResultData(t, get)
	require.Equal(t, "sch_1", getData["id"])
	require.Equal(t, "after", getData["template"])
	require.Equal(t, true, getData["startThread"])
	require.Equal(t, "every", getData["schedule"].(map[string]any)["kind"])
	require.Equal(t, float64(120), getData["schedule"].(map[string]any)["seconds"])
	require.NotContains(t, getData, "sourceKind")
	require.NotContains(t, getData, "timeMode")
	require.NotContains(t, getData, "intervalSeconds")
	require.NotContains(t, getData, "messageTemplate")
	require.NotContains(t, getData, "alsoStartThread")
	require.NotContains(t, getData, "scheduledMessage")
	require.NotContains(t, getData, "source")

	write := validScheduledMessageWriteRequest("after")
	created, err := handler.create(context.Background(), actionScopedJSON[scheduledMessageCreateRequest]{
		Authorized: authorized,
		Body:       scheduledMessageCreateRequest{scheduledMessageWriteRequest: write},
	})
	require.NoError(t, err)
	require.Equal(t, "sch_1", scheduledMessageResultData(t, created)["id"])

	validated, err := handler.validate(context.Background(), actionScopedJSON[scheduledMessageValidateRequest]{
		Authorized: authorized,
		Body:       scheduledMessageValidateRequest{scheduledMessageWriteRequest: write},
	})
	require.NoError(t, err)
	validateData := scheduledMessageResultData(t, validated)
	require.Equal(t, "before", validateData["current"].(map[string]any)["name"])
	require.Equal(t, "after", validateData["proposed"].(map[string]any)["name"])
	require.Equal(t, "2026-07-25T00:04:00Z", validateData["estimatedScheduledAt"])
	require.NotContains(t, validateData, "valid")
	require.NotContains(t, validateData, "scheduledMessage")

	runs, err := handler.runs(context.Background(), actionScopedJSON[scheduledMessageRunsRequest]{
		Authorized: authorized,
		Body:       scheduledMessageRunsRequest{ID: "sch_1"},
	})
	require.NoError(t, err)
	encoded, err := json.Marshal(runs)
	require.NoError(t, err)
	var runsEnvelope struct {
		Data struct {
			Runs []map[string]any `json:"runs"`
		} `json:"data"`
	}
	require.NoError(t, json.Unmarshal(encoded, &runsEnvelope))
	require.Len(t, runsEnvelope.Data.Runs, 1)
	require.Equal(t, "2026-07-25T00:03:02Z", runsEnvelope.Data.Runs[0]["attemptedAt"])
	require.Equal(t, "2026-07-25T00:03:03Z", runsEnvelope.Data.Runs[0]["completedAt"])
	require.NotContains(t, runsEnvelope.Data.Runs[0], "startedAt")
	require.NotContains(t, runsEnvelope.Data.Runs[0], "finishedAt")
}

func scheduledMessageResultData(t *testing.T, result any) map[string]any {
	t.Helper()
	encoded, err := json.Marshal(result)
	require.NoError(t, err)
	var envelope struct {
		Data map[string]any `json:"data"`
	}
	require.NoError(t, json.Unmarshal(encoded, &envelope))
	return envelope.Data
}
