import { redirect, notFound } from "next/navigation";

import Survey from "@/components/pages/participant/opportunities/survey";
import { SurveyDataResponse } from "@/components/pages/participant/opportunities/survey-utils";
import { CORE_ENDPOINTS } from "@/constants/api-mappings/external-api-mapping";
import { retrieveUserSession, retrieveUserToken } from "@/lib/user-session";
import { INTERNAL_PAGES } from "@/constants/pages-mapping/internal-pages-mapping";
import { ApiError, reportSentryError } from "@/utils/sentry-utils";
import {
  checkIfOpportunityHasExpired,
  getOpportunitiesNotLoggedIn,
  getOpportunityById,
  verifyIfUserAppliedToJob,
} from "@/services/opportunities";
import OpportunityExpired from "@/components/pages/participant/opportunities/opportunity-expired";

type Params = Promise<{ id: number }>;

export async function generateMetadata({ params }: { params: Params }) {
  const { id } = await params;

  return {
    title: `Survey | Job ID: ${id}`,
  };
}

async function getQuestionnaireByJobId(jobId: number): Promise<any> {
  const userToken = await retrieveUserToken();
  const url = `${CORE_ENDPOINTS.getQuestionnaireByJobId(jobId)}?cache=false`;

  try {
    const response = await fetch(url, {
      method: "GET",
      headers: {
        "Content-Type": "application/json",
        Authorization: `Bearer ${userToken}`,
      },
      cache: "no-store",
    });

    if (!response.ok) {
      throw await ApiError.fromResponse(response);
    }

    const data: SurveyDataResponse = await response.json();
    return data;
  } catch (error) {
    const err = error as Error;
    reportSentryError(err, { jobId }, "Get questionnaire by job id error");
    return err;
  }
}

async function getQuestionnaireInPreview(previewToken: string): Promise<any> {
  const url = `${CORE_ENDPOINTS.questionnairePreview(previewToken)}&cache=false`;

  try {
    const response = await fetch(url, {
      method: "GET",
      headers: {
        "Content-Type": "application/json",
      },
      cache: "no-store",
    });

    if (!response.ok) {
      throw await ApiError.fromResponse(response);
    }

    const data: SurveyDataResponse = await response.json();
    return data;
  } catch (error) {
    const err = error as Error;
    reportSentryError(err, { previewToken }, "Get questionnaire preview error");
    return err;
  }
}

export default async function SurveyPage({
  params,
  searchParams,
}: {
  params: Params;
  searchParams?: Record<string, string | undefined>;
}) {
  const { id: jobId } = await params;

  const opportunityDetails = await getOpportunityById(jobId);

  if (!opportunityDetails) {
    notFound();
  }

  const isExpired = await checkIfOpportunityHasExpired(jobId);

  if (isExpired) {
    const { title } = opportunityDetails;

    const sort: { colId: string; sort: "desc" | "asc" } = {
      colId: "publishDate",
      sort: "desc",
    };
    const filterModel = {};
    const itemsPerPage = 5;
    const maxPage = 3;
    const randomPage = Math.floor(Math.random() * maxPage) + 1;

    const listOfOpportunities = await getOpportunitiesNotLoggedIn(
      itemsPerPage,
      randomPage,
      sort,
      filterModel,
    );

    const opportunityList = (listOfOpportunities.data || [])
      .filter((opp) => opp.jobId !== Number(jobId))
      .slice(0, 4);

    return (
      <OpportunityExpired
        relatedOpportunities={opportunityList}
        title={title}
      />
    );
  }

  const {
    sandbox,
    sandboxToken,
    full_journey,
    utm_source,
    utm_medium,
    utm_content,
  } = searchParams || {};
  const isSandbox = sandbox === "true";
  const isCampaign = full_journey === "true";

  /* 
  ┌─────────────────────────────────────────────────────────────────────────┐
  │  Sandbox/Preview mode                                                   │
  └─────────────────────────────────────────────────────────────────────────┘
 */

  if (isSandbox) {
    if (!sandboxToken) {
      redirect(`${INTERNAL_PAGES.participant.login}?jobIdRef=${jobId}`);
    }

    const questionnaireDetails = await getQuestionnaireInPreview(sandboxToken);
    const storageKey = `job-survey-sandbox-${jobId}`;

    return (
      <Survey
        isSandbox
        jobSurvey={questionnaireDetails}
        storageKey={storageKey}
      />
    );
  }

  /* 
  ┌─────────────────────────────────────────────────────────────────────────┐
  │  Normal mode                                                            │
  └─────────────────────────────────────────────────────────────────────────┘
 */
  const { userId, clientId } = (await retrieveUserSession()) || {};

  // Redirect if user is not logged in.
  if (!userId) {
    redirect(`${INTERNAL_PAGES.participant.login}?jobIdRef=${jobId}`);
  }

  const questionnaireDetails = await getQuestionnaireByJobId(jobId);
  const storageKey = `job-survey-${jobId}`;

  let hasParticipantApplied = false;

  if (userId) {
    hasParticipantApplied = await verifyIfUserAppliedToJob(jobId);
  }

  // Redirect if user is exclusive to client.
  if (clientId) {
    redirect(`${INTERNAL_PAGES.participant.opportunities.main}/${jobId}`);
  }

  // Redirect if user has already applied.
  if (hasParticipantApplied) {
    redirect(
      `${INTERNAL_PAGES.participant.opportunities.main}/${jobId}/already-applied`,
    );
  }

  const utmParams = {
    utm_source,
    utm_medium,
    utm_content,
  };

  return (
    <Survey
      isCampaign={isCampaign}
      jobSurvey={questionnaireDetails}
      storageKey={storageKey}
      utmParams={utmParams}
    />
  );
}
