"use client";
// External libraries
import {
  createContext,
  useContext,
  useState,
  useEffect,
  useCallback,
  ReactNode,
} from "react";
import { useRouter, usePathname } from "next/navigation";

// Services
import { AuthService } from "@/src/services/api/auth";
import { api } from "../services/api/http/instances";

// Types
import { AuthContextData, User } from "@/src/types/auth";
import { SignInRequest } from "../services/api/auth/dtos";

const AuthContext = createContext<AuthContextData>({} as AuthContextData);

const TOKEN_KEY = "@embrapa-idh:token";
const USER_KEY = "@embrapa-idh:user";

interface AuthProviderProps {
  children: ReactNode;
}

const PUBLIC_PATHS = ["/login", "/politica-de-privacidade", "/termos-de-uso"];

export function AuthProvider({ children }: AuthProviderProps) {
  const [user, setUser] = useState<User | null>(null);
  const [isLoading, setIsLoading] = useState(true);
  const router = useRouter();
  const pathname = usePathname();

  const isAuthenticated = !!user;

  useEffect(() => {
    if (isLoading) return;
    const isPublic = PUBLIC_PATHS.includes(pathname);
    if (!user && !isPublic) {
      router.replace("/login");
    } else if (user && pathname === "/login") {
      router.replace("/");
    }
  }, [isLoading, user, pathname, router]);

  useEffect(() => {
    if (typeof window === "undefined") {
      console.warn(
        "O código está sendo executado no servidor. Ignorando o carregamento de dados de autenticação.",
      );
      return;
    }

    const loadStoredData = () => {
      try {
        const storedToken = localStorage.getItem(TOKEN_KEY);
        const storedUser = localStorage.getItem(USER_KEY);

        if (storedToken && storedUser) {
          const parsedUser = JSON.parse(storedUser);
          const allowedRoles = ["ADMIN", "EMBRAPA"];

          if (!allowedRoles.includes(parsedUser.role)) {
            localStorage.removeItem(TOKEN_KEY);
            localStorage.removeItem(USER_KEY);
            console.warn("Usuário sem permissão de acesso. Sessão encerrada.");
            return;
          }

          api.defaults.headers.common.Authorization = `Bearer ${storedToken}`;
          setUser(parsedUser);
        }
      } catch (error) {
        console.error("Erro ao carregar dados de autenticação:", error);
      } finally {
        setIsLoading(false);
      }
    };

    loadStoredData();
  }, [router]);

  const signIn = useCallback(
    async (credentials: SignInRequest) => {
      const accessDeniedError = {
        response: {
          status: 403,
          data: {
            message:
              "Acesso negado. Apenas usuários ADMIN ou EMBRAPA podem acessar o sistema.",
          },
        },
      };

      const { token } = await AuthService.signIn(credentials);

      localStorage.setItem(TOKEN_KEY, token);
      api.defaults.headers.common.Authorization = `Bearer ${token}`;

      try {
        const usuarioLogado = await AuthService.getUsuarioLogado();

        if (!usuarioLogado.usersId) {
          throw accessDeniedError;
        }

        const userRecord = await AuthService.getUserById(String(usuarioLogado.usersId));
        const userRole = userRecord.role || "USER";
        const allowedRoles = ["ADMIN", "EMBRAPA"];

        if (!allowedRoles.includes(userRole)) {
          throw accessDeniedError;
        }

        const userToStore: User = {
          id: userRecord.id,
          email: userRecord.email ?? usuarioLogado.email,
          name: userRecord.name ?? usuarioLogado.nome,
          role: userRole,
          usuariosCadastroId: usuarioLogado.idt,
          matricula: usuarioLogado.matricula,
        };

        localStorage.setItem(USER_KEY, JSON.stringify(userToStore));
        setUser(userToStore);

        router.push("/");
      } catch (error) {
        localStorage.removeItem(TOKEN_KEY);
        localStorage.removeItem(USER_KEY);
        delete api.defaults.headers.common.Authorization;
        throw error;
      }
    },
    [router],
  );

  const signOut = useCallback(() => {
    localStorage.removeItem(TOKEN_KEY);
    localStorage.removeItem(USER_KEY);
    delete api.defaults.headers.common.Authorization;
    setUser(null);
    router.push("/login");
  }, [router]);

  const isPublic = PUBLIC_PATHS.includes(pathname);
  const shouldBlock = isLoading || (!user && !isPublic);

  return (
    <AuthContext.Provider
      value={{
        user,
        isAuthenticated,
        isLoading,
        signIn,
        signOut,
      }}
    >
      {shouldBlock && !isPublic ? null : children}
    </AuthContext.Provider>
  );
}

export function useAuth(): AuthContextData {
  const context = useContext(AuthContext);

  if (!context) {
    throw new Error("useAuth deve ser usado dentro de um AuthProvider");
  }

  return context;
}
