"use client";

import { useEffect, useRef, useState } from "react";
import { Survey as SurveyCore } from "survey-react-ui";
import "survey-core/survey-core.css";
import "@/components/pages/participant/opportunities/custom-styles.css";
import { ITheme, SurveyModel } from "survey-core";
import { useTheme } from "next-themes";
import { useRouter, useSearchParams } from "next/navigation";
import { useDisclosure } from "@nextui-org/react";
import Link from "next/link";

import {
  convertBackendToSurveyJS,
  SurveyDataResponse,
  applyNoneExclusivity,
  collectExistingNoneChoices,
} from "@/components/pages/participant/opportunities/survey-utils";
import Breadcrumbs from "@/components/common/breadcrumbs";
import { submitEnrolment } from "@/services/enrolments";
import { INTERNAL_PAGES } from "@/constants/pages-mapping/internal-pages-mapping";
import LightTheme from "@/components/pages/participant/opportunities/themes/light.json";
import DarkTheme from "@/components/pages/participant/opportunities/themes/dark.json";
import { registerReferralComponent } from "@/components/pages/participant/opportunities/partials/register-referral-info";
import SurveyPreviewModal from "@/components/pages/participant/opportunities/partials/survey-preview-modal";
import SubmitSurveyErrorModal from "@/components/pages/participant/opportunities/partials/submit-survey-error-modal";
import { reportSentryError } from "@/utils/sentry-utils";

registerReferralComponent();

type SurveyProps = {
  jobSurvey: SurveyDataResponse;
  storageKey: string;
  isSandbox?: boolean;
  isCampaign?: boolean;
  utmParams?: {
    utm_source?: string;
    utm_medium?: string;
    utm_content?: string;
  };
};

// note for the future: SurveyJS is not handling very well the usage of hooks to save/get information, causing loops and side effects unwanted.
// for now, let's keep the usage of the regular window.localStorage.

function Survey({
  jobSurvey,
  storageKey,
  isSandbox,
  isCampaign,
  utmParams,
}: SurveyProps) {
  const { theme } = useTheme();
  const searchParams = useSearchParams();
  const queryString = searchParams.toString();
  const router = useRouter();
  const convertedSurvey = convertBackendToSurveyJS(jobSurvey);
  const { title } = convertedSurvey;
  const { isOpen, onOpen, onClose } = useDisclosure();
  const [sandboxPreviewData, setSandboxPreviewData] = useState<any>(null);
  const surveyRef = useRef<SurveyModel | null>(null);

  const saveSurveyProgress = (survey: any) => {
    const data = survey.data;
    data.pageNo = survey.currentPageNo;
    window.localStorage.setItem(storageKey, JSON.stringify(data));
  };

  const mapSurveyValuesToText = (surveyData: any, surveyModel: SurveyModel) => {
    const mappedData = { ...surveyData };

    surveyModel.pages.forEach((page) => {
      page.elements.forEach((element) => {
        const question = surveyModel.getQuestionByName(element.name);
        const questionType = question?.getType();

        switch (questionType) {
          case "radiogroup": {
            const selectedValue = surveyData[element.name];
            const selectedChoice = question?.choices?.find(
              (choice: any) => choice.value === selectedValue,
            );
            if (selectedChoice) {
              mappedData[element.name] = selectedChoice.text;
            }
            break;
          }
          case "checkbox": {
            const selectedValues = surveyData[element.name];
            if (Array.isArray(selectedValues)) {
              mappedData[element.name] = selectedValues.map((value: string) => {
                const selectedChoice = question?.choices?.find(
                  (choice: any) => choice.value === value,
                );
                return selectedChoice?.text || value;
              });
            }
            break;
          }
          case "text": {
            mappedData[element.name] = surveyData[element.name];
            break;
          }
          case "referral": {
            const referralData = surveyData[element.name];

            if (referralData && referralData.firstName) {
              const { firstName, lastName, email } = referralData;
              mappedData[element.name] = `${firstName} ${lastName} (${email})`;
            } else {
              mappedData[element.name] = null;
            }
            break;
          }
          default: {
            mappedData[element.name] = surveyData[element.name];
            break;
          }
        }
      });
    });

    return mappedData;
  };

  const mapSurveyValuesForPreview = (
    surveyData: any,
    surveyModel: SurveyModel,
  ) => {
    const mappedData: any = {};

    surveyModel.pages.forEach((page) => {
      page.elements.forEach((element) => {
        const question = surveyModel.getQuestionByName(element.name);
        const questionType = question?.getType();
        const questionTitle = question?.title || element.name;

        switch (questionType) {
          case "radiogroup": {
            const selectedValue = surveyData[element.name];
            const selectedChoice = question?.choices?.find(
              (choice: any) => choice.value === selectedValue,
            );
            if (selectedChoice) {
              mappedData[questionTitle] = selectedChoice.text;
            }
            break;
          }
          case "checkbox": {
            const selectedValues = surveyData[element.name];
            if (Array.isArray(selectedValues)) {
              mappedData[questionTitle] = selectedValues.map(
                (value: string) => {
                  const selectedChoice = question?.choices?.find(
                    (choice: any) => choice.value === value,
                  );
                  return selectedChoice?.text || value;
                },
              );
            }
            break;
          }
          case "text": {
            mappedData[questionTitle] = surveyData[element.name];
            break;
          }
          case "referral": {
            const referralData = surveyData[element.name];
            if (referralData && referralData.firstName) {
              const { firstName, lastName, email } = referralData;
              mappedData[questionTitle] = `${firstName} ${lastName} (${email})`;
            } else {
              mappedData[questionTitle] = null;
            }
            break;
          }
          default: {
            mappedData[questionTitle] = surveyData[element.name];
            break;
          }
        }

        const commentKey = `${element.name}-Comment`;

        if (surveyData[commentKey]) {
          const commentValue = surveyData[commentKey];
          mappedData[`${questionTitle} (comment)`] = commentValue;
        }
      });
    });

    return mappedData;
  };

  const handleTerminateSession = async () => {
    // Full-journey campaign users should be signed out after applying, but the
    // configured SurveyJS or internal completion route must control navigation.
    const response = await fetch("/participant/auth/full-journey-complete", {
      method: "POST",
      credentials: "same-origin",
    });

    if (!response.ok) {
      throw new Error(
        `Full-journey session cleanup failed with status ${response.status}.`,
      );
    }
  };

  if (!surveyRef.current) {
    const survey = new SurveyModel(convertedSurvey);
    survey.applyTheme(
      theme === "dark" ? (DarkTheme as ITheme) : (LightTheme as ITheme),
    );
    survey.showCompletedPage = false;
    survey.showTitle = false;
    survey.showPageNumbers = false;
    survey.showProgressBar = "off";
    survey.showPageTitles = false;
    survey.showNavigationButtons = true;

    collectExistingNoneChoices(survey);
    applyNoneExclusivity(survey);

    survey.onValueChanged.add(saveSurveyProgress);
    survey.onCurrentPageChanged.add(saveSurveyProgress);

    survey.onCompleting.add(async (sender, options) => {
      if (isSandbox) {
        return;
      }

      try {
        const surveyResponseWithText = mapSurveyValuesToText(
          sender.data,
          survey,
        );
        const { JobId: jobId } = jobSurvey;
        const response = await submitEnrolment({
          jobId,
          surveyResponse: surveyResponseWithText,
          utmParams,
        });

        if (!response.success) {
          options.allow = false;
          onOpen();
          return;
        }
      } catch {
        options.allow = false;
        onOpen();
        return;
      }

      if (isCampaign) {
        try {
          await handleTerminateSession();
        } catch (error) {
          reportSentryError(
            error,
            { jobId: jobSurvey.JobId },
            "Full-journey session cleanup error",
          );
        }
      }
    });

    survey.onComplete.add((sender) => {
      if (isSandbox) {
        const surveyResponseWithText = mapSurveyValuesForPreview(
          sender.data,
          survey,
        );
        setSandboxPreviewData(surveyResponseWithText);
        onOpen();
        return;
      }

      window.localStorage.removeItem(storageKey);

      if (sender.getNavigateToUrl()) {
        return;
      }

      const { JobId: jobId } = jobSurvey;

      if (isCampaign) {
        router.push(
          `${INTERNAL_PAGES.participant.opportunities.main}/${jobId}/thanks-for-applying?${queryString}`,
        );
      } else {
        const thanksUrl = `${INTERNAL_PAGES.participant.opportunities.main}/${jobId}/thanks-for-applying`;
        const utmQuery = utmParams
          ? new URLSearchParams(
              Object.entries(utmParams).filter(
                (entry): entry is [string, string] => !!entry[1],
              ),
            ).toString()
          : "";

        router.push(utmQuery ? `${thanksUrl}?${utmQuery}` : thanksUrl);
      }
    });

    surveyRef.current = survey;
  }

  const survey = surveyRef.current;

  const handleOnClose = () => {
    setSandboxPreviewData(null);
    onClose();
  };

  const handleResetSandbox = () => {
    survey.clear(false);
    survey.currentPageNo = 0;
    window.localStorage.setItem(storageKey, "");
    setSandboxPreviewData(null);
    onClose();
  };

  useEffect(() => {
    survey.applyTheme(
      theme === "dark" ? (DarkTheme as ITheme) : (LightTheme as ITheme),
    );
  }, [survey, theme]);

  useEffect(() => {
    const prevData = window.localStorage.getItem(storageKey) || null;

    if (prevData) {
      const data = JSON.parse(prevData);
      survey.data = data;

      if (data.pageNo) {
        survey.currentPageNo = data.pageNo;
      }
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  return (
    <div className="flex flex-col min-h-screen bg-participant-light dark:bg-participant-dark">
      {isSandbox && (
        <div className="bg-amber-500 dark:bg-amber-600 text-black dark:text-white px-6 py-3 font-inter font-bold text-center text-sm">
          🔧 Sandbox mode: Preview only
        </div>
      )}

      <div className="p-6 flex flex-col">
        <Breadcrumbs />
        <h1 className="font-inter font-black text-4xl tracking-tight">
          {title}
        </h1>
        <span className="font-noto text-sm my-3">
          Your progress will be saved automatically. If you leave the page, you
          can return to it later, but we advise you to finish the questionnaire
          in one go to avoid data loss. Please use the buttons
          &apos;Previous&apos; and &apos;Next&apos; to navigate between pages.
          When you&apos;re ready to submit your responses, click the
          &apos;Complete&apos; button.
        </span>
      </div>

      <main className="grow overflow-auto" id="main-content">
        <SurveyCore model={survey} />
        <p className="text-xs text-gray-500 dark:text-gray-400 text-center mt-2 px-4">
          By submitting your application, you acknowledge our recently updated{" "}
          <Link
            className="underline hover:text-gray-700 dark:hover:text-gray-200"
            href={`${INTERNAL_PAGES.participant.howItWorks.policies}/participant-data-privacy-policy`}
            target="_blank"
          >
            Privacy Policy
          </Link>
          .
        </p>
      </main>

      {isSandbox && sandboxPreviewData && (
        <SurveyPreviewModal
          isOpen={isOpen}
          sandboxPreviewData={sandboxPreviewData}
          onClickReset={handleResetSandbox}
          onClose={handleOnClose}
        />
      )}

      {isOpen && !isSandbox && (
        <SubmitSurveyErrorModal
          isOpen={isOpen}
          oppTitle={title}
          onClose={handleOnClose}
        />
      )}
    </div>
  );
}

export default Survey;
