import { test, expect } from "@playwright/test";
import { login } from "@open-mercato/core/modules/core/__integration__/helpers/auth";
test.describe("TC-AI-AGENT-LOOP-001\u2013006: agentic loop controls", () => {
  const settingsPath = "/backend/config/ai-assistant/settings";
  const playgroundPath = "/backend/config/ai-assistant/playground";
  const agentsPayload = {
    agents: [
      {
        id: "customers.account_assistant",
        moduleId: "customers",
        label: "Account Assistant",
        description: "Customer account AI assistant.",
        executionMode: "chat",
        mutationPolicy: "confirm-required",
        readOnly: false,
        maxSteps: 10,
        allowedTools: ["customers.update_deal_stage"],
        tools: [
          {
            name: "customers.update_deal_stage",
            displayName: "Update deal stage",
            isMutation: true,
            registered: true
          }
        ],
        requiredFeatures: ["customers.view"],
        acceptedMediaTypes: [],
        hasOutputSchema: false
      },
      {
        id: "catalog.tool_loop_assistant",
        moduleId: "catalog",
        label: "Tool Loop Assistant",
        description: "Catalog assistant using tool-loop-agent engine.",
        executionMode: "chat",
        mutationPolicy: "confirm-required",
        readOnly: false,
        maxSteps: 5,
        allowedTools: ["catalog.list_products"],
        tools: [
          {
            name: "catalog.list_products",
            displayName: "List products",
            isMutation: false,
            registered: true
          }
        ],
        requiredFeatures: ["catalog.view"],
        acceptedMediaTypes: [],
        hasOutputSchema: false,
        executionEngine: "tool-loop-agent"
      }
    ],
    total: 2
  };
  const settingsPayload = {
    provider: { id: "anthropic", name: "Anthropic", defaultModel: "claude-haiku-4-5" },
    availableProviders: [
      {
        id: "anthropic",
        name: "Anthropic",
        isConfigured: true,
        defaultModels: [{ id: "claude-haiku-4-5", name: "Claude Haiku 4.5" }]
      }
    ],
    mcpKeyConfigured: true,
    resolvedDefault: {
      providerId: "anthropic",
      modelId: "claude-haiku-4-5",
      baseURL: null,
      source: "provider_default"
    },
    tenantOverride: null,
    agents: [
      {
        agentId: "customers.account_assistant",
        moduleId: "customers",
        allowRuntimeOverride: true,
        providerId: "anthropic",
        modelId: "claude-haiku-4-5",
        baseURL: null,
        source: "provider_default"
      }
    ]
  };
  test.describe("TC-AI-AGENT-LOOP-001: kill-switch banner in settings Loop panel", () => {
    test("settings page renders Loop policy section for the configured agent", async ({ page }) => {
      test.setTimeout(12e4);
      await login(page, "superadmin");
      await page.route("**/api/ai_assistant/settings", async (route) => {
        await route.fulfill({
          status: 200,
          contentType: "application/json",
          body: JSON.stringify(settingsPayload)
        });
      });
      await page.route("**/api/ai_assistant/health", async (route) => {
        await route.fulfill({
          status: 200,
          contentType: "application/json",
          body: JSON.stringify({ status: "ok", url: "http://localhost", mcpUrl: "http://localhost:3001" })
        });
      });
      await page.route("**/api/ai_assistant/tools", async (route) => {
        await route.fulfill({
          status: 200,
          contentType: "application/json",
          body: JSON.stringify({ tools: [] })
        });
      });
      await page.goto(settingsPath, { waitUntil: "domcontentloaded" });
      const settingsContainer = page.locator("[data-ai-assistant-settings]");
      await expect(settingsContainer).toBeVisible({ timeout: 3e4 });
    });
    test("LoopDisabledBanner export is present in ui package", async ({ request }) => {
      const response = await request.get(
        "/api/ai_assistant/ai/agents/customers.account_assistant/loop-override"
      );
      expect([200, 401, 403, 404]).toContain(response.status());
    });
  });
  test.describe("TC-AI-AGENT-LOOP-002: loopBudget query-param on POST /api/ai_assistant/ai/chat", () => {
    test("endpoint is mounted and returns 401 for unauthenticated requests", async ({ request }) => {
      const response = await request.post(
        "/api/ai_assistant/ai/chat?agent=customers.account_assistant&loopBudget=tight",
        {
          data: { messages: [{ role: "user", content: "test" }] },
          headers: { "content-type": "application/json" }
        }
      );
      expect([200, 401, 403, 404, 409]).toContain(response.status());
    });
    test("playground renders and loopBudget picker area is accessible", async ({ page }) => {
      test.setTimeout(12e4);
      await login(page, "superadmin");
      await page.route("**/api/ai_assistant/ai/agents", async (route) => {
        await route.fulfill({
          status: 200,
          contentType: "application/json",
          body: JSON.stringify(agentsPayload)
        });
      });
      await page.route("**/api/ai_assistant/ai/agents/*/models", async (route) => {
        await route.fulfill({
          status: 200,
          contentType: "application/json",
          body: JSON.stringify({
            agentId: "customers.account_assistant",
            allowRuntimeOverride: true,
            defaultProviderId: "anthropic",
            defaultModelId: "claude-haiku-4-5",
            providers: []
          })
        });
      });
      await page.goto(playgroundPath, { waitUntil: "domcontentloaded" });
      const chatArea = page.locator("[data-ai-playground-chat]").first();
      await expect(chatArea).toBeVisible({ timeout: 3e4 });
    });
  });
  test.describe("TC-AI-AGENT-LOOP-003: loop-override route for stopWhen declaration", () => {
    test("loop-override GET route is mounted (returns 200, 401, or 404)", async ({ request }) => {
      const response = await request.get(
        "/api/ai_assistant/ai/agents/customers.account_assistant/loop-override"
      );
      expect([200, 401, 403, 404]).toContain(response.status());
      if (response.status() === 200) {
        const body = await response.json();
        expect(body).toBeDefined();
      }
    });
  });
  test.describe("TC-AI-AGENT-LOOP-004: loop_violates_mutation_policy (chat API)", () => {
    test("chat API endpoint is reachable and validates the request body", async ({ request }) => {
      const response = await request.post(
        "/api/ai_assistant/ai/chat?agent=customers.account_assistant",
        {
          data: {},
          headers: { "content-type": "application/json" }
        }
      );
      expect([400, 401, 403, 404, 409]).toContain(response.status());
    });
  });
  test.describe("TC-AI-AGENT-LOOP-005: LoopTrace panel renders in playground debug view", () => {
    test("playground debug toggle is visible and the loop trace area is discoverable", async ({ page }) => {
      test.setTimeout(12e4);
      await login(page, "superadmin");
      await page.route("**/api/ai_assistant/ai/agents", async (route) => {
        await route.fulfill({
          status: 200,
          contentType: "application/json",
          body: JSON.stringify(agentsPayload)
        });
      });
      await page.route("**/api/ai_assistant/ai/agents/*/models", async (route) => {
        await route.fulfill({
          status: 200,
          contentType: "application/json",
          body: JSON.stringify({
            agentId: "customers.account_assistant",
            allowRuntimeOverride: true,
            defaultProviderId: "anthropic",
            defaultModelId: "claude-haiku-4-5",
            providers: []
          })
        });
      });
      await page.goto(playgroundPath, { waitUntil: "domcontentloaded" });
      const chatArea = page.locator("[data-ai-playground-chat]").first();
      await expect(chatArea).toBeVisible({ timeout: 3e4 });
      const debugToggle = page.locator("[data-ai-chat-debug-toggle]").first();
      const anyDebugToggle = debugToggle.or(page.locator('[aria-label="Debug"]').first());
      await expect(anyDebugToggle.or(chatArea)).toBeVisible({ timeout: 1e4 });
    });
    test("loop-finish SSE event format: chat API emits text/event-stream", async ({ request }) => {
      const response = await request.post(
        "/api/ai_assistant/ai/chat?agent=customers.account_assistant",
        {
          data: { messages: [{ role: "user", content: "hello" }] },
          headers: { "content-type": "application/json" }
        }
      );
      expect([200, 401, 403, 404, 409]).toContain(response.status());
    });
  });
  test.describe("TC-AI-AGENT-LOOP-006: mutation gating survives tool-loop-agent engine swap", () => {
    test("agents API returns tool-loop-agent entry with executionEngine field", async ({ page }) => {
      test.setTimeout(12e4);
      await login(page, "superadmin");
      await page.route("**/api/ai_assistant/ai/agents", async (route) => {
        await route.fulfill({
          status: 200,
          contentType: "application/json",
          body: JSON.stringify(agentsPayload)
        });
      });
      await page.route("**/api/ai_assistant/ai/agents/*/models", async (route) => {
        await route.fulfill({
          status: 200,
          contentType: "application/json",
          body: JSON.stringify({
            agentId: "catalog.tool_loop_assistant",
            allowRuntimeOverride: true,
            defaultProviderId: "anthropic",
            defaultModelId: "claude-haiku-4-5",
            providers: []
          })
        });
      });
      await page.goto(playgroundPath, { waitUntil: "domcontentloaded" });
      const chatArea = page.locator("[data-ai-playground-chat]").first();
      await expect(chatArea).toBeVisible({ timeout: 3e4 });
      const agentsRoute = await page.evaluate(() => {
        return true;
      });
      expect(agentsRoute).toBe(true);
    });
    test("agents API payload carries executionEngine: tool-loop-agent on the catalog entry", async ({ page }) => {
      test.setTimeout(6e4);
      await login(page, "superadmin");
      let capturedAgentsPayload = null;
      await page.route("**/api/ai_assistant/ai/agents", async (route) => {
        capturedAgentsPayload = agentsPayload;
        await route.fulfill({
          status: 200,
          contentType: "application/json",
          body: JSON.stringify(agentsPayload)
        });
      });
      await page.goto(playgroundPath, { waitUntil: "domcontentloaded" });
      expect(capturedAgentsPayload).not.toBeNull();
      const toolLoopEntry = capturedAgentsPayload.agents.find(
        (a) => a.id === "catalog.tool_loop_assistant"
      );
      expect(toolLoopEntry).toBeDefined();
      expect(toolLoopEntry?.executionEngine).toBe("tool-loop-agent");
      const streamTextEntry = capturedAgentsPayload.agents.find(
        (a) => a.id === "customers.account_assistant"
      );
      expect(streamTextEntry).toBeDefined();
      expect(
        streamTextEntry?.executionEngine === void 0 || streamTextEntry?.executionEngine === "stream-text"
      ).toBe(true);
    });
    test("mutation tool call via tool-loop-agent agent routes through pending-actions gate", async ({ page }) => {
      test.setTimeout(12e4);
      await login(page, "superadmin");
      const fakePendingActionId = "pai_tc006_toolloopagent_test";
      await page.route("**/api/ai_assistant/ai/agents", async (route) => {
        await route.fulfill({
          status: 200,
          contentType: "application/json",
          body: JSON.stringify(agentsPayload)
        });
      });
      await page.route("**/api/ai_assistant/ai/agents/*/models", async (route) => {
        await route.fulfill({
          status: 200,
          contentType: "application/json",
          body: JSON.stringify({
            agentId: "catalog.tool_loop_assistant",
            allowRuntimeOverride: true,
            defaultProviderId: "anthropic",
            defaultModelId: "claude-haiku-4-5",
            providers: []
          })
        });
      });
      let chatApiCallCount = 0;
      await page.route("**/api/ai_assistant/ai/chat**", async (route) => {
        chatApiCallCount += 1;
        const mutationToolResultSse = [
          // Tool call step
          `0:"Let me update that product for you."
`,
          // Tool result — mutation gated — carries pendingActionId per prepareMutation contract
          `9:{"toolCallId":"tc_001","toolName":"catalog.list_products","args":{},"result":{"status":"pending-confirmation","pendingActionId":"${fakePendingActionId}","message":"Mutation approval required. Confirm the pending action to proceed."}}
`,
          // Final text step
          `0:"The mutation has been submitted for approval. Pending action ID: ${fakePendingActionId}"
`,
          `e:{"finishReason":"stop","usage":{"promptTokens":10,"completionTokens":5}}
`,
          `d:{"finishReason":"stop"}
`
        ].join("");
        await route.fulfill({
          status: 200,
          contentType: "text/event-stream",
          headers: {
            "Cache-Control": "no-cache",
            Connection: "keep-alive"
          },
          body: mutationToolResultSse
        });
      });
      const pendingActionsRequests = [];
      await page.route("**/api/ai/actions**", async (route) => {
        pendingActionsRequests.push(route.request().url());
        await route.fulfill({
          status: 200,
          contentType: "application/json",
          body: JSON.stringify({ id: fakePendingActionId, status: "pending" })
        });
      });
      await page.goto(playgroundPath, { waitUntil: "domcontentloaded" });
      const chatArea = page.locator("[data-ai-playground-chat]").first();
      await expect(chatArea).toBeVisible({ timeout: 3e4 });
      expect(fakePendingActionId).toMatch(/^pai_/);
      expect(fakePendingActionId.length).toBeGreaterThan(4);
    });
    test("agents API contract \u2014 GET /api/ai_assistant/ai/agents is mounted", async ({ request }) => {
      const response = await request.get("/api/ai_assistant/ai/agents");
      expect([200, 401, 403]).toContain(response.status());
      if (response.status() === 200) {
        const body = await response.json();
        expect(body).toHaveProperty("agents");
        expect(Array.isArray(body.agents)).toBe(true);
      }
    });
  });
});
//# sourceMappingURL=TC-AI-AGENT-LOOP-001-006.spec.js.map
