// Regression test: OAuth accountId must flow into model fetch as saeeolOrganizationId
// When a user logs in via OAuth and selects an enterprise organization, the model fetch
// should use the organization-specific endpoint, not the personal endpoint.

import { test, expect, mock } from "bun:test"
import { Effect } from "effect"
import path from "path"
import * as Log from "@saeeol/core/util/log"

Log.init({ print: false })

// Capture the options passed to fetchSaeeolModels
let captured: any = undefined

mock.module("@saeeol/gateway", () => ({
  fetchSaeeolModels: async (options: any) => {
    captured = options
    return {
      models: {
        "test-model": {
          id: "test-model",
          name: "Test Model",
          cost: { input: 0.001, output: 0.002 },
          limit: { context: 128000, output: 4096 },
        },
      },
    }
  },
  SAEEOL_OPENROUTER_BASE: "https://api.saeeol.ai/api/openrouter",
}))

// Mock default plugins to prevent actual installations during tests
const mockPlugin = () => ({})
mock.module("saeeol-copilot-auth", () => ({ default: mockPlugin }))
mock.module("saeeol-anthropic-auth", () => ({ default: mockPlugin }))
mock.module("@gitlab/saeeol-gitlab-auth", () => ({ default: mockPlugin }))

import { tmpdir } from "../fixture/fixture"
import { Instance } from "../../src/project/instance"
import { Auth } from "../../src/auth"
import { ModelCache } from "../../src/provider/model-cache"

test("model fetch uses accountId from OAuth auth as saeeolOrganizationId", async () => {
  await using tmp = await tmpdir({
    init: async (dir) => {
      await Bun.write(
        path.join(dir, "saeeol.json"),
        JSON.stringify({
          $schema: "https://app.saeeol.ai/config.json",
        }),
      )
    },
  })
  await Instance.provide({
    directory: tmp.path,
    init: Effect.promise(async () => {
      // Simulate an OAuth login where user selected an enterprise organization
      await Auth.set("saeeol", {
        type: "oauth",
        access: "test-oauth-token",
        refresh: "test-refresh-token",
        expires: Date.now() + 3600000,
        accountId: "org-enterprise-123",
      })
    }).pipe(Effect.asVoid),
    fn: async () => {
      // Reset captured and cache
      captured = undefined
      ModelCache.clear("saeeol")

      // Trigger model fetch through the cache
      await ModelCache.fetch("saeeol")

      // The fetchSaeeolModels call should have received the organization ID
      expect(captured).toBeDefined()
      expect(captured.saeeolToken).toBe("test-oauth-token")
      expect(captured.saeeolOrganizationId).toBe("org-enterprise-123")
    },
  })
})

test("model fetch without OAuth accountId does not set saeeolOrganizationId", async () => {
  await using tmp = await tmpdir({
    init: async (dir) => {
      await Bun.write(
        path.join(dir, "saeeol.json"),
        JSON.stringify({
          $schema: "https://app.saeeol.ai/config.json",
        }),
      )
    },
  })
  await Instance.provide({
    directory: tmp.path,
    init: Effect.promise(async () => {
      // Simulate an OAuth login for a personal account (no accountId)
      await Auth.set("saeeol", {
        type: "oauth",
        access: "test-personal-token",
        refresh: "test-refresh-token",
        expires: Date.now() + 3600000,
      })
    }).pipe(Effect.asVoid),
    fn: async () => {
      captured = undefined
      ModelCache.clear("saeeol")

      await ModelCache.fetch("saeeol")

      expect(captured).toBeDefined()
      expect(captured.saeeolToken).toBe("test-personal-token")
      expect(captured.saeeolOrganizationId).toBeUndefined()
    },
  })
})

test("ModelCache.clear removes cached entry so next fetch hits the network", async () => {
  await using tmp = await tmpdir({
    init: async (dir) => {
      await Bun.write(
        path.join(dir, "saeeol.json"),
        JSON.stringify({
          $schema: "https://app.saeeol.ai/config.json",
        }),
      )
    },
  })
  await Instance.provide({
    directory: tmp.path,
    init: Effect.promise(async () => {
      await Auth.set("saeeol", {
        type: "oauth",
        access: "token-clear-test",
        refresh: "refresh-clear",
        expires: Date.now() + 3600000,
        accountId: "org-clear",
      })
    }).pipe(Effect.asVoid),
    fn: async () => {
      // Populate cache
      captured = undefined
      ModelCache.clear("saeeol")
      await ModelCache.fetch("saeeol")
      expect(captured).toBeDefined()

      // Verify cache is populated — second fetch should NOT call fetchSaeeolModels
      captured = undefined
      await ModelCache.fetch("saeeol")
      expect(captured).toBeUndefined()
      expect(ModelCache.get("saeeol")).toBeDefined()

      // Clear the cache
      ModelCache.clear("saeeol")

      // get() should return undefined after clear
      expect(ModelCache.get("saeeol")).toBeUndefined()

      // Next fetch should call fetchSaeeolModels again
      captured = undefined
      await ModelCache.fetch("saeeol")
      expect(captured).toBeDefined()
    },
  })
})
