import NextAuth, { NextAuthOptions } from "next-auth"
import GoogleProvider from "next-auth/providers/google"
import FacebookProvider from "next-auth/providers/facebook"
import GithubProvider from "next-auth/providers/github"
import TwitterProvider from "next-auth/providers/twitter"
import Auth0Provider from "next-auth/providers/auth0"
import AppleProvider from "next-auth/providers/apple"
import EmailProvider from "next-auth/providers/email"
import CredentialsProvider from "next-auth/providers/credentials"
import { PrismaAdapter } from "@auth/prisma-adapter"
import bcrypt from "bcrypt"

const emailHelper = require('../../../src/helpers/email');
//microsoft
import AzureADProvider from "next-auth/providers/azure-ad";

// https://next-auth.js.org/getting-started/client

const common = require("../../../src/helpers/common");
import { isLoggedIn, setAuthTokens, clearAuthTokens, getAccessToken, getRefreshToken } from 'axios-jwt'
import { create } from "domain"
import { logger } from "src/helpers/common"


//console.log("appleID:", process.env.APPLE_APP_ID);

// console.log(process.env.EMAIL_SERVER)
// For more information on each option (and a full list of options) go to
// https://next-auth.js.org/configuration/options
export const authOptions: NextAuthOptions = {
  // https://next-auth.js.org/configuration/providers/oauth

  site: process.env.NEXT_PUBLIC_PUBLIC_URL,
  secret: process.env.NEXTAUTH_SECRET, // Ensure you have this set in your .env file
  //adapter: PrismaAdapter(prisma),
  providers: [
    // register new URL at  https://console.cloud.google.com/apis/credentials/oauthclient/926212607479-d3m8hm8f8esp3rf1639prskn445sa01v.apps.googleusercontent.com?project=grand-forge-108716 
    //Request details: redirect_uri=http://20.101.62.76:8005/api/auth/callback/google https://s.mwitnessingmwitnessing.com/
    GoogleProvider({
      clientId: process.env.GOOGLE_ID,
      clientSecret: process.env.GOOGLE_SECRET,
      authorization: {
        params: {
          prompt: "consent",
          access_type: "offline",
          response_type: "code"
        }
      }
    }),
    AppleProvider({
      // clientId: process.env.APPLE_APP_ID,
      // clientSecret: process.env.APPLE_SECRET
      clientId: process.env.APPLE_APP_ID,
      clientSecret: {
        appleId: process.env.APPLE_APP_ID,
        teamId: process.env.APPLE_TEAM_ID,
        privateKey: process.env.APPLE_PK,
        keyId: process.env.APPLE_KEY_ID,
      }
    }),
    AzureADProvider({
      clientId: process.env.AZURE_AD_CLIENT_ID,
      clientSecret: process.env.AZURE_AD_CLIENT_SECRET,
      tenantId: process.env.AZURE_AD_TENANT_ID,
    }),
    CredentialsProvider({
      id: 'credentials',
      // The name to display on the sign in form (e.g. 'Sign in with...')
      name: 'Credentials',
      credentials: {
        username: { label: "Потребител", type: "text", placeholder: "Потребителско име" },
        password: { label: "Парола", type: "password" }
      },
      async authorize(credentials, req) {

        const users = [
          { id: "1", name: "admin", email: "admin@example.com", password: process.env.ADMIN_PASSWORD, role: "ADMIN", static: true }
        ];

        if (process.env.ADMIN_PASSWORD !== credentials.password) {
          throw new Error('невалидна парола');
        }

        const user = users.find(user =>
          user.name === credentials.username && user.password === credentials.password
        );

        if (user) {
          const remoteIP = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
          const userAgent = req.headers['user-agent'];
          const message = "login form built-in admin account from ip:" + remoteIP + " user-agent:" + userAgent;
          console.log(message);
          logger.info(message);
          return user;
        }
        else {
          const prisma = common.getPrismaClient();
          const user = await prisma.user.findUnique({ where: { email: credentials.username } });
          if (user) {
            if (!user.emailVerified) {
              const mailVerifyToken = await bcrypt.hash(credentials.username, 10);
              const date = new Date().getTime();
              const emailVerifyToken = date + "_" + mailVerifyToken;
              await prisma.user.update({
                where: { email: credentials.username },
                data: { emailVerifyToken: emailVerifyToken }
              });
              console.log("resending email verification token to ", credentials.username);
              logger.info("resending email verification token to ", credentials.username);
              emailHelper.SendEmail_ValidateTemplate(credentials.username, emailVerifyToken);
              throw new Error('Моля потвърди имейла си преди да влезеш в системата.');
            }
            else {
              const match = await bcrypt.compare(credentials?.password, user.passwordHashLocalAccount);
              if (match) {
                console.log("User authenticated successfully.");
                //create access token
                user.accessToken = await getAccessToken();

                return user;
              }
              else {
                console.log("Password mismatch.");
                throw new Error('невалидна парола');
              }
            }
          }
          else {
            try {
              const pub = await prisma.publisher.findUnique({ where: { email: credentials.username } });
              if (pub) {
                const passHash = await bcrypt.hash(credentials.password, 10);
                const mailVerifyToken = await bcrypt.hash(pub.email, 10);
                const date = new Date().getTime();
                const emailVerifyToken = date + "_" + mailVerifyToken;
                const newUser = await prisma.user.create({
                  data: {
                    name: credentials.username,
                    email: credentials.username,
                    passwordHashLocalAccount: passHash,
                    emailVerifyToken: emailVerifyToken
                  }
                });
                console.log("New local credential user created for publisher ", pub.firstName, " ", pub.lastName, " (", pub.email, ")");
                logger.info("New local credential user created for publisher ", pub.firstName, " ", pub.lastName, " (", pub.email, ")");
                emailHelper.SendEmail_ValidateTemplate(pub.email, emailVerifyToken, pub.firstName, pub.lastName);
                //return newUser;
                throw new Error("Моля проверете вашия имейл '" + credentials?.username + "' за да потвърдите регистрацията си.");
              }
              else {

                throw new Error("Не можем да намерим твоя имейл '" + credentials?.username + "' в участниците в ССОМ. Моля свържи се с нас за да те регистрираме ако искаш да ползваш този имейл.");
              }
            } catch (err) {
              console.log("Error in credentials authorize:", err);
              throw new Error("Не можем да намерим твоя имейл '" + credentials?.username + "' в участниците в ССОМ. Моля свържи се с нас за да те регистрираме ако искаш да ползваш този имейл.");
            }
          }
        }
      }
    })
    /*
    EmailProvider({
      server: {
        host: "smtp.mailtrap.io",
        port: 2525,
        auth: {
          user: "8ec69527ff2104",
          pass: "c7bc05f171c96c"
        }
      },
      // server: process.env.EMAIL_SERVER,
      from: "noreply@example.com",
    }),

    // Temporarily removing the Apple provider from the demo site as the
    // callback URL for it needs updating due to Vercel changing domains
    /* 

        */

    //d-popov@abv.bg
    // Auth0Provider({
    //   clientId: process.env.AUTH0_ID,
    //   clientSecret: process.env.AUTH0_SECRET,
    //   issuer: process.env.AUTH0_ISSUER,
    // }),
  ],
  theme: {
    colorScheme: "light",
  },
  session: {
    strategy: "jwt"
  },
  callbacks: {
    // https://codevoweb.com/implement-authentication-with-nextauth-in-nextjs-14/
    async signIn({ user, account, profile }) {
      if (account.provider === 'credentials' && user?.static) {
        return true;
      }

      var prisma = common.getPrismaClient();

      console.log("[nextauth] signIn:", account.provider, user.email)
      //if (account.provider === 'google' ) {

      // Check user in your database and assign roles
      const dbUser = await prisma.publisher.findUnique({
        where: { email: user.email }
      });

      if (dbUser) {
        // Assign roles from your database to the session
        user.role = dbUser.role;
        user.id = dbUser.id;
        //user.permissions = dbUser.permissions;
        const session = { ...user };

        await prisma.publisher.update({
          where: { id: dbUser.id },
          data: { lastLogin: new Date() }
        });
        return true;
      } else {
        //user nor found in our database. deny access, showing error message. logout and redirect to message page
        //throw new Error(`Твоят имейл '${user.email}' не е регистриран в системата. Моля свържи се с нас за да те регистрираме ако искаш да ползваш този имейл.`);
        throw new Error(`UserNotFound&email=${encodeURIComponent(user?.email)}`);
      }

    },

    // async redirect({ url, baseUrl, user }) {
    //   // Redirect based on the user or error
    //   console.log("[nextauth] redirect", url, baseUrl, user)
    //   if (user) {
    //     return url;
    //   } else if (url.includes('error=UserNotFound')) {
    //     // Redirect to a custom error page or display an error
    //     return `${baseUrl}/error=UserNotFound&mail=${encodeURIComponent(user?.email)}`;
    //   }
    //   return baseUrl;
    // },

    // Persist the OAuth access_token to the token right after signin
    async jwt({ token, user, account, profile, isNewUser }) {
      //!console.log("[nextauth] JWT", token, user)
      //token.userRole = "adminer"
      if (user) {
        token.role = user.role;
        token.id = user.id; //already done in session?
        //token.name = user.name; already done in session (name, email, picture, sub)
      }
      if (account && user) {
        token.accessToken = account.access_token; // Set the access token from the account object
        token.provider = account.provider;
        console.log("[nextauth] setting token.accessToken", token.accessToken);
        setAuthTokens({
          accessToken: account.accessToken,
          refreshToken: account.refreshToken,
        })
      }

      return token;
    },

    // Send properties to the client, like an access_token from a provider.
    async session({ session, token, user }) {
      //!console.log("[nextauth] session", token, user)
      if (token) {
        //session.user.role = token.role;
        session.user.id = token.id;
        session.user.role = token.role;
        session.user.name = token.name || token.email;
      }
      if (user?.impersonating) {
        // Add flag to session if user is being impersonated
        session.user.impersonating = true;
      }
      // if (session?.user) {
      //   session.user.id = user.id; //duplicate
      // }

      return {
        ...session,
        accessToken: token.accessToken
      };
    },
  },
  pages: {
    signIn: "/auth/signin",
    signOut: "/auth/signout",
    error: "/message", // Error code passed in query string as ?error=
    verifyRequest: "/auth/verify-request", // (used for check email message)
    newUser: null // If set, new users will be directed here on first sign in
  },

  debug: process.env.NODE_ENV === 'development',
}

export default NextAuth(authOptions)