import React from "react";
import { useTranslation } from "react-i18next";
import { useConfig } from "#/hooks/query/use-config";
import { createPermissionGuard } from "#/utils/org/permission-guard";
import { useSettings } from "#/hooks/query/use-settings";
import { BrandButton } from "#/components/features/settings/brand-button";
import { useDeleteGitProviders } from "#/hooks/mutation/use-delete-git-providers";
import { GitHubTokenInput } from "#/components/features/settings/git-settings/github-token-input";
import { GitLabTokenInput } from "#/components/features/settings/git-settings/gitlab-token-input";
import { GitLabWebhookManager } from "#/components/features/settings/git-settings/gitlab-webhook-manager";
import { BitbucketTokenInput } from "#/components/features/settings/git-settings/bitbucket-token-input";
import { BitbucketDCTokenInput } from "#/components/features/settings/git-settings/bitbucket-dc-token-help-input";
import { BitbucketDCWebhookManager } from "#/components/features/settings/git-settings/bitbucket-dc-webhook-manager";
import { AzureDevOpsTokenInput } from "#/components/features/settings/git-settings/azure-devops-token-input";
import { ForgejoTokenInput } from "#/components/features/settings/git-settings/forgejo-token-input";
import { ConfigureGitHubRepositoriesAnchor } from "#/components/features/settings/git-settings/configure-github-repositories-anchor";
import { ConfigureAzureDevOpsAnchor } from "#/components/features/settings/git-settings/configure-azure-devops-anchor";
import { InstallSlackAppAnchor } from "#/components/features/settings/git-settings/install-slack-app-anchor";
import DebugStackframeDot from "#/icons/debug-stackframe-dot.svg?react";
import { I18nKey } from "#/i18n/declaration";
import {
  displayErrorToast,
  displaySuccessToast,
} from "#/utils/custom-toast-handlers";
import { retrieveAxiosErrorMessage } from "#/utils/retrieve-axios-error-message";
import { GitSettingInputsSkeleton } from "#/components/features/settings/git-settings/github-settings-inputs-skeleton";
import { useAddGitProviders } from "#/hooks/mutation/use-add-git-providers";
import { useUserProviders } from "#/hooks/use-user-providers";
import { ProjectManagementIntegration } from "#/components/features/settings/project-management/project-management-integration";
import { Typography } from "#/ui/typography";

export const clientLoader = createPermissionGuard("manage_integrations");

function GitSettingsScreen() {
  const { t } = useTranslation();

  const { mutate: saveGitProviders, isPending } = useAddGitProviders();
  const { mutate: disconnectGitTokens, isPending: isDisconnecting } =
    useDeleteGitProviders();

  const { data: settings, isLoading } = useSettings();
  const { providers } = useUserProviders();

  const { data: config } = useConfig();

  React.useEffect(() => {
    const params = new URLSearchParams(window.location.search);
    const jiraDcWebhookStatus = params.get("jira_dc_webhook");
    if (!jiraDcWebhookStatus) {
      return;
    }

    if (jiraDcWebhookStatus === "install_failed") {
      displayErrorToast(
        t(I18nKey.PROJECT_MANAGEMENT$JIRA_DC_WEBHOOK_INSTALL_FAILED),
      );
    } else if (jiraDcWebhookStatus === "installed") {
      displaySuccessToast(
        t(I18nKey.PROJECT_MANAGEMENT$JIRA_DC_WEBHOOK_SETUP_SAVED),
      );
    }

    params.delete("jira_dc_webhook");
    const query = params.toString();
    window.history.replaceState(
      null,
      "",
      `${window.location.pathname}${query ? `?${query}` : ""}${
        window.location.hash
      }`,
    );
  }, [t]);

  const [githubTokenInputHasValue, setGithubTokenInputHasValue] =
    React.useState(false);
  const [gitlabTokenInputHasValue, setGitlabTokenInputHasValue] =
    React.useState(false);
  const [bitbucketTokenInputHasValue, setBitbucketTokenInputHasValue] =
    React.useState(false);
  const [bitbucketDCTokenInputHasValue, setBitbucketDCTokenInputHasValue] =
    React.useState(false);
  const [azureDevOpsTokenInputHasValue, setAzureDevOpsTokenInputHasValue] =
    React.useState(false);
  const [forgejoTokenInputHasValue, setForgejoTokenInputHasValue] =
    React.useState(false);

  const [githubHostInputHasValue, setGithubHostInputHasValue] =
    React.useState(false);
  const [gitlabHostInputHasValue, setGitlabHostInputHasValue] =
    React.useState(false);
  const [bitbucketHostInputHasValue, setBitbucketHostInputHasValue] =
    React.useState(false);
  const [bitbucketDCHostInputHasValue, setBitbucketDCHostInputHasValue] =
    React.useState(false);
  const [azureDevOpsHostInputHasValue, setAzureDevOpsHostInputHasValue] =
    React.useState(false);
  const [forgejoHostInputHasValue, setForgejoHostInputHasValue] =
    React.useState(false);

  const existingGithubHost = settings?.provider_tokens_set.github;
  const existingGitlabHost = settings?.provider_tokens_set.gitlab;
  const existingBitbucketHost = settings?.provider_tokens_set.bitbucket;
  const existingBitbucketDCHost =
    settings?.provider_tokens_set.bitbucket_data_center;
  const existingAzureDevOpsHost = settings?.provider_tokens_set.azure_devops;
  const existingForgejoHost = settings?.provider_tokens_set.forgejo;

  const isSaas = config?.app_mode === "saas";
  const isGitHubTokenSet = providers.includes("github");
  const isGitLabTokenSet = providers.includes("gitlab");
  const isBitbucketTokenSet = providers.includes("bitbucket");
  const isBitbucketDCTokenSet = providers.includes("bitbucket_data_center");
  const isAzureDevOpsTokenSet = providers.includes("azure_devops");
  const isForgejoTokenSet = providers.includes("forgejo");

  const formAction = async (formData: FormData) => {
    const disconnectButtonClicked =
      formData.get("disconnect-tokens-button") !== null;

    if (disconnectButtonClicked) {
      disconnectGitTokens(undefined, {
        onSuccess: () => {
          displaySuccessToast(t(I18nKey.SETTINGS$SAVED));
        },
        onError: (error) => {
          const errorMessage = retrieveAxiosErrorMessage(error);
          displayErrorToast(errorMessage || t(I18nKey.ERROR$GENERIC));
        },
      });
      return;
    }

    const githubToken = (
      formData.get("github-token-input")?.toString() || ""
    ).trim();
    const gitlabToken = (
      formData.get("gitlab-token-input")?.toString() || ""
    ).trim();
    const bitbucketToken = (
      formData.get("bitbucket-token-input")?.toString() || ""
    ).trim();
    const bitbucketDCToken = (
      formData.get("bitbucket-dc-token-input")?.toString() || ""
    ).trim();
    const azureDevOpsToken = (
      formData.get("azure-devops-token-input")?.toString() || ""
    ).trim();
    const forgejoToken = (
      formData.get("forgejo-token-input")?.toString() || ""
    ).trim();
    const githubHost = (
      formData.get("github-host-input")?.toString() || ""
    ).trim();
    const gitlabHost = (
      formData.get("gitlab-host-input")?.toString() || ""
    ).trim();
    const bitbucketHost = (
      formData.get("bitbucket-host-input")?.toString() || ""
    ).trim();
    const bitbucketDCHost = (
      formData.get("bitbucket-dc-host-input")?.toString() || ""
    ).trim();
    const azureDevOpsHost = (
      formData.get("azure-devops-host-input")?.toString() || ""
    ).trim();
    const forgejoHost = (
      formData.get("forgejo-host-input")?.toString() || ""
    ).trim();

    // Create providers object with all tokens
    const providerTokens: Record<string, { token: string; host: string }> = {
      github: { token: githubToken, host: githubHost },
      gitlab: { token: gitlabToken, host: gitlabHost },
      bitbucket: { token: bitbucketToken, host: bitbucketHost },
      bitbucket_data_center: { token: bitbucketDCToken, host: bitbucketDCHost },
      azure_devops: { token: azureDevOpsToken, host: azureDevOpsHost },
      forgejo: { token: forgejoToken, host: forgejoHost },
    };

    saveGitProviders(
      {
        providers: providerTokens,
      },
      {
        onSuccess: () => {
          displaySuccessToast(t(I18nKey.SETTINGS$SAVED));
        },
        onError: (error) => {
          const errorMessage = retrieveAxiosErrorMessage(error);
          displayErrorToast(errorMessage || t(I18nKey.ERROR$GENERIC));
        },
        onSettled: () => {
          setGithubTokenInputHasValue(false);
          setGitlabTokenInputHasValue(false);
          setBitbucketTokenInputHasValue(false);
          setBitbucketDCTokenInputHasValue(false);
          setAzureDevOpsTokenInputHasValue(false);
          setForgejoTokenInputHasValue(false);
          setGithubHostInputHasValue(false);
          setGitlabHostInputHasValue(false);
          setBitbucketHostInputHasValue(false);
          setBitbucketDCHostInputHasValue(false);
          setAzureDevOpsHostInputHasValue(false);
          setForgejoHostInputHasValue(false);
        },
      },
    );
  };

  const formIsClean =
    !githubTokenInputHasValue &&
    !gitlabTokenInputHasValue &&
    !bitbucketTokenInputHasValue &&
    !bitbucketDCTokenInputHasValue &&
    !azureDevOpsTokenInputHasValue &&
    !forgejoTokenInputHasValue &&
    !githubHostInputHasValue &&
    !gitlabHostInputHasValue &&
    !bitbucketHostInputHasValue &&
    !bitbucketDCHostInputHasValue &&
    !azureDevOpsHostInputHasValue &&
    !forgejoHostInputHasValue;
  const shouldRenderGitHubConfigureButton = isSaas && config?.github_app_slug;
  const shouldRenderGitLabSection = isSaas && Boolean(config?.gitlab_enabled);
  const shouldRenderBitbucketDCSection =
    isSaas &&
    Boolean(config?.providers_configured?.includes("bitbucket_data_center"));
  const shouldRenderAzureDevOpsSection =
    isSaas && Boolean(config?.providers_configured?.includes("azure_devops"));
  const shouldRenderSlackSection = isSaas && Boolean(config?.slack_enabled);
  const shouldRenderProjectManagementIntegrations =
    config?.feature_flags?.enable_jira ||
    config?.feature_flags?.enable_jira_dc ||
    config?.feature_flags?.enable_linear;

  return (
    <form
      data-testid="git-settings-screen"
      action={formAction}
      className="flex flex-col h-full justify-between"
    >
      {!isLoading && (
        <div className="flex flex-col">
          {shouldRenderGitHubConfigureButton && (
            <>
              <div className="pb-1 flex flex-col">
                <h3 className="text-xl font-medium text-white">
                  {t(I18nKey.SETTINGS$GITHUB)}
                </h3>
                <ConfigureGitHubRepositoriesAnchor
                  slug={config.github_app_slug!}
                />
              </div>
              <div className="w-1/2 border-b border-gray-200" />
            </>
          )}

          {shouldRenderGitLabSection && (
            <>
              <div className="mt-6 flex flex-col gap-4 pb-8">
                <Typography.H3 className="text-xl">
                  {t(I18nKey.SETTINGS$GITLAB)}
                </Typography.H3>
                <div className="flex items-center">
                  <DebugStackframeDot
                    className="w-6 h-6 shrink-0"
                    color={isGitLabTokenSet ? "#BCFF8C" : "#FF684E"}
                  />
                  <Typography.Text
                    className="text-sm text-gray-400"
                    testId="gitlab-status-text"
                  >
                    {t(I18nKey.COMMON$STATUS)}:{" "}
                    {isGitLabTokenSet
                      ? t(I18nKey.STATUS$CONNECTED)
                      : t(I18nKey.SETTINGS$GITLAB_NOT_CONNECTED)}
                  </Typography.Text>
                </div>
                {isGitLabTokenSet && <GitLabWebhookManager />}
              </div>
              <div className="w-1/2 border-b border-gray-200" />
            </>
          )}

          {shouldRenderBitbucketDCSection && (
            <>
              <div className="mt-6 flex flex-col gap-4 pb-8">
                <Typography.H3 className="text-xl">
                  {t(I18nKey.BITBUCKET_DATA_CENTER$WEBHOOK_SECTION_TITLE)}
                </Typography.H3>
                <div className="flex items-center">
                  <DebugStackframeDot
                    className="w-6 h-6 shrink-0"
                    color={isBitbucketDCTokenSet ? "#BCFF8C" : "#FF684E"}
                  />
                  <Typography.Text
                    className="text-sm text-gray-400"
                    testId="bitbucket-dc-status-text"
                  >
                    {t(I18nKey.COMMON$STATUS)}:{" "}
                    {isBitbucketDCTokenSet
                      ? t(I18nKey.STATUS$CONNECTED)
                      : t(I18nKey.BITBUCKET_DATA_CENTER$NOT_CONNECTED)}
                  </Typography.Text>
                </div>
                {isBitbucketDCTokenSet && <BitbucketDCWebhookManager />}
              </div>
              <div className="w-1/2 border-b border-gray-200" />
            </>
          )}

          {shouldRenderAzureDevOpsSection && (
            <>
              <div className="mt-6 flex flex-col gap-4 pb-8">
                <Typography.H3 className="text-xl">
                  {t(I18nKey.SETTINGS$AZURE_DEVOPS)}
                </Typography.H3>
                <div className="flex items-center">
                  <DebugStackframeDot
                    className="w-6 h-6 shrink-0"
                    color={isAzureDevOpsTokenSet ? "#BCFF8C" : "#FF684E"}
                  />
                  <Typography.Text
                    className="text-sm text-gray-400"
                    testId="azure-devops-status-text"
                  >
                    {t(I18nKey.COMMON$STATUS)}:{" "}
                    {isAzureDevOpsTokenSet
                      ? t(I18nKey.STATUS$CONNECTED)
                      : t(I18nKey.AZURE_DEVOPS$NOT_CONNECTED)}
                  </Typography.Text>
                </div>
                <ConfigureAzureDevOpsAnchor />
              </div>
              <div className="w-1/2 border-b border-gray-200" />
            </>
          )}

          {shouldRenderSlackSection && (
            <>
              <div className="pb-1 mt-6 flex flex-col">
                <h3 className="text-xl font-medium text-white">
                  {t(I18nKey.SETTINGS$SLACK)}
                </h3>
                <InstallSlackAppAnchor />
              </div>
              <div className="w-1/2 border-b border-gray-200" />
            </>
          )}

          {shouldRenderProjectManagementIntegrations && !isLoading && (
            <div className="mt-6">
              <ProjectManagementIntegration />
            </div>
          )}

          <div className="flex flex-col gap-4">
            {!isSaas && (
              <GitHubTokenInput
                name="github-token-input"
                isGitHubTokenSet={isGitHubTokenSet}
                onChange={(value) => {
                  setGithubTokenInputHasValue(!!value);
                }}
                onGitHubHostChange={(value) => {
                  setGithubHostInputHasValue(!!value);
                }}
                githubHostSet={existingGithubHost}
              />
            )}

            {!isSaas && (
              <GitLabTokenInput
                name="gitlab-token-input"
                isGitLabTokenSet={isGitLabTokenSet}
                onChange={(value) => {
                  setGitlabTokenInputHasValue(!!value);
                }}
                onGitLabHostChange={(value) => {
                  setGitlabHostInputHasValue(!!value);
                }}
                gitlabHostSet={existingGitlabHost}
              />
            )}

            {!isSaas && (
              <BitbucketTokenInput
                name="bitbucket-token-input"
                isBitbucketTokenSet={isBitbucketTokenSet}
                onChange={(value) => {
                  setBitbucketTokenInputHasValue(!!value);
                }}
                onBitbucketHostChange={(value) => {
                  setBitbucketHostInputHasValue(!!value);
                }}
                bitbucketHostSet={existingBitbucketHost}
              />
            )}

            {!isSaas && (
              <BitbucketDCTokenInput
                name="bitbucket-dc-token-input"
                isBitbucketDCTokenSet={isBitbucketDCTokenSet}
                onChange={(value) => {
                  setBitbucketDCTokenInputHasValue(!!value);
                }}
                onBitbucketDCHostChange={(value) => {
                  setBitbucketDCHostInputHasValue(!!value);
                }}
                bitbucketDCHostSet={existingBitbucketDCHost}
              />
            )}

            {!isSaas && (
              <AzureDevOpsTokenInput
                name="azure-devops-token-input"
                isAzureDevOpsTokenSet={isAzureDevOpsTokenSet}
                onChange={(value) => {
                  setAzureDevOpsTokenInputHasValue(!!value);
                }}
                onAzureDevOpsHostChange={(value) => {
                  setAzureDevOpsHostInputHasValue(!!value);
                }}
                azureDevOpsHostSet={existingAzureDevOpsHost}
              />
            )}

            {!isSaas && (
              <ForgejoTokenInput
                name="forgejo-token-input"
                isForgejoTokenSet={isForgejoTokenSet}
                onChange={(value) => {
                  setForgejoTokenInputHasValue(!!value);
                }}
                onForgejoHostChange={(value) => {
                  setForgejoHostInputHasValue(!!value);
                }}
                forgejoHostSet={existingForgejoHost}
              />
            )}
          </div>
        </div>
      )}

      {isLoading && <GitSettingInputsSkeleton />}

      <div className="flex gap-6 p-6 justify-end">
        {!isSaas && (
          <>
            <BrandButton
              testId="disconnect-tokens-button"
              name="disconnect-tokens-button"
              type="submit"
              variant="secondary"
              isDisabled={
                isDisconnecting ||
                (!isGitHubTokenSet &&
                  !isGitLabTokenSet &&
                  !isBitbucketTokenSet &&
                  !isBitbucketDCTokenSet &&
                  !isAzureDevOpsTokenSet &&
                  !isForgejoTokenSet)
              }
            >
              {t(I18nKey.GIT$DISCONNECT_TOKENS)}
            </BrandButton>
            <BrandButton
              testId="submit-button"
              type="submit"
              variant="primary"
              isDisabled={isPending || formIsClean}
            >
              {!isPending && t("SETTINGS$SAVE_CHANGES")}
              {isPending && t("SETTINGS$SAVING")}
            </BrandButton>
          </>
        )}
      </div>
    </form>
  );
}

export default GitSettingsScreen;
