import NextAuth from "next-auth"
import KeycloakProvider from "next-auth/providers/keycloak"

declare module "next-auth" {
  interface Session {
    user: {
      id: string
      name?: string | null
      email?: string | null
      image?: string | null
      clubs?: Record<string, string>
      isAdmin?: boolean
    }
    accessToken?: string
  }
  
  interface JWT {
    clubs?: Record<string, string>
    accessToken?: string
    isAdmin?: boolean
  }
}

// In Docker, the Next.js server reaches Keycloak via internal hostname
// (keycloak:8080) but the browser uses localhost:8080. Explicit endpoint
// URLs bypass OIDC discovery, avoiding issuer mismatch validation errors.
const issuerPublic = process.env.KEYCLOAK_ISSUER!
const issuerInternal = process.env.KEYCLOAK_ISSUER_INTERNAL || issuerPublic
const oidcPublic = `${issuerPublic}/protocol/openid-connect`
const oidcInternal = `${issuerInternal.replace(':8080', ':8081')}/protocol/openid-connect`

export const { handlers, signIn, signOut, auth } = NextAuth({
  providers: [
    KeycloakProvider({
      clientId: process.env.KEYCLOAK_CLIENT_ID!,
      issuer: issuerPublic,
      authorization: {
        url: `${oidcPublic}/auth`,
        params: { scope: "openid email profile" },
      },
      token: `${oidcInternal}/token`,
      userinfo: `${oidcInternal}/userinfo`,
      jwks_endpoint: `${oidcInternal}/certs`,
    })
  ],
  trustHost: true,
  cookies: {
    pkceCodeVerifier: {
      name: "authjs.pkce.code_verifier",
      options: {
        httpOnly: true,
        sameSite: "lax",
        path: "/",
        secure: false,
      },
    },
    state: {
      name: "authjs.state",
      options: {
        httpOnly: true,
        sameSite: "lax",
        path: "/",
        secure: false,
      },
    },
  },
  debug: true,
  callbacks: {
    async jwt({ token, account }) {
      if (account && account.access_token) {
        // Add clubs claim from Keycloak access token
        token.clubs = (account as { clubs?: Record<string, string> }).clubs || {}
        token.accessToken = account.access_token
        
        try {
          const payload = JSON.parse(Buffer.from((token.accessToken as string).split('.')[1], 'base64').toString());
          const roles = (payload.realm_access?.roles as string[]) || [];
          token.isAdmin = roles.includes('admin');
        } catch {
          token.isAdmin = false;
        }
      }
      return token
    },
    async session({ session, token }) {
      // Expose clubs to client
      if (session.user) {
        session.user.clubs = token.clubs as Record<string, string> | undefined
        session.user.isAdmin = token.isAdmin as boolean | undefined
      }
      session.accessToken = token.accessToken as string | undefined
      return session
    }
  }
})
