import { Alert, AlertType } from "@/components/alert";
import { DynamicTheme } from "@/components/dynamic-theme";
import { IdpSignin } from "@/components/idp-signin";
import { idpTypeToIdentityProviderType, PROVIDER_MAPPING } from "@/lib/idp";
import {
  addIDPLink,
  createUser,
  getBrandingSettings,
  getIDPByID,
  listUsers,
  retrieveIDPIntent,
} from "@/lib/zitadel";
import { AutoLinkingOption } from "@zitadel/proto/zitadel/idp/v2/idp_pb";
import { BrandingSettings } from "@zitadel/proto/zitadel/settings/v2/branding_settings_pb";
import { getLocale, getTranslations } from "next-intl/server";

async function loginFailed(branding?: BrandingSettings) {
  const locale = getLocale();
  const t = await getTranslations({ locale, namespace: "idp" });

  return (
    <DynamicTheme branding={branding}>
      <div className="flex flex-col items-center space-y-4">
        <h1>{t("loginError.title")}</h1>
        <div className="w-full">
          {<Alert type={AlertType.ALERT}>{t("loginError.title")}</Alert>}
        </div>
      </div>
    </DynamicTheme>
  );
}

async function loginSuccess(
  userId: string,
  idpIntent: { idpIntentId: string; idpIntentToken: string },
  authRequestId?: string,
  branding?: BrandingSettings,
) {
  const locale = getLocale();
  const t = await getTranslations({ locale, namespace: "idp" });

  return (
    <DynamicTheme branding={branding}>
      <div className="flex flex-col items-center space-y-4">
        <h1>{t("loginSuccess.title")}</h1>
        <div>
          {t("loginSuccess.description")}
          <IdpSignin
            userId={userId}
            idpIntent={idpIntent}
            authRequestId={authRequestId}
          />
        </div>
      </div>
    </DynamicTheme>
  );
}

async function linkingSuccess(
  userId: string,
  idpIntent: { idpIntentId: string; idpIntentToken: string },
  authRequestId?: string,
  branding?: BrandingSettings,
) {
  const locale = getLocale();
  const t = await getTranslations({ locale, namespace: "idp" });

  return (
    <DynamicTheme branding={branding}>
      <div className="flex flex-col items-center space-y-4">
        <h1>{t("linkingSuccess.title")}</h1>
        <div>
          {t("linkingSuccess.description")}
          <IdpSignin
            userId={userId}
            idpIntent={idpIntent}
            authRequestId={authRequestId}
          />
        </div>
      </div>
    </DynamicTheme>
  );
}

export default async function Page(props: {
  searchParams: Promise<Record<string | number | symbol, string | undefined>>;
  params: Promise<{ provider: string }>;
}) {
  const params = await props.params;
  const searchParams = await props.searchParams;
  const locale = getLocale();
  const t = await getTranslations({ locale, namespace: "idp" });
  const { id, token, authRequestId, organization, link } = searchParams;
  const { provider } = params;

  const branding = await getBrandingSettings(organization);

  if (!provider || !id || !token) {
    return loginFailed(branding);
  }

  const intent = await retrieveIDPIntent(id, token);

  const { idpInformation, userId } = intent;

  // sign in user. If user should be linked continue
  if (userId && !link) {
    // TODO: update user if idp.options.isAutoUpdate is true

    return loginSuccess(
      userId,
      { idpIntentId: id, idpIntentToken: token },
      authRequestId,
      branding,
    );
  }

  if (!idpInformation) {
    return loginFailed(branding);
  }

  const idp = await getIDPByID(idpInformation.idpId);
  const options = idp?.config?.options;

  if (!idp) {
    throw new Error("IDP not found");
  }

  const providerType = idpTypeToIdentityProviderType(idp.type);

  // search for potential user via username, then link
  if (options?.isLinkingAllowed) {
    let foundUser;
    const email = PROVIDER_MAPPING[providerType](idpInformation).email?.email;

    if (options.autoLinking === AutoLinkingOption.EMAIL && email) {
      foundUser = await listUsers({ email }).then((response) => {
        return response.result ? response.result[0] : null;
      });
    } else if (options.autoLinking === AutoLinkingOption.USERNAME) {
      foundUser = await listUsers(
        options.autoLinking === AutoLinkingOption.USERNAME
          ? { userName: idpInformation.userName }
          : { email },
      ).then((response) => {
        return response.result ? response.result[0] : null;
      });
    } else {
      foundUser = await listUsers({
        userName: idpInformation.userName,
        email,
      }).then((response) => {
        return response.result ? response.result[0] : null;
      });
    }

    if (foundUser) {
      const idpLink = await addIDPLink(
        {
          id: idpInformation.idpId,
          userId: idpInformation.userId,
          userName: idpInformation.userName,
        },
        foundUser.userId,
      ).catch((error) => {
        return (
          <DynamicTheme branding={branding}>
            <div className="flex flex-col items-center space-y-4">
              <h1>{t("linkingError.title")}</h1>
              <div className="w-full">
                {
                  <Alert type={AlertType.ALERT}>
                    {t("linkingError.description")}
                  </Alert>
                }
              </div>
            </div>
          </DynamicTheme>
        );
      });

      if (idpLink) {
        return linkingSuccess(
          foundUser.userId,
          { idpIntentId: id, idpIntentToken: token },
          authRequestId,
          branding,
        );
      }
    }
  }

  if (options?.isCreationAllowed && options.isAutoCreation) {
    const newUser = await createUser(providerType, idpInformation);

    if (newUser) {
      return (
        <DynamicTheme branding={branding}>
          <div className="flex flex-col items-center space-y-4">
            <h1>{t("registerSuccess.title")}</h1>
            <div>{t("registerSuccess.description")}</div>
          </div>
        </DynamicTheme>
      );
    }
  }

  // return login failed if no linking or creation is allowed and no user was found
  return loginFailed(branding);
}
