import { SignInAction } from '@/feactures/auth/actions/login-action';
import { resfreshTokenAction } from '@/feactures/auth/actions/refresh-token-action';
import { CredentialsSignin, NextAuthConfig, Session, User } from 'next-auth';
import { DefaultJWT } from 'next-auth/jwt';
import CredentialProvider from 'next-auth/providers/credentials';


// Define los tipos para tus respuestas de SignInAction
interface SignInSuccessResponse {
  message: string;
  user: {
    email: string;
    username: string;
    id: number;
    rol: Array<{ id: number; rol: string }>;
    fullname: string;
  };
  tokens: {
    access_token: string;
    access_expire_in: number;
    refresh_token: string;
    refresh_expire_in: number;
  };
}

// **CAMBIO AQUÍ**: `type: string;` en lugar de una unión de literales
interface SignInErrorResponse {
  type: string; // Si SignInAction puede devolver cualquier string aquí
  message: string;
  details?: any;
}

// Unión de tipos para el resultado de SignInAction, AHORA INCLUYE `null`
type SignInActionResult = SignInSuccessResponse | SignInErrorResponse | null;

const authConfig: NextAuthConfig = {
  providers: [
    CredentialProvider({
      credentials: {
        username: {
          type: 'username',
        },
        password: {
          type: 'password',
        },
      },
      async authorize(
        credentials: Partial<Record<'username' | 'password', unknown>>,
      ): Promise<User | null> {
        const credential = {
          username: credentials?.username as string,
          password: credentials?.password as string,
        };

        // Asigna el tipo `SignInActionResult` que ahora incluye `null`
        const response: SignInActionResult = await SignInAction(credential);

        // **NUEVO: Manejar el caso `null` primero**
        if (response === null) {
          console.error("SignInAction returned null, indicating a potential issue before API call or generic error.");
          throw new CredentialsSignin("Error de inicio de sesión inesperado.");
        }

        // Tipo Guarda: Verificar la respuesta de error
        if (
          'type' in response &&
          (response.type === 'API_ERROR' ||
            response.type === 'VALIDATION_ERROR' ||
            response.type === 'UNKNOWN_ERROR') // Incluye todos los tipos de error posibles
        ) {
          // Si es un error, lánzalo. Este camino termina aquí.
          throw new CredentialsSignin("Error en la API:" + response.message);
        }

        if (!('user' in response)) {
          // Esto solo ocurriría si SignInAction devolvió un objeto que no es null,
          // no es un error conocido por 'type', PERO tampoco tiene la propiedad 'user'.
          // Es un caso de respuesta inesperada del API.
          console.error("Respuesta de SignInAction con formato inesperado: falta la propiedad 'user'.");
          throw new CredentialsSignin("Error en el formato de la respuesta del servidor.");
        }

        return {
          id: response?.user.id?.toString() ?? '0',
          username: response?.user.username ?? '',
          fullname: response?.user.fullname ?? '',
          email: response?.user.email ?? '',
          role: response?.user.rol ?? [], // Add role array
          access_token: response?.tokens.access_token ?? '',
          access_expire_in: response?.tokens.access_expire_in ?? 0,
          refresh_token: response?.tokens.refresh_token ?? '',
          refresh_expire_in: response?.tokens.refresh_expire_in ?? 0,
        };


      },
    }),
  ],
  pages: {
    signIn: '/', //sigin page
  },
  callbacks: {
    async jwt({ token, user }:{
      user: User
      token: any

    }) {
      // 1. Manejar el inicio de sesión inicial
      // El `user` solo se proporciona en el primer inicio de sesión.
      if (user) {
        return {
          id: user.id,
          username: user.username,
          fullname: user.fullname,
          email: user.email,
          role: user.role,
          access_token: user.access_token,
          access_expire_in: user.access_expire_in,
          refresh_token: user.refresh_token,
          refresh_expire_in: user.refresh_expire_in
        }
        // return token;
      }

      // 2. Si no es un nuevo login, verificar la expiración del token
      const now = Math.floor(Date.now() / 1000); // Usar Math.floor para un número entero

      // Verificar si el token de acceso aún es válido
      if (now < (token.access_expire_in as number)) {
        return token; // Si no ha expirado, no hacer nada y devolver el token actual
      }

      console.log("Now Access Expire:",token.access_expire_in);
      

      // 3. Si el token de acceso ha expirado, verificar el refresh token
      console.log("Access token ha expirado. Verificando refresh token...");
      if (now > (token.refresh_expire_in as number)) {
        console.log("Refresh token ha expirado. Forzando logout.");
        return null; // Forzar el logout al devolver null
      }

      console.log("token:", token.refresh_token);


      // 4. Si el token de acceso ha expirado pero el refresh token es válido, renovar
      console.log("Renovando token de acceso...");
      try {
        const res = await resfreshTokenAction({ token: token.refresh_token as string });

        if (!res || !res.tokens) {
          throw new Error('Fallo en la respuesta de la API de refresco.');
        }

        console.log("Old Access Expire:", token.access_expire_in);
        console.log("New Access Expire:", res.tokens.access_expire_in);

        console.log("token:", token.refresh_token);
        

        // Actualizar el token directamente con los nuevos valores
        token.access_token = res.tokens.access_token;
        token.access_expire_in = res.tokens.access_expire_in;
        token.refresh_token = res.tokens.refresh_token;
        token.refresh_expire_in = res.tokens.refresh_expire_in;
        return token;

      } catch (error) {
        console.error("Error al renovar el token: ", error);
        return null; // Fallo al renovar, forzar logout
      }
    },
    async session({ session, token }: { session: Session; token: any }) {
      session.access_token = token.access_token as string;
      session.access_expire_in = token.access_expire_in as number;
      session.refresh_token = token.refresh_token as string;
      session.refresh_expire_in = token.refresh_expire_in as number;
      session.user = {
        id: token.id as number,
        username: token.username as string,
        fullname: token.fullname as string,
        email: token.email as string,
        role: token.role as Array<{ id: number; rol: string }>,
      };
      return session;
    },
  },
} satisfies NextAuthConfig;

export default authConfig;
