import { type NextAuthOptions } from "next-auth"
import CredentialsProvider from "next-auth/providers/credentials"
import Auth0Provider from "next-auth/providers/auth0"
import { compare } from "bcryptjs"
import prisma from "@/lib/prisma"

/**
 * Find or create a user+org from an Auth0 social login.
 * First login creates the org; subsequent logins find existing.
 */
async function findOrCreateSocialUser(profile: { email: string; name?: string; picture?: string }) {
  if (!prisma || !profile.email) return null

  const email = profile.email.toLowerCase().trim()

  // Check if user exists
  const existing = await prisma.user.findUnique({
    where: { email },
    include: { organization: { select: { id: true, name: true, slug: true } } },
  })

  if (existing) {
    return {
      id: existing.id,
      email: existing.email,
      name: existing.name,
      role: existing.role,
      orgId: existing.organizationId,
      orgName: existing.organization.name,
      orgSlug: existing.organization.slug,
    }
  }

  // First-time social login → create org + user
  const name = profile.name || email.split("@")[0]
  const slug = name.toLowerCase().replace(/[^a-z0-9]+/g, "-").slice(0, 30) + "-" + Date.now().toString(36)

  const result = await prisma.$transaction(async (tx) => {
    const org = await tx.organization.create({
      data: {
        name: `${name}'s Charity`,
        slug,
        country: "GB",
        refPrefix: slug.substring(0, 4).toUpperCase(),
      },
    })
    const user = await tx.user.create({
      data: {
        email,
        name,
        role: "org_admin",
        organizationId: org.id,
      },
    })
    return { user, org }
  })

  return {
    id: result.user.id,
    email: result.user.email,
    name: result.user.name,
    role: result.user.role,
    orgId: result.org.id,
    orgName: result.org.name,
    orgSlug: result.org.slug,
  }
}

export const authOptions: NextAuthOptions = {
  session: { strategy: "jwt" },
  pages: {
    signIn: "/login",
  },
  providers: [
    // Auth0 — Google, Apple, email/password via Universal Login
    Auth0Provider({
      clientId: process.env.AUTH0_CLIENT_ID || "hpr7JcEAAk3Q5ADkzyyZSRDxGIZTcjRJ",
      clientSecret: process.env.AUTH0_CLIENT_SECRET || "ha6Q5bK1B-YaluwznBvgi8jaCpqwdNmLq-UAca_-WHVy6Yfscf1tfNCrHPxKwvAh",
      issuer: process.env.AUTH0_ISSUER || "https://quikcue.us.auth0.com",
    }),

    // Keep credentials for demo login + existing password users
    CredentialsProvider({
      name: "credentials",
      credentials: {
        email: { label: "Email", type: "email" },
        password: { label: "Password", type: "password" },
      },
      async authorize(credentials) {
        if (!credentials?.email || !credentials?.password || !prisma) return null

        const user = await prisma.user.findUnique({
          where: { email: credentials.email.toLowerCase().trim() },
          include: { organization: { select: { id: true, name: true, slug: true } } },
        })

        if (!user || !user.hashedPassword) return null

        const valid = await compare(credentials.password, user.hashedPassword)
        if (!valid) return null

        return {
          id: user.id,
          email: user.email,
          name: user.name,
          role: user.role,
          orgId: user.organizationId,
          orgName: user.organization.name,
          orgSlug: user.organization.slug,
        }
      },
    }),
  ],
  callbacks: {
    async signIn({ user, account, profile }) {
      // For Auth0 social logins, find/create user in our DB
      if (account?.provider === "auth0" && profile?.email) {
        const dbUser = await findOrCreateSocialUser({
          email: profile.email,
          name: (profile as { name?: string }).name || undefined,
          picture: (profile as { picture?: string }).picture || undefined,
        })
        if (dbUser) {
          // Attach our DB fields to the user object for the jwt callback
          Object.assign(user, dbUser)
        }
        return true
      }
      return true
    },
    async jwt({ token, user }) {
      if (user) {
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        const u = user as any
        if (u.orgId) {
          token.role = u.role
          token.orgId = u.orgId
          token.orgName = u.orgName
          token.orgSlug = u.orgSlug
          token.dbId = u.id
        }
      }
      // For Auth0 users on first token creation, look up from DB
      if (!token.orgId && token.email) {
        const dbUser = await findOrCreateSocialUser({ email: token.email as string, name: token.name || undefined })
        if (dbUser) {
          token.role = dbUser.role
          token.orgId = dbUser.orgId
          token.orgName = dbUser.orgName
          token.orgSlug = dbUser.orgSlug
          token.dbId = dbUser.id
        }
      }
      return token
    },
    async session({ session, token }) {
      if (session.user) {
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        const s = session as any
        s.user.id = token.dbId || token.sub
        s.user.role = token.role
        s.user.orgId = token.orgId
        s.user.orgName = token.orgName
        s.user.orgSlug = token.orgSlug
      }
      return session
    },
  },
}
