import NextAuth from 'next-auth';
import CredentialsProvider from 'next-auth/providers/credentials';
import jwt_decode from 'jsonwebtoken';
import logger from '@/utils/logger';

const options = {
  secret: process.env.AUTH_SECRET,
  providers: [
    CredentialsProvider({
      name: 'Credentials',
      credentials: {
        email: { label: 'Email', type: 'email' },
        password: { label: 'Password', type: 'password' },
      },
      authorize: async (credentials) => {
        // URL calculée ici (pas au niveau module) pour garantir que NEXT_PUBLIC_API_URL est chargé
        const loginUrl = `${process.env.NEXT_PUBLIC_API_URL}/Auth/login`;
        const csrfUrl = `${process.env.NEXT_PUBLIC_API_URL}/Auth/csrf`;
        try {
          // Récupération server-side du CSRF token + cookie Django
          const csrfRes = await fetch(csrfUrl, {
            method: 'GET',
            headers: { Connection: 'close' },
          });
          const csrfData = await csrfRes.json();
          const csrfToken = csrfData?.csrfToken;
          // Extraction du cookie csrftoken depuis la réponse
          const rawCookies = csrfRes.headers.get('set-cookie') || '';
          const csrfCookieMatch = rawCookies.match(/csrftoken=([^;]+)/);
          const csrfCookie = csrfCookieMatch ? csrfCookieMatch[1] : csrfToken;

          const res = await fetch(loginUrl, {
            method: 'POST',
            headers: {
              'Content-Type': 'application/json',
              // Connection: close évite le SocketError undici lié au keep-alive vers Daphne
              Connection: 'close',
              'X-CSRFToken': csrfToken,
              Cookie: `csrftoken=${csrfCookie}`,
            },
            body: JSON.stringify({
              email: credentials.email,
              password: credentials.password,
            }),
          });

          if (!res.ok) {
            const body = await res.json().catch(() => ({}));
            throw new Error(body?.errorMessage || 'Identifiants invalides');
          }

          const user = await res.json();
          return user || null;
        } catch (error) {
          logger.error('Authorize error:', error.message);
          throw new Error(error.message || 'Invalid credentials');
        }
      },
    }),
  ],
  session: {
    strategy: 'jwt',
    maxAge: 60 * 60, // 1 Hour
    // 0 = réécrire le cookie à chaque fois que le token change (indispensable avec
    // un access token Django de 15 min, sinon le cookie expiré reste en place)
    updateAge: 0,
  },
  cookies: {
    sessionToken: {
      name: 'n3wtschool_session_token',
      options: {
        httpOnly: true,
        sameSite: 'lax',
        path: '/',
        secure: process.env.NODE_ENV === 'production',
      },
    },
  },
  callbacks: {
    async jwt({ token, user }) {
      // Si c'est la première connexion
      if (user && user?.token) {
        return {
          ...token,
          token: user.token,
          refresh: user.refresh,
          tokenExpires: jwt_decode.decode(user.token).exp * 1000,
        };
      }

      // Vérifier si le token n'est pas expiré
      if (Date.now() < token.tokenExpires) {
        return token;
      }

      // Token Django expiré (lifetime = 15 min), essayer de le rafraîchir
      logger.info('JWT: access token expiré, tentative de refresh');

      if (!token.refresh) {
        logger.error('JWT: refresh token absent dans la session');
        return { ...token, error: 'RefreshTokenError' };
      }

      const refreshUrl = `${process.env.NEXT_PUBLIC_API_URL}/Auth/refreshJWT`;
      if (!process.env.NEXT_PUBLIC_API_URL) {
        logger.error('JWT: NEXT_PUBLIC_API_URL non défini, refresh impossible');
        return { ...token, error: 'RefreshTokenError' };
      }

      try {
        const res = await fetch(refreshUrl, {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
            // Connection: close évite le SocketError undici lié au keep-alive vers Daphne
            Connection: 'close',
          },
          body: JSON.stringify({ refresh: token.refresh }),
        });

        if (!res.ok) {
          const body = await res.json().catch(() => ({}));
          logger.error('JWT: refresh échoué', { status: res.status, body });
          throw new Error(`Refresh HTTP ${res.status}`);
        }

        const response = await res.json();
        if (!response?.token) {
          logger.error('JWT: réponse refresh sans token', { response });
          throw new Error('Réponse refresh invalide');
        }

        logger.info('JWT: refresh réussi');
        return {
          ...token,
          token: response.token,
          refresh: response.refresh,
          tokenExpires: jwt_decode.decode(response.token).exp * 1000,
          error: undefined,
        };
      } catch (error) {
        logger.error('JWT: refresh token failed', { message: error.message });
        return { ...token, error: 'RefreshTokenError' };
      }
    },
    async session({ session, token }) {
      if (token?.error === 'RefreshTokenError') {
        session.error = 'RefreshTokenError';
        return session;
      }
      if (token && token?.token) {
        const { user_id, email, roles, roleIndexLoginDefault } =
          jwt_decode.decode(token.token);
        session.user = {
          ...session.user,
          token: token.token,
          refresh: token.refresh,
          user_id: user_id,
          email: email,
          roles: roles,
          roleIndexLoginDefault: roleIndexLoginDefault,
        };
      }
      return session;
    },
  },
  pages: {
    signIn: '/[locale]/users/login',
  },
  csrf: true,
};

export default (req, res) => NextAuth(req, res, options);
