package input_test

import (
	"context"
	"errors"
	"testing"
	"time"

	"iop/apps/edge/internal/authprojection"
	edgeinput "iop/apps/edge/internal/input"
	edgeservice "iop/apps/edge/internal/service"
	"iop/packages/go/config"
	iop "iop/proto/gen/iop"

	"go.uber.org/zap"
)

func newTestService() *edgeservice.Service {
	return edgeservice.New(nil, nil)
}

func TestManagerDisabledCredentialPlaneHasNoProjectionSource(t *testing.T) {
	cfg := config.EdgeConfig{
		OpenAI: config.EdgeOpenAIConf{Enabled: false},
		A2A:    config.EdgeA2AConf{Enabled: false},
	}
	mgr := edgeinput.NewManager(cfg, newTestService(), zap.NewNop())
	if projection := mgr.PrincipalProjection(); projection != nil {
		t.Fatal("disabled credential plane exposed a managed projection source")
	}
	if got := mgr.OpenAI.PrincipalProjection(); got != nil {
		t.Fatal("disabled OpenAI server received a managed projection source")
	}
	if mgr.OpenAI.CredentialPlaneManaged() {
		t.Fatal("disabled credential plane selected managed ingress mode")
	}
}

func TestManagerEnabledCredentialPlaneSharesProjectionWithOpenAI(t *testing.T) {
	cfg := config.EdgeConfig{
		CredentialPlane: config.EdgeCredentialPlaneConf{Enabled: true},
		OpenAI:          config.EdgeOpenAIConf{Enabled: false},
		A2A:             config.EdgeA2AConf{Enabled: false},
	}
	mgr := edgeinput.NewManager(cfg, newTestService(), zap.NewNop())
	projection := mgr.PrincipalProjection()
	if projection == nil {
		t.Fatal("enabled credential plane did not create a projection source")
	}
	if state := projection.State(); state != authprojection.StateUnmanaged {
		t.Fatalf("default projection state: got %s", state)
	}
	if got := mgr.OpenAI.PrincipalProjection(); got != projection {
		t.Fatal("OpenAI server does not use the Manager projection instance")
	}
	if !mgr.OpenAI.CredentialPlaneManaged() {
		t.Fatal("enabled credential plane did not select managed ingress mode")
	}

	now := time.Now().UTC()
	if err := projection.Apply(&iop.PrincipalProjection{
		Generation: 1, IssuedAtUnixNano: now.UnixNano(), ExpiresAtUnixNano: now.Add(time.Minute).UnixNano(),
	}); err != nil {
		t.Fatal(err)
	}
	if state := mgr.OpenAI.PrincipalProjection().State(); state != authprojection.StateFresh {
		t.Fatalf("shared projection state: got %s", state)
	}
}

func TestManagerOwnsOpenAIAndA2AInputs(t *testing.T) {
	cfg := config.EdgeConfig{
		OpenAI: config.EdgeOpenAIConf{Enabled: false},
		A2A:    config.EdgeA2AConf{Enabled: false},
	}
	mgr := edgeinput.NewManager(cfg, newTestService(), zap.NewNop())
	if mgr == nil {
		t.Fatal("NewManager returned nil")
	}
	if mgr.OpenAI == nil {
		t.Fatal("Manager.OpenAI is nil")
	}
	if mgr.A2A == nil {
		t.Fatal("Manager.A2A is nil")
	}
}

func TestManagerStartStopDisabled(t *testing.T) {
	cfg := config.EdgeConfig{
		OpenAI: config.EdgeOpenAIConf{Enabled: false},
		A2A:    config.EdgeA2AConf{Enabled: false},
	}
	mgr := edgeinput.NewManager(cfg, newTestService(), zap.NewNop())
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	if err := mgr.Start(ctx); err != nil {
		t.Fatalf("Start disabled: %v", err)
	}
	if err := mgr.Stop(ctx); err != nil {
		t.Fatalf("Stop disabled: %v", err)
	}
}

func TestManagerInstallsSingleRequestExecutor(t *testing.T) {
	svc := newTestService()
	_, errBefore := svc.StartSingleRequest(context.Background(), edgeservice.SingleRequestRequest{
		RequestID: "req-before-install",
	})
	if !errors.Is(errBefore, edgeservice.ErrSingleRequestExecutorUnavailable) {
		t.Fatalf("before NewManager: got err = %v, want ErrSingleRequestExecutorUnavailable", errBefore)
	}

	cfg := config.EdgeConfig{
		OpenAI: config.EdgeOpenAIConf{Enabled: false},
		A2A:    config.EdgeA2AConf{Enabled: false},
	}
	_ = edgeinput.NewManager(cfg, svc, zap.NewNop())

	_, errAfter := svc.StartSingleRequest(context.Background(), edgeservice.SingleRequestRequest{
		RequestID: "req-after-install",
	})
	if errors.Is(errAfter, edgeservice.ErrSingleRequestExecutorUnavailable) {
		t.Fatalf("after NewManager: got ErrSingleRequestExecutorUnavailable, want installed executor")
	}
}
