import { Hono } from 'hono'
import { randomBytes, createHash } from 'crypto'
import { Buffer } from 'buffer'

const app = new Hono()

// In-memory PKCE store (should use Redis or similar in production)
const pkceStore = new Map<string, string>()

const generateCodeVerifier = () => {
  return randomBytes(32).toString('hex')
}

const generateCodeChallenge = (verifier: string) => {
  const hash = createHash('sha256').update(verifier).digest()
  return hash.toString('base64url')
}

// Step 1: Redirect to GitHub with PKCE
app.get('/login', (c) => {
  const codeVerifier = generateCodeVerifier()
  const codeChallenge = generateCodeChallenge(codeVerifier)
  const state = randomBytes(8).toString('hex')

  pkceStore.set(state, codeVerifier)

  const params = new URLSearchParams({
    client_id: process.env.GITHUB_CLIENT_ID!,
    redirect_uri: 'http://localhost:8787/callback',
    scope: 'read:user',
    state,
    response_type: 'code',
    code_challenge: codeChallenge,
    code_challenge_method: 'S256',
  })

  return c.redirect(`https://github.com/login/oauth/authorize?${params}`)
})

// Step 2: GitHub redirects back here
app.get('/callback', async (c) => {
  const url = new URL(c.req.url)
  const code = url.searchParams.get('code')
  const state = url.searchParams.get('state')

  if (!code || !state) {
    return c.text('Missing code or state', 400)
  }

  const codeVerifier = pkceStore.get(state)
  if (!codeVerifier) {
    return c.text('Invalid or expired state', 400)
  }

  // Step 3: Exchange code + verifier for token
  const tokenRes = await fetch('https://github.com/login/oauth/access_token', {
    method: 'POST',
    headers: {
      Accept: 'application/json',
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      client_id: process.env.GITHUB_CLIENT_ID,
      client_secret: process.env.GITHUB_CLIENT_SECRET,
      code,
      redirect_uri: 'http://localhost:8787/callback',
      code_verifier: codeVerifier,
    }),
  })

  const tokenData = await tokenRes.json()
  if (!tokenData.access_token) {
    return c.text('Failed to get access token', 500)
  }

  // Step 4: Use token to fetch user profile
  const userRes = await fetch('https://api.github.com/user', {
    headers: {
      Authorization: `Bearer ${tokenData.access_token}`,
      'User-Agent': 'hono-app',
    },
  })

  const user = await userRes.json()
  return c.json({
    message: 'GitHub login successful!',
    user,
  })
})

export default { 
  port: 8787,
  fetch: app.fetch,
}