import {RoleEnum} from '@constant/StaticData';
import { useRouter } from 'next/navigation';
import { toast } from 'react-toastify';
import AuthenticationService from '@/service/AuthenticationService';
import jwt from 'jsonwebtoken';
import slugify from 'slugify';
import { log } from 'node:console';

export interface CustomCookieSetOptions {
    path?: string;
    expires?: Date;
    domain?: string;
}

export interface CookieValues {
  [key: string]: string;
}

export interface userDataInfo{
  username: string
  email: string
  ar_id: number
  user_id: number
}

type FetchParams = any[];
interface FetchData {
  (params: FetchParams): Promise<void>; 
}

export const generateJWT = async (setCookie: (name: string, value: string, options?: CustomCookieSetOptions) => void
) => {
    try {		
      const credentials = {
        username: process.env.username ?? "admin",
        identify: process.env.identify ?? "opwq@AK56",
      };
    
      const currentDT = new Date(); 
      const afterAYearDT = new Date(currentDT.setFullYear(currentDT.getFullYear() + 1));
      const graphSignInDatas  = await AuthenticationService.CheckUserAuthenticationMutation(credentials);   
    
      if (graphSignInDatas && graphSignInDatas?.GraphSignin ) {
        setCookie('lr_ap_tk', graphSignInDatas?.GraphSignin.jwt_access_token, { path: '/', expires: afterAYearDT, domain: process.env.DOMAIN})
        setCookie('lr_ap_refresh_tk', graphSignInDatas.GraphSignin.jwt_refresh_token, { path: '/', expires: afterAYearDT, domain: process.env.DOMAIN}) 
      }
    } catch (err) {
      console.error('Error during fetch data:', err);
    }
  };

export const generateJWTusingRefTkn = async (cookies: CookieValues, setCookie: (name: string, value: string, options?: CustomCookieSetOptions) => void
) => {
    try {
        const currentDT = new Date(); 
        const afterAYearDT = new Date(currentDT.setFullYear(currentDT.getFullYear() + 1));
        const graphSignInDatas = await AuthenticationService.getJWTUsingRefToken(cookies.lr_ap_refresh_tk || "");   
        
        if (graphSignInDatas && graphSignInDatas?.GraphRefreshJWT) {
            setCookie('lr_ap_tk', graphSignInDatas?.GraphRefreshJWT.jwt_access_token, { 
                path: '/', 
                expires: afterAYearDT, 
                domain: process.env.DOMAIN 
            });
            setCookie('lr_ap_refresh_tk', graphSignInDatas.GraphRefreshJWT.jwt_refresh_token, { 
                path: '/', 
                expires: afterAYearDT, 
                domain: process.env.DOMAIN 
            });
        }
    } catch (err) {
      if (typeof err === 'string' && err.includes('JWT Refresh token error')) {
        try {
            await generateJWT(setCookie);
        } catch (jwtError) {
            throw new Error('Failed to get token');
        }
      }
      else{
          console.error('Error during refresh token:', err);
          throw new Error('Failed to get refresh token');
      }
    }
};

export const checkUserToken = (role:number, cookies: CookieValues, router: ReturnType<typeof useRouter>, removeCookie: (name: string) => void, params:string) => {
  const decodedUserData = cookies.lr_u_info ? decodeSimpleJWT(cookies.lr_u_info) : null;
  if (cookies.lr_usr_tkn && decodedUserData && decodedUserData.ar_id === role &&  role == RoleEnum.ADMIN) {
    if (isTokenExpired(cookies.lr_usr_tkn)) {
      removeCookie('lr_usr_tkn');
      router.push('/login/admin');
    } else {
      if(params === "/login/admin" )
        router.push('/admin/floor-plan');   
      return true;
    }
  }  
  else if(role == RoleEnum.ADMIN){
    router.push('/login/admin');    
  } 
  else if(role == RoleEnum.CUSTOMER){
    if(decodedUserData && decodedUserData.ar_id === role && cookies.lr_usr_tkn ){
      if (isTokenExpired(cookies.lr_usr_tkn)) {
        removeCookie('lr_usr_tkn');
        router.push('/');
      }
      else
      return true;
    }
    else{
      router.push('/');  
    }
  } 
  return false;
};

export const checkJWTToken = async (cookies: CookieValues, router: ReturnType<typeof useRouter>, removeCookie: (name: string) => void, setCookie: (name: string, value: string, options?: CustomCookieSetOptions) => void) => {  
  if (cookies.lr_ap_tk) {
    if (isTokenExpired(cookies.lr_ap_tk)) {
      removeCookie('lr_ap_tk');
      await generateJWTusingRefTkn(cookies, setCookie as (name: string, value: string, options?: CustomCookieSetOptions) => void);
    } 
  }
};

export const isTokenExpired = (token : string) => {
  if (!token) return true;
  try {
    const decodedToken = jwt.decode(token);
    
    if (!decodedToken || typeof decodedToken === 'string' || decodedToken == undefined) {
      return true;
    }
    const currentTime = Math.floor(Date.now() / 1000);
    if (decodedToken.exp !== undefined) {
      return decodedToken?.exp  < currentTime;
    }
  } catch (error) {
    console.error('Error decoding token:', error);
    return true;
  }
};

export const encodeSimpleJWT = (data:userDataInfo) => {
  const jsonData = JSON.stringify(data);
  return btoa(jsonData); 
};

export const decodeSimpleJWT = (token:string) => {
  if(token){
      try {
      const jsonData = atob(token); 
      return JSON.parse(jsonData);
      } catch (error) {
      console.error('Invalid token:', error);
      return null;
      }
  }
};

const handleErrorMessage =(message:string)=>{
  const userNotFoundPattern = /User not found for \[un_pe_pm: (.+?)\]/;
    if (userNotFoundPattern.test(message)) {
      message="User not found. please check your credentials.";
    } else if(message === "Error during fetch data"){
      message="Something went wrong please try again after sometime";
    } else {
      message= message || "An unexpected error occurred.";
    }
  
  toast.error(message, {
      position: "bottom-left",
      autoClose: 5000,
  });
}

export const handleFetchWithTokenRefresh = async (err :string, cookies:CookieValues, setCookie: (name: string, value: string, options?: CustomCookieSetOptions) => void, fetchData: FetchData, msg:string, params: FetchParams = []) => {
  const handleError = (message: string): void => {
    handleErrorMessage(message)
  };
  if (typeof err === 'string' && err.includes('Context creation failed')) {
      try {
          await generateJWTusingRefTkn(cookies, setCookie);
          await fetchData(params); 
      } catch (jwtError) {
          handleError(msg);
      }
  } 
  else if(typeof err === 'string' && err.includes('NetworkError when attempting to fetch resource.')) {
    handleError("We are unable to connect to the service right now. Please try again later.");
  }
  else {
      handleError(msg);
  }
};

export const slugToTitle = (slug: string) => {
  const words = slug.split('-'); 
  const title = words.map((word, index) => {
    if (/\d/.test(word)) {
      return word.charAt(0).toUpperCase() + word.slice(1); 
    } else {
      return word.charAt(0).toUpperCase() + word.slice(1); 
    }
  }).join(' '); 

  return title;
};

export const titleToSlug = (title:string) => {
  const slug = slugify(title, { lower: true });
  return slug;
}
