import { test, expect } from "bun:test"
import path from "path"

import { tmpdir } from "../fixture/fixture"
import { Instance } from "../../src/project/instance"
import { Provider } from "../../src/provider/provider"
import { Env } from "../../src/env"
import { Global } from "../../src/global"

test("GitLab Duo: loads provider with API key from environment", async () => {
  await using tmp = await tmpdir({
    init: async (dir) => {
      await Bun.write(
        path.join(dir, "opencode.json"),
        JSON.stringify({
          $schema: "https://opencode.ai/config.json",
        }),
      )
    },
  })
  await Instance.provide({
    directory: tmp.path,
    init: async () => {
      Env.set("GITLAB_TOKEN", "test-gitlab-token")
    },
    fn: async () => {
      const providers = await Provider.list()
      expect(providers["gitlab"]).toBeDefined()
      expect(providers["gitlab"].key).toBe("test-gitlab-token")
    },
  })
})

test("GitLab Duo: config instanceUrl option sets baseURL", async () => {
  await using tmp = await tmpdir({
    init: async (dir) => {
      await Bun.write(
        path.join(dir, "opencode.json"),
        JSON.stringify({
          $schema: "https://opencode.ai/config.json",
          provider: {
            gitlab: {
              options: {
                instanceUrl: "https://gitlab.example.com",
              },
            },
          },
        }),
      )
    },
  })
  await Instance.provide({
    directory: tmp.path,
    init: async () => {
      Env.set("GITLAB_TOKEN", "test-token")
      Env.set("GITLAB_INSTANCE_URL", "https://gitlab.example.com")
    },
    fn: async () => {
      const providers = await Provider.list()
      expect(providers["gitlab"]).toBeDefined()
      expect(providers["gitlab"].options?.instanceUrl).toBe("https://gitlab.example.com")
    },
  })
})

test("GitLab Duo: loads with OAuth token from auth.json", async () => {
  await using tmp = await tmpdir({
    init: async (dir) => {
      await Bun.write(
        path.join(dir, "opencode.json"),
        JSON.stringify({
          $schema: "https://opencode.ai/config.json",
        }),
      )
    },
  })

  const authPath = path.join(Global.Path.data, "auth.json")
  await Bun.write(
    authPath,
    JSON.stringify({
      gitlab: {
        type: "oauth",
        access: "test-access-token",
        refresh: "test-refresh-token",
        expires: Date.now() + 3600000,
      },
    }),
  )

  await Instance.provide({
    directory: tmp.path,
    init: async () => {
      Env.set("GITLAB_TOKEN", "")
    },
    fn: async () => {
      const providers = await Provider.list()
      expect(providers["gitlab"]).toBeDefined()
    },
  })
})

test("GitLab Duo: loads with Personal Access Token from auth.json", async () => {
  await using tmp = await tmpdir({
    init: async (dir) => {
      await Bun.write(
        path.join(dir, "opencode.json"),
        JSON.stringify({
          $schema: "https://opencode.ai/config.json",
        }),
      )
    },
  })

  const authPath2 = path.join(Global.Path.data, "auth.json")
  await Bun.write(
    authPath2,
    JSON.stringify({
      gitlab: {
        type: "api",
        key: "glpat-test-pat-token",
      },
    }),
  )

  await Instance.provide({
    directory: tmp.path,
    init: async () => {
      Env.set("GITLAB_TOKEN", "")
    },
    fn: async () => {
      const providers = await Provider.list()
      expect(providers["gitlab"]).toBeDefined()
      expect(providers["gitlab"].key).toBe("glpat-test-pat-token")
    },
  })
})

test("GitLab Duo: supports self-hosted instance configuration", async () => {
  await using tmp = await tmpdir({
    init: async (dir) => {
      await Bun.write(
        path.join(dir, "opencode.json"),
        JSON.stringify({
          $schema: "https://opencode.ai/config.json",
          provider: {
            gitlab: {
              options: {
                instanceUrl: "https://gitlab.company.internal",
                apiKey: "glpat-internal-token",
              },
            },
          },
        }),
      )
    },
  })
  await Instance.provide({
    directory: tmp.path,
    init: async () => {
      Env.set("GITLAB_INSTANCE_URL", "https://gitlab.company.internal")
    },
    fn: async () => {
      const providers = await Provider.list()
      expect(providers["gitlab"]).toBeDefined()
      expect(providers["gitlab"].options?.instanceUrl).toBe("https://gitlab.company.internal")
    },
  })
})

test("GitLab Duo: config apiKey takes precedence over environment variable", async () => {
  await using tmp = await tmpdir({
    init: async (dir) => {
      await Bun.write(
        path.join(dir, "opencode.json"),
        JSON.stringify({
          $schema: "https://opencode.ai/config.json",
          provider: {
            gitlab: {
              options: {
                apiKey: "config-token",
              },
            },
          },
        }),
      )
    },
  })
  await Instance.provide({
    directory: tmp.path,
    init: async () => {
      Env.set("GITLAB_TOKEN", "env-token")
    },
    fn: async () => {
      const providers = await Provider.list()
      expect(providers["gitlab"]).toBeDefined()
    },
  })
})

test("GitLab Duo: supports feature flags configuration", async () => {
  await using tmp = await tmpdir({
    init: async (dir) => {
      await Bun.write(
        path.join(dir, "opencode.json"),
        JSON.stringify({
          $schema: "https://opencode.ai/config.json",
          provider: {
            gitlab: {
              options: {
                featureFlags: {
                  duo_agent_platform_agentic_chat: true,
                  duo_agent_platform: true,
                },
              },
            },
          },
        }),
      )
    },
  })
  await Instance.provide({
    directory: tmp.path,
    init: async () => {
      Env.set("GITLAB_TOKEN", "test-token")
    },
    fn: async () => {
      const providers = await Provider.list()
      expect(providers["gitlab"]).toBeDefined()
      expect(providers["gitlab"].options?.featureFlags).toBeDefined()
      expect(providers["gitlab"].options?.featureFlags?.duo_agent_platform_agentic_chat).toBe(true)
    },
  })
})

test("GitLab Duo: has multiple agentic chat models available", async () => {
  await using tmp = await tmpdir({
    init: async (dir) => {
      await Bun.write(
        path.join(dir, "opencode.json"),
        JSON.stringify({
          $schema: "https://opencode.ai/config.json",
        }),
      )
    },
  })
  await Instance.provide({
    directory: tmp.path,
    init: async () => {
      Env.set("GITLAB_TOKEN", "test-token")
    },
    fn: async () => {
      const providers = await Provider.list()
      expect(providers["gitlab"]).toBeDefined()
      const models = Object.keys(providers["gitlab"].models)
      expect(models.length).toBeGreaterThan(0)
      expect(models).toContain("duo-chat-haiku-4-5")
      expect(models).toContain("duo-chat-sonnet-4-5")
      expect(models).toContain("duo-chat-opus-4-5")
    },
  })
})
