import backgroundImage from "@Assets/images/background_refonte.svg";
import CoffreIcon from "@Assets/logo_small_blue.svg";
import Auth from "@Front/Api/Auth/IdNot";
import Loader from "@Front/Components/DesignSystem/Loader";
import Typography, { ETypo, ETypoColor } from "@Front/Components/DesignSystem/Typography";
import HelpBox from "@Front/Components/Elements/HelpBox";
import DefaultDoubleSidePage from "@Front/Components/LayoutTemplates/DefaultDoubleSidePage";
import Module from "@Front/Config/Module";
import UserStore from "@Front/Stores/UserStore";
import CookieService from "@Front/Services/CookieService/CookieService";
import Image from "next/image";
import { useRouter } from "next/router";
import React, { useEffect, useState } from "react";
import classes from "./classes.module.scss";

// Importer les composants de UI pour les barres de progression
import { LinearProgress, Box, Typography as MuiTypography } from "@mui/material";

import AuthModal from "src/sdk/AuthModal";

import MessageBus from "src/sdk/MessageBus";
import Iframe from "src/sdk/Iframe";

import LoaderService from "src/common/Api/LeCoffreApi/sdk/Loader/LoaderService";
import { ProgressInfo } from "src/common/Api/LeCoffreApi/sdk/ImportData";

export default function LoginCallBack() {
  const router = useRouter();
  const [isAuthModalOpen, setIsAuthModalOpen] = useState(false);
  const [isConnected, setIsConnected] = useState(false);

  // États pour les barres de progression
  const [showProgress, setShowProgress] = useState(false);
  const [progressInfo, setProgressInfo] = useState<ProgressInfo>({
    globalProgress: 0,
    currentStep: '',
    stepProgress: 0,
    description: ''
  });

  const waitForUserInfo = (): Promise<any> => {
    return new Promise((resolve, reject) => {
      if (UserStore.instance.getUser()) {
        resolve(UserStore.instance.getUser());
        return;
      }
      
      // Poll for userInfo every 100ms
      const checkInterval = setInterval(() => {
        if (UserStore.instance.getUser()) {
          clearInterval(checkInterval);
          resolve(UserStore.instance.getUser());
        }
      }, 100);
      
      // Timeout after 60 seconds
      setTimeout(() => {
        clearInterval(checkInterval);
        reject(new Error('Timeout waiting for user info'));
      }, 60000);
    });
  };

  useEffect(() => {
    async function getUser() {
      UserStore.instance.disconnect();

      // TODO: review
      // HACK: If start with http://local.lecoffreio.4nkweb:3000/authorized-client 
      //       Replace with http://localhost:3000/authorized-client
      if (window.location.href.startsWith('http://local.lecoffreio.4nkweb')) {
        window.location.href = window.location.href.replace('http://local.lecoffreio.4nkweb:3000/authorized-client', 'http://localhost:3000/authorized-client');
        return;
      }

      const code = router.query["code"];
      if (code) {
        try {
          // Nettoyer l'URL pour ne garder que la racine
          const rootUrl = window.location.origin;
          if (window.location.href !== rootUrl) {
            window.history.replaceState({}, document.title, rootUrl);
          }

          const user: any = await Auth.getInstance().idNotAuth(code as string);
          
          // Extract both user data and auth token from the response
          const { idNotUser, authToken } = user;
          
          if (!authToken) {
            console.error('[LoginCallback] No authToken received from backend');
            return router.push(Module.getInstance().get().modules.pages.Login.props.path + "?error=1");
          }
          
          // Store the auth token for API authentication
          // TODO The authToken is just a uuid for now, it's very broken
          CookieService.getInstance().setCookie("leCoffreAccessToken", authToken);

          // Test that we can get user info and the authToken works
          // TODO test that what's returned is identical to what we got before
          const userInfoResponse = await Auth.getInstance().getIdNotUser();
          console.log('[LoginCallback] userInfoResponse:', userInfoResponse);
          if (!userInfoResponse || !userInfoResponse.success || !userInfoResponse.data) {
            console.error('[LoginCallback] No userInfo received from backend');
            return router.push(Module.getInstance().get().modules.pages.Login.props.path + "?error=1");
          }

          // Store user info as a cookie
          CookieService.getInstance().setCookie("leCoffreUserInfo", JSON.stringify(userInfoResponse.data));
          setIsAuthModalOpen(true);
          console.log('[LoginCallback] authToken stored successfully');
          
          return;
        } catch (e: any) {
          if (e.http_status === 401 && e.message === "Email not found") {
            return router.push(Module.getInstance().get().modules.pages.Login.props.path + "?error=3");
          }
          if (e.http_status === 409) {
            return router.push(Module.getInstance().get().modules.pages.Login.props.path + "?error=4");
          }
          return router.push(Module.getInstance().get().modules.pages.Login.props.path + "?error=1");
        }
      }
      return router.push(Module.getInstance().get().modules.pages.Login.props.path + "?error=2");
    }
    getUser();
  }, [router]);

  return (
    <DefaultDoubleSidePage title={"Login"} image={backgroundImage}>
      <div className={classes["root"]} style={showProgress ? { width: 'calc(75vw - 70px)', maxWidth: '1130px', margin: '80px 0 80px 70px' } : undefined}>
        <div className={classes["title-container"]}>
          <Image alt="coffre" src={CoffreIcon} width={56} />
          <Typography typo={ETypo.TITLE_H1} color={ETypoColor.TEXT_ACCENT}>
            Connexion à votre espace professionnel
          </Typography>
        </div>

        {!showProgress ? (
          <Loader color={"var(--secondary-default-base, #FF4617)"} width={29} />
        ) : (
          <Box sx={{ width: '100%', mb: 4, p: 4, px: 6, borderRadius: 2, boxShadow: '0 4px 12px rgba(0, 0, 0, 0.08)' }}>
            <MuiTypography variant="h6" align="center" sx={{ mb: 2, fontWeight: 600, color: 'var(--primary-default-base, #006BE0)' }}>
              Importation des données
            </MuiTypography>
            {/* Progression globale */}
            <Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', mb: 1 }}>
              <MuiTypography variant="body2" sx={{ fontWeight: 500, color: 'text.primary' }}>
                Progression globale: <span style={{ color: 'var(--secondary-default-base, #FF4617)', fontWeight: 600 }}>{Math.round(progressInfo.globalProgress)}%</span>
              </MuiTypography>
              <MuiTypography variant="body2" sx={{ fontWeight: 500, color: 'text.secondary' }}>
                <span style={{ fontStyle: 'italic' }}>{progressInfo.currentStep}</span>
              </MuiTypography>
            </Box>
            <LinearProgress
              variant="determinate"
              value={progressInfo.globalProgress}
              sx={{
                height: 12,
                borderRadius: 6,
                backgroundColor: 'rgba(255, 70, 23, 0.15)',
                '& .MuiLinearProgress-bar': {
                  backgroundColor: 'var(--secondary-default-base, #FF4617)',
                  transition: 'transform 0.5s ease'
                }
              }}
            />

            {/* Progression par étape */}
            <Box sx={{ mt: 2, mb: 1 }}>
              <MuiTypography variant="body2" sx={{ display: 'flex', justifyContent: 'space-between', fontWeight: 500, color: 'text.primary' }}>
                <span>Progression de l'étape: <span style={{ color: 'var(--primary-default-base, #006BE0)', fontWeight: 600 }}>{Math.round(progressInfo.stepProgress)}%</span></span>
                <span style={{ maxWidth: '60%', textAlign: 'right', color: 'text.secondary' }}>{progressInfo.description || ''}</span>
              </MuiTypography>
            </Box>
            <LinearProgress
              variant="determinate"
              value={progressInfo.stepProgress}
              sx={{
                height: 8,
                borderRadius: 4,
                backgroundColor: 'rgba(0, 107, 224, 0.15)',
                '& .MuiLinearProgress-bar': {
                  backgroundColor: 'var(--primary-default-base, #006BE0)',
                  transition: 'transform 0.3s ease'
                }
              }}
            />
          </Box>
        )}
        <div />
        <HelpBox
          title="Vous n'arrivez pas à vous connecter ?"
          description="Notre équipe de support est là pour vous aider."
          button={{ text: "Contacter l'administrateur", link: "mailto:support@lecoffre.io" }}
        />
        {isAuthModalOpen && <AuthModal
          isOpen={isAuthModalOpen}
          onClose={() => {
            setIsAuthModalOpen(false);
            setIsConnected(true);
            setTimeout(() => {
              LoaderService.getInstance().show();
              MessageBus.getInstance().initMessageListener();
              MessageBus.getInstance().isReady().then(async () => {
                try {
                  const userInfo = await waitForUserInfo();
                  if (!userInfo) {
                    console.error('[LoginCallback] No userInfo received from backend');
                    return router.push(Module.getInstance().get().modules.pages.Login.props.path + "?error=1");
                  }
                  // console.log('userInfo : ', userInfo);

                  // Here we are now authenticated with idNot, we have our idnot user info
                  // We also have a device and it should be paired
                  // What we may not have yet is a collaborator process
                  // Office may not have a process too
                  let collaboratorProcess: { processId: string, processData: { [key: string]: any } } | null = null;
                  let officeProcess: { processId: string, processData: { [key: string]: any } } | null = null;
                  
                  // Initialize collaborator process
                  try {
                    // Wait for pairing ID to be available before proceeding
                    const pairingId = await MessageBus.getInstance().getPairingId();
                    console.log('[LoginCallback] Pairing ID obtained:', pairingId);
                    // Check if we are part of the right collaborator process
                    const myCollaboratorProcessesData = await MessageBus.getInstance().getProcessesDecoded((processId: string, values: { [key: string]: any }) => {
                      return values['utype'] === 'collaborator' 
                        && values['idNot'] === userInfo.idNot
                        && values['isDeleted'] === 'false';
                    });
                    if (myCollaboratorProcessesData && Object.keys(myCollaboratorProcessesData).length !== 0) {
                      collaboratorProcess = { processId: Object.keys(myCollaboratorProcessesData)[0]!, processData: Object.values(myCollaboratorProcessesData)[0]! };
                    } else {
                      const res = await Auth.getInstance().getUserProcessByIdNot(pairingId);
                      if (res.success) {
                        collaboratorProcess = res.data;
                      } else {
                        console.error('[LoginCallback] Error getting collaborator process');
                        router.push(Module.getInstance().get().modules.pages.Login.props.path + "?error=1");
                        return;
                      }
                      // await new Promise(resolve => setTimeout(resolve, 100));
                    }
                    // If we're on a new device, signer should notice and add us to the process
                    // TODO check that we're part of the collaborator process
                  } catch (error: any) {
                    console.error('[LoginCallback] Error getting collaborator process:', error);
                    if (error.message === 'Timeout waiting for pairing ID') {
                      console.error('[LoginCallback] Pairing ID not available after timeout');
                      return router.push(Module.getInstance().get().modules.pages.Login.props.path + "?error=1");
                    }
                    // If we can't get collaborator process, we can't proceed
                    return router.push(Module.getInstance().get().modules.pages.Login.props.path + "?error=1");
                  }

                  // Initialize office process
                  try {
                    // Wait for pairing ID to be available before proceeding
                    const pairingId = await MessageBus.getInstance().getPairingId();
                    console.log('[LoginCallback] Pairing ID obtained:', pairingId);
                    // Now we need to check for office process
                    const myOfficeProcessesData = await MessageBus.getInstance().getProcessesDecoded((processId: string, values: { [key: string]: any }) => {
                      return values['utype'] === 'office' 
                        && values['idNot'] === userInfo.office.idNot
                        && values['isDeleted'] === 'false';
                    });
                    if (myOfficeProcessesData && Object.keys(myOfficeProcessesData).length !== 0) {
                      officeProcess = { processId: Object.keys(myOfficeProcessesData)[0]!, processData: Object.values(myOfficeProcessesData)[0]! };
                    } else {
                      const res = await Auth.getInstance().getUserProcessByIdNot(pairingId);
                      if (res.success) {
                        officeProcess = res.data;
                      } else {
                        console.error('[LoginCallback] Error getting collaborator process');
                        router.push(Module.getInstance().get().modules.pages.Login.props.path + "?error=1");
                        return;
                      }
                    }

                    // TODO Check that we're part of the office process
                    // For now we rely on the signer to get office data, for the sake of simplicity
                  } catch (error: any) {
                    console.error('[LoginCallback] Error getting office process:', error);
                    return router.push(Module.getInstance().get().modules.pages.Login.props.path + "?error=1");
                  }

                  // Verify both processes are initialized before proceeding
                  if (!collaboratorProcess || !officeProcess) {
                    console.error('[LoginCallback] Failed to initialize required processes');
                    router.push(Module.getInstance().get().modules.pages.Login.props.path + "?error=1");
                    return;
                  }

                  if (!UserStore.instance.connect(collaboratorProcess.processData, officeProcess.processData)) {
                    console.error('[LoginCallback] collaborator not connected');
                    router.push(Module.getInstance().get().modules.pages.Login.props.path + "?error=1");
                    return;
                  }

                  window.location.href = Module.getInstance().get().modules.pages.Folder.props.path;
                } catch (error) {
                  console.error('[LoginCallback] Error waiting for user info or processing collaborator:', error);
                  router.push(Module.getInstance().get().modules.pages.Login.props.path + "?error=1");
                } finally {
                  MessageBus.getInstance().destroyMessageListener();
                  LoaderService.getInstance().hide();
                }
                return;
              });
            }, 100);
          }}
        />}
        {isConnected && <Iframe />}
      </div>
    </DefaultDoubleSidePage>
  );
}
