//
// Tests that the saeeol custom loader keeps paid models visible without authentication.
// Mocks fetchSaeeolModels from @saeeol/gateway to avoid real network
// calls (which fail on Windows CI).

import { test, expect, mock } from "bun:test"
import path from "path"
import { unlink } from "fs/promises"

// Bun's mock.module() is process-wide and permanent — it replaces the module
// for ALL test files in the same runner process. To avoid breaking other tests
// that import @saeeol/gateway, we spread the real exports and only
// override fetchSaeeolModels with a stub that returns both free and paid models.
const real = await import("@saeeol/gateway")

mock.module("@saeeol/gateway", () => ({
  ...real,
  fetchSaeeolModels: async () => ({
    models: {
      "free-model": {
        id: "free-model",
        name: "Free Model",
        cost: { input: 0, output: 0 },
        limit: { context: 128000, output: 4096 },
      },
      "paid-model": {
        id: "paid-model",
        name: "Paid Model",
        cost: { input: 1.0, output: 2.0 },
        limit: { context: 128000, output: 4096 },
      },
    },
  }),
}))

import { tmpdir } from "../fixture/fixture"
import { Global } from "@saeeol/core/global"
import { Instance } from "../../src/project/instance"
import { Provider } from "../../src/provider/provider"
import { ProviderID } from "../../src/provider/schema"
import { Filesystem } from "../../src/util/filesystem"
import { ModelCache } from "../../src/provider/model-cache"
import { Auth } from "../../src/auth"

function paid(providers: Awaited<ReturnType<typeof Provider.list>>) {
  const item = providers[ProviderID.saeeol]
  expect(item).toBeDefined()
  return Object.values(item.models).filter((model) => model.cost.input > 0).length
}

test("saeeol loader keeps paid models without auth and when config apiKey is present", async () => {
  // Reset state that may be stale from other test files sharing this process.
  // Auth.set from other tests persists in the shared auth.json,
  // and ModelCache keeps fetched models in a TTL map.
  // ModelsDev.Data was removed in v1.14.33 — instance-store disposal handles cache invalidation.
  await Auth.remove("saeeol")
  ModelCache.clear("saeeol")

  await using base = await tmpdir({
    init: async (dir) => {
      await Bun.write(
        path.join(dir, "saeeol.json"),
        JSON.stringify({
          $schema: "https://app.saeeol.ai/config.json",
        }),
      )
    },
  })

  const none = await Instance.provide({
    directory: base.path,
    fn: async () => paid(await Provider.list()),
  })

  await using keyed = await tmpdir({
    init: async (dir) => {
      await Bun.write(
        path.join(dir, "saeeol.json"),
        JSON.stringify({
          $schema: "https://app.saeeol.ai/config.json",
          provider: {
            saeeol: {
              options: {
                apiKey: "test-key",
              },
            },
          },
        }),
      )
    },
  })

  const count = await Instance.provide({
    directory: keyed.path,
    fn: async () => paid(await Provider.list()),
  })

  expect(none).toBeGreaterThan(0)
  expect(count).toBeGreaterThan(0)
})

test("saeeol loader keeps paid models without auth and when auth exists", async () => {
  await Auth.remove("saeeol")
  ModelCache.clear("saeeol")

  await using base = await tmpdir({
    init: async (dir) => {
      await Bun.write(
        path.join(dir, "saeeol.json"),
        JSON.stringify({
          $schema: "https://app.saeeol.ai/config.json",
        }),
      )
    },
  })

  const none = await Instance.provide({
    directory: base.path,
    fn: async () => paid(await Provider.list()),
  })

  await using keyed = await tmpdir({
    init: async (dir) => {
      await Bun.write(
        path.join(dir, "saeeol.json"),
        JSON.stringify({
          $schema: "https://app.saeeol.ai/config.json",
        }),
      )
    },
  })

  const authPath = path.join(Global.Path.data, "auth.json")
  let prev: string | undefined

  try {
    prev = await Filesystem.readText(authPath)
  } catch {}

  try {
    await Filesystem.write(
      authPath,
      JSON.stringify({
        saeeol: {
          type: "api",
          key: "test-key",
        },
      }),
    )

    const count = await Instance.provide({
      directory: keyed.path,
      fn: async () => paid(await Provider.list()),
    })

    expect(none).toBeGreaterThan(0)
    expect(count).toBeGreaterThan(0)
  } finally {
    if (prev !== undefined) {
      await Filesystem.write(authPath, prev)
    }
    if (prev === undefined) {
      try {
        await unlink(authPath)
      } catch {}
    }
  }
})
