import { test } from "@playwright/test"
import { gitAuth } from "../constants"
import { Endpoints } from "@octokit/types"
import { GitAuthDevice } from "api/typesGenerated"
import { Awaiter, createServer } from "../helpers"

// Ensures that a Git auth provider with the device flow functions and completes!
test("git auth device", async ({ page }) => {
  const device: GitAuthDevice = {
    device_code: "1234",
    user_code: "1234-5678",
    expires_in: 900,
    interval: 1,
    verification_uri: "",
  }

  // Start a server to mock the GitHub API.
  const srv = await createServer(gitAuth.devicePort)
  srv.use(gitAuth.validatePath, (req, res) => {
    res.write(JSON.stringify(ghUser))
    res.end()
  })
  srv.use(gitAuth.codePath, (req, res) => {
    res.write(JSON.stringify(device))
    res.end()
  })
  srv.use(gitAuth.installationsPath, (req, res) => {
    res.write(JSON.stringify(ghInstall))
    res.end()
  })

  const token = {
    access_token: "",
    error: "authorization_pending",
    error_description: "",
  }
  // First we send a result from the API that the token hasn't been
  // authorized yet to ensure the UI reacts properly.
  const sentPending = new Awaiter()
  srv.use(gitAuth.tokenPath, (req, res) => {
    res.write(JSON.stringify(token))
    res.end()
    sentPending.done()
  })

  await page.goto(`/gitauth/${gitAuth.deviceProvider}`, {
    waitUntil: "networkidle",
  })
  await page.getByText(device.user_code).isVisible()
  await sentPending.wait()
  // Update the token to be valid and ensure the UI updates!
  token.error = ""
  token.access_token = "hello-world"
  await page.waitForSelector("text=1 organization authorized")
})

test("git auth web", async ({ baseURL, page }) => {
  const srv = await createServer(gitAuth.webPort)
  // The GitHub validate endpoint returns the currently authenticated user!
  srv.use(gitAuth.validatePath, (req, res) => {
    res.write(JSON.stringify(ghUser))
    res.end()
  })
  srv.use(gitAuth.tokenPath, (req, res) => {
    res.write(JSON.stringify({ access_token: "hello-world" }))
    res.end()
  })
  srv.use(gitAuth.authPath, (req, res) => {
    res.redirect(
      `${baseURL}/gitauth/${gitAuth.webProvider}/callback?code=1234&state=` +
        req.query.state,
    )
  })
  await page.goto(`/gitauth/${gitAuth.webProvider}`, {
    waitUntil: "networkidle",
  })
  // This endpoint doesn't have the installations URL set intentionally!
  await page.waitForSelector("text=You've authenticated with GitHub!")
})

const ghUser: Endpoints["GET /user"]["response"]["data"] = {
  login: "kylecarbs",
  id: 7122116,
  node_id: "MDQ6VXNlcjcxMjIxMTY=",
  avatar_url: "https://avatars.githubusercontent.com/u/7122116?v=4",
  gravatar_id: "",
  url: "https://api.github.com/users/kylecarbs",
  html_url: "https://github.com/kylecarbs",
  followers_url: "https://api.github.com/users/kylecarbs/followers",
  following_url:
    "https://api.github.com/users/kylecarbs/following{/other_user}",
  gists_url: "https://api.github.com/users/kylecarbs/gists{/gist_id}",
  starred_url: "https://api.github.com/users/kylecarbs/starred{/owner}{/repo}",
  subscriptions_url: "https://api.github.com/users/kylecarbs/subscriptions",
  organizations_url: "https://api.github.com/users/kylecarbs/orgs",
  repos_url: "https://api.github.com/users/kylecarbs/repos",
  events_url: "https://api.github.com/users/kylecarbs/events{/privacy}",
  received_events_url: "https://api.github.com/users/kylecarbs/received_events",
  type: "User",
  site_admin: false,
  name: "Kyle Carberry",
  company: "@coder",
  blog: "https://carberry.com",
  location: "Austin, TX",
  email: "kyle@carberry.com",
  hireable: null,
  bio: "hey there",
  twitter_username: "kylecarbs",
  public_repos: 52,
  public_gists: 9,
  followers: 208,
  following: 31,
  created_at: "2014-04-01T02:24:41Z",
  updated_at: "2023-06-26T13:03:09Z",
}

const ghInstall: Endpoints["GET /user/installations"]["response"]["data"] = {
  installations: [
    {
      id: 1,
      access_tokens_url: "",
      account: ghUser,
      app_id: 1,
      app_slug: "coder",
      created_at: "2014-04-01T02:24:41Z",
      events: [],
      html_url: "",
      permissions: {},
      repositories_url: "",
      repository_selection: "all",
      single_file_name: "",
      suspended_at: null,
      suspended_by: null,
      target_id: 1,
      target_type: "",
      updated_at: "2023-06-26T13:03:09Z",
    },
  ],
  total_count: 1,
}
