import { test } from "@playwright/test";
import {
  ProvidersPage,
  AWSProviderData,
  AWSOrganizationsProviderCredential,
  AWSOrganizationsProviderData,
  AWSProviderCredential,
  AWS_CREDENTIAL_OPTIONS,
  AZUREProviderData,
  AZUREProviderCredential,
  AZURE_CREDENTIAL_OPTIONS,
  M365ProviderData,
  M365ProviderCredential,
  M365_CREDENTIAL_OPTIONS,
  KubernetesProviderData,
  KubernetesProviderCredential,
  KUBERNETES_CREDENTIAL_OPTIONS,
  GCPProviderData,
  GCPProviderCredential,
  GCP_CREDENTIAL_OPTIONS,
  GitHubProviderData,
  GitHubProviderCredential,
  GITHUB_CREDENTIAL_OPTIONS,
  OCIProviderData,
  OCIProviderCredential,
  OCI_CREDENTIAL_OPTIONS,
  AlibabaCloudProviderData,
  AlibabaCloudProviderCredential,
  ALIBABACLOUD_CREDENTIAL_OPTIONS,
  GoogleWorkspaceProviderData,
  GoogleWorkspaceProviderCredential,
  GOOGLEWORKSPACE_CREDENTIAL_OPTIONS,
  OktaProviderData,
  OktaProviderCredential,
  OKTA_CREDENTIAL_OPTIONS,
  VercelProviderData,
  VercelProviderCredential,
  VERCEL_CREDENTIAL_OPTIONS,
} from "./providers-page";
import fs from "fs";
import { deleteProviderIfExists } from "../helpers";

test.describe("Add Provider", () => {
  test.describe.serial("Add AWS Provider", () => {
    // Providers page object
    let providersPage: ProvidersPage;
    // Test data from environment variables
    const accountId = process.env.E2E_AWS_PROVIDER_ACCOUNT_ID ?? "";
    const accessKey = process.env.E2E_AWS_PROVIDER_ACCESS_KEY ?? "";
    const secretKey = process.env.E2E_AWS_PROVIDER_SECRET_KEY ?? "";
    const roleArn = process.env.E2E_AWS_PROVIDER_ROLE_ARN ?? "";
    const organizationId = process.env.E2E_AWS_ORGANIZATION_ID ?? "";
    const organizationRoleArn = process.env.E2E_AWS_ORGANIZATION_ROLE_ARN ?? "";

    // Setup before each test
    test.beforeEach(async ({ page }) => {
      test.skip(!accountId, "E2E_AWS_PROVIDER_ACCOUNT_ID is not set");
      providersPage = new ProvidersPage(page);
      await deleteProviderIfExists(providersPage, accountId!);
    });

    // Use admin authentication for provider management
    test.use({ storageState: "playwright/.auth/admin_user.json" });

    test(
      "should add a new AWS provider with static credentials",
      {
        tag: [
          "@critical",
          "@e2e",
          "@providers",
          "@aws",
          "@serial",
          "@PROVIDER-E2E-001",
        ],
      },
      async ({ page }) => {
        // Validate required environment variables
        if (!accountId || !accessKey || !secretKey) {
          throw new Error(
            "E2E_AWS_PROVIDER_ACCOUNT_ID, E2E_AWS_PROVIDER_ACCESS_KEY, and E2E_AWS_PROVIDER_SECRET_KEY environment variables are not set",
          );
        }

        // Prepare test data for AWS provider
        const awsProviderData: AWSProviderData = {
          accountId: accountId,
          alias: "Test E2E AWS Account - Credentials",
        };

        // Prepare static credentials
        const staticCredentials: AWSProviderCredential = {
          type: AWS_CREDENTIAL_OPTIONS.AWS_CREDENTIALS,
          accessKeyId: accessKey,
          secretAccessKey: secretKey,
        };

        // Navigate to providers page
        await providersPage.goto();
        await providersPage.verifyPageLoaded();

        // Start adding new provider
        await providersPage.clickAddProvider();
        await providersPage.verifyConnectAccountPageLoaded();

        // Select AWS provider
        await providersPage.selectAWSProvider();

        // Fill provider details
        await providersPage.fillAWSProviderDetails(awsProviderData);
        await providersPage.clickNext();

        await providersPage.verifyCredentialsPageLoaded();

        // Select static credentials type
        await providersPage.selectCredentialsType(
          AWS_CREDENTIAL_OPTIONS.AWS_CREDENTIALS,
        );

        // Fill static credentials
        await providersPage.fillStaticCredentials(staticCredentials);
        await providersPage.clickNext();

        // Confirm the provider connection without launching a scan
        await providersPage.completeProviderConnectionWithoutLaunchingScan(
          accountId,
        );
      },
    );

    test(
      "should add a new AWS provider with assume role credentials with Access Key and Secret Key",
      {
        tag: [
          "@critical",
          "@e2e",
          "@providers",
          "@aws",
          "@serial",
          "@PROVIDER-E2E-002",
        ],
      },
      async ({ page }) => {
        // Validate required environment variables
        if (!roleArn) {
          throw new Error(
            "E2E_AWS_PROVIDER_ROLE_ARN environment variable is not set",
          );
        }

        // Prepare test data for AWS provider
        const awsProviderData: AWSProviderData = {
          accountId: accountId,
          alias: "Test E2E AWS Account - Credentials",
        };

        // Prepare role-based credentials
        const roleCredentials: AWSProviderCredential = {
          type: AWS_CREDENTIAL_OPTIONS.AWS_ROLE_ARN,
          accessKeyId: accessKey,
          secretAccessKey: secretKey,
          roleArn: roleArn,
        };

        // Navigate to providers page
        await providersPage.goto();
        await providersPage.verifyPageLoaded();

        // Start adding new provider
        await providersPage.clickAddProvider();
        await providersPage.verifyConnectAccountPageLoaded();

        // Select AWS provider
        await providersPage.selectAWSProvider();

        // Fill provider details
        await providersPage.fillAWSProviderDetails(awsProviderData);
        await providersPage.clickNext();

        await providersPage.verifyCredentialsPageLoaded();

        // Select role credentials type
        await providersPage.selectCredentialsType(
          AWS_CREDENTIAL_OPTIONS.AWS_ROLE_ARN,
        );

        // Fill role credentials
        await providersPage.fillRoleCredentials(roleCredentials);
        await providersPage.clickNext();

        // Confirm the provider connection without launching a scan
        await providersPage.completeProviderConnectionWithoutLaunchingScan(
          accountId,
        );
      },
    );

    test(
      "should add a new AWS provider with assume role credentials using AWS SDK",
      {
        tag: [
          "@critical",
          "@e2e",
          "@providers",
          "@aws",
          "@serial",
          "@PROVIDER-E2E-011",
        ],
      },
      async ({ page }) => {
        // Validate required environment variables
        if (!accountId || !roleArn) {
          throw new Error(
            "E2E_AWS_PROVIDER_ACCOUNT_ID, and E2E_AWS_PROVIDER_ROLE_ARN environment variables are not set",
          );
        }

        // Prepare test data for AWS provider
        const awsProviderData: AWSProviderData = {
          accountId: accountId,
          alias: "Test E2E AWS Account - Credentials",
        };

        // Prepare role-based credentials
        const roleCredentials: AWSProviderCredential = {
          type: AWS_CREDENTIAL_OPTIONS.AWS_ROLE_ARN,
          roleArn: roleArn,
        };

        // Navigate to providers page
        await providersPage.goto();
        await providersPage.verifyPageLoaded();

        // Start adding new provider
        await providersPage.clickAddProvider();
        await providersPage.verifyConnectAccountPageLoaded();

        // Select AWS provider
        await providersPage.selectAWSProvider();

        // Fill provider details
        await providersPage.fillAWSProviderDetails(awsProviderData);
        await providersPage.clickNext();

        // Select role credentials type
        await providersPage.selectCredentialsType(
          AWS_CREDENTIAL_OPTIONS.AWS_ROLE_ARN,
        );
        await providersPage.verifyCredentialsPageLoaded();

        // Select Authentication Method
        await providersPage.selectAuthenticationMethod(
          AWS_CREDENTIAL_OPTIONS.AWS_SDK_DEFAULT,
        );

        // Fill role credentials
        await providersPage.fillRoleCredentials(roleCredentials);
        await providersPage.clickNext();

        // Confirm the provider connection without launching a scan
        await providersPage.completeProviderConnectionWithoutLaunchingScan(
          accountId,
        );
      },
    );

    test(
      "should add multiple AWS accounts using AWS Organizations",
      {
        tag: [
          "@critical",
          "@e2e",
          "@providers",
          "@aws",
          "@serial",
          "@PROVIDER-E2E-016",
        ],
      },
      async ({ page }) => {
        // AWS Organizations (multi-account onboarding) is a Cloud-only feature,
        // so this test must never run in the OSS CI. Gate explicitly on the
        // Cloud env flag instead of relying on the org env vars being absent.
        test.skip(
          process.env.NEXT_PUBLIC_IS_CLOUD_ENV !== "true",
          "AWS Organizations multi-account onboarding is a Cloud-only feature",
        );

        if (!organizationId || !organizationRoleArn) {
          test.skip(
            true,
            "E2E_AWS_ORGANIZATION_ID and E2E_AWS_ORGANIZATION_ROLE_ARN environment variables are not set",
          );
          return;
        }

        const awsOrganizationId = organizationId;
        const awsOrganizationRoleArn = organizationRoleArn;

        await deleteProviderIfExists(providersPage, awsOrganizationId);

        const awsOrganizationData: AWSOrganizationsProviderData = {
          organizationId: awsOrganizationId,
          organizationName: "Test E2E AWS Organization",
        };
        const organizationsCredentials: AWSOrganizationsProviderCredential = {
          roleArn: awsOrganizationRoleArn,
          stackSetDeployed: true,
        };

        await providersPage.goto();
        await providersPage.verifyPageLoaded();

        await providersPage.clickAddProvider();
        await providersPage.verifyConnectAccountPageLoaded();

        await providersPage.selectAWSProvider();
        await providersPage.selectAWSOrganizationsMethod();

        await providersPage.fillAWSOrganizationsProviderDetails(
          awsOrganizationData,
        );
        await providersPage.clickNext();

        await providersPage.verifyOrganizationsAuthenticationStepLoaded();
        await providersPage.fillAWSOrganizationsCredentials(
          organizationsCredentials,
        );
        await providersPage.clickNext();

        await providersPage.verifyOrganizationsAccountSelectionStepLoaded();
        await providersPage.clickNext();

        await providersPage.verifyOrganizationsLaunchStepLoaded();
        await providersPage.chooseOrganizationsScanSchedule("daily");
        await providersPage.clickNext();

        await providersPage.verifyLoadProviderPageAfterNewProvider();
      },
    );
  });

  test.describe.serial("Add AZURE Provider", () => {
    // Providers page object
    let providersPage: ProvidersPage;

    // Test data from environment variables
    const subscriptionId = process.env.E2E_AZURE_SUBSCRIPTION_ID ?? "";
    const clientId = process.env.E2E_AZURE_CLIENT_ID ?? "";
    const clientSecret = process.env.E2E_AZURE_SECRET_ID ?? "";
    const tenantId = process.env.E2E_AZURE_TENANT_ID ?? "";

    // Setup before each test
    test.beforeEach(async ({ page }) => {
      test.skip(
        !subscriptionId || !clientId || !clientSecret || !tenantId,
        "Azure E2E env vars are not set",
      );
      providersPage = new ProvidersPage(page);
      await deleteProviderIfExists(providersPage, subscriptionId!);
    });

    // Use admin authentication for provider management
    test.use({ storageState: "playwright/.auth/admin_user.json" });

    test(
      "should add a new Azure provider with static credentials",
      {
        tag: [
          "@critical",
          "@e2e",
          "@providers",
          "@azure",
          "@serial",
          "@PROVIDER-E2E-003",
        ],
      },
      async ({ page }) => {
        // Prepare test data for AZURE provider
        const azureProviderData: AZUREProviderData = {
          subscriptionId: subscriptionId,
          alias: "Test E2E AZURE Account - Credentials",
        };

        // Prepare static credentials
        const azureCredentials: AZUREProviderCredential = {
          type: AZURE_CREDENTIAL_OPTIONS.AZURE_CREDENTIALS,
          clientId: clientId,
          clientSecret: clientSecret,
          tenantId: tenantId,
        };

        // Navigate to providers page
        await providersPage.goto();
        await providersPage.verifyPageLoaded();

        // Start adding new provider
        await providersPage.clickAddProvider();
        await providersPage.verifyConnectAccountPageLoaded();

        // Select AZURE provider
        await providersPage.selectAZUREProvider();

        // Fill provider details
        await providersPage.fillAZUREProviderDetails(azureProviderData);
        await providersPage.clickNext();

        // Fill static credentials details
        await providersPage.fillAZURECredentials(azureCredentials);
        await providersPage.clickNext();

        // Confirm the provider connection without launching a scan
        await providersPage.completeProviderConnectionWithoutLaunchingScan(
          subscriptionId,
        );
      },
    );
  });

  test.describe.serial("Add M365 Provider", () => {
    // Providers page object
    let providersPage: ProvidersPage;

    // Test data from environment variables
    const domainId = process.env.E2E_M365_DOMAIN_ID ?? "";
    const clientId = process.env.E2E_M365_CLIENT_ID ?? "";
    const tenantId = process.env.E2E_M365_TENANT_ID ?? "";

    // Setup before each test
    test.beforeEach(async ({ page }) => {
      test.skip(
        !domainId || !clientId || !tenantId,
        "M365 E2E env vars are not set",
      );
      providersPage = new ProvidersPage(page);
      await deleteProviderIfExists(providersPage, domainId!);
    });

    // Use admin authentication for provider management
    test.use({ storageState: "playwright/.auth/admin_user.json" });

    test(
      "should add a new M365 provider with static credentials",
      {
        tag: [
          "@critical",
          "@e2e",
          "@providers",
          "@m365",
          "@serial",
          "@PROVIDER-E2E-004",
        ],
      },
      async ({ page }) => {
        // Validate required environment variables
        const clientSecret = process.env.E2E_M365_SECRET_ID ?? "";

        if (!clientSecret) {
          throw new Error("E2E_M365_SECRET_ID environment variable is not set");
        }
        // Prepare test data for M365 provider
        const m365ProviderData: M365ProviderData = {
          domainId: domainId,
          alias: "Test E2E M365 Account - Credentials",
        };

        // Prepare static credentials
        const m365Credentials: M365ProviderCredential = {
          type: M365_CREDENTIAL_OPTIONS.M365_CREDENTIALS,
          clientId: clientId,
          clientSecret: clientSecret,
          tenantId: tenantId,
        };

        // Navigate to providers page
        await providersPage.goto();
        await providersPage.verifyPageLoaded();

        // Start adding new provider
        await providersPage.clickAddProvider();
        await providersPage.verifyConnectAccountPageLoaded();

        // Select M365 provider
        await providersPage.selectM365Provider();

        // Fill provider details
        await providersPage.fillM365ProviderDetails(m365ProviderData);
        await providersPage.clickNext();

        // Select static credentials type
        await providersPage.selectM365CredentialsType(
          M365_CREDENTIAL_OPTIONS.M365_CREDENTIALS,
        );

        // Verify M365 credentials page is loaded
        await providersPage.verifyM365CredentialsPageLoaded();

        // Fill static credentials details
        await providersPage.fillM365Credentials(m365Credentials);
        await providersPage.clickNext();

        // Confirm the provider connection without launching a scan
        await providersPage.completeProviderConnectionWithoutLaunchingScan(
          domainId,
        );
      },
    );

    test(
      "should add a new M365 provider with certificate",
      {
        tag: [
          "@critical",
          "@e2e",
          "@providers",
          "@m365",
          "@serial",
          "@PROVIDER-E2E-005",
        ],
      },
      async ({ page }) => {
        // Validate required environment variables
        const certificateContent =
          process.env.E2E_M365_CERTIFICATE_CONTENT ?? "";

        if (!certificateContent) {
          throw new Error(
            "E2E_M365_CERTIFICATE_CONTENT environment variable is not set",
          );
        }

        // Prepare test data for M365 provider
        const m365ProviderData: M365ProviderData = {
          domainId: domainId,
          alias: "Test E2E M365 Account - Certificate",
        };

        // Prepare static credentials
        const m365Credentials: M365ProviderCredential = {
          type: M365_CREDENTIAL_OPTIONS.M365_CERTIFICATE_CREDENTIALS,
          clientId: clientId,
          tenantId: tenantId,
          certificateContent: certificateContent,
        };

        // Navigate to providers page
        await providersPage.goto();
        await providersPage.verifyPageLoaded();

        // Start adding new provider
        await providersPage.clickAddProvider();
        await providersPage.verifyConnectAccountPageLoaded();

        // Select M365 provider
        await providersPage.selectM365Provider();

        // Fill provider details
        await providersPage.fillM365ProviderDetails(m365ProviderData);
        await providersPage.clickNext();

        // Select static credentials type
        await providersPage.selectM365CredentialsType(
          M365_CREDENTIAL_OPTIONS.M365_CERTIFICATE_CREDENTIALS,
        );

        // Verify M365 certificate credentials page is loaded
        await providersPage.verifyM365CertificateCredentialsPageLoaded();

        // Fill static credentials details
        await providersPage.fillM365CertificateCredentials(m365Credentials);
        await providersPage.clickNext();

        // Confirm the provider connection without launching a scan
        await providersPage.completeProviderConnectionWithoutLaunchingScan(
          domainId,
        );
      },
    );
  });

  test.describe.serial("Add Kubernetes Provider", () => {
    // Providers page object
    let providersPage: ProvidersPage;

    // Test data from environment variables
    const context = process.env.E2E_KUBERNETES_CONTEXT ?? "";
    const kubeconfigPath = process.env.E2E_KUBERNETES_KUBECONFIG_PATH ?? "";

    // Setup before each test
    test.beforeEach(async ({ page }) => {
      test.skip(
        !context || !kubeconfigPath,
        "Kubernetes E2E env vars are not set",
      );
      providersPage = new ProvidersPage(page);
      await deleteProviderIfExists(providersPage, context!);
    });

    // Use admin authentication for provider management
    test.use({ storageState: "playwright/.auth/admin_user.json" });

    test(
      "should add a new Kubernetes provider with kubeconfig context",
      {
        tag: [
          "@critical",
          "@e2e",
          "@providers",
          "@kubernetes",
          "@serial",
          "@PROVIDER-E2E-006",
        ],
      },
      async ({ page }) => {
        // Verify kubeconfig file exists
        if (!fs.existsSync(kubeconfigPath)) {
          throw new Error(`Kubeconfig file not found at ${kubeconfigPath}`);
        }

        // Read kubeconfig content from file
        let kubeconfigContent: string;
        try {
          kubeconfigContent = fs.readFileSync(kubeconfigPath, "utf8");
        } catch (error) {
          throw new Error(
            `Failed to read kubeconfig file at ${kubeconfigPath}: ${error}`,
          );
        }

        // Prepare test data for Kubernetes provider
        const kubernetesProviderData: KubernetesProviderData = {
          context: context,
          alias: "Test E2E Kubernetes Account - Kubeconfig Context",
        };

        // Prepare static credentials
        const kubernetesCredentials: KubernetesProviderCredential = {
          type: KUBERNETES_CREDENTIAL_OPTIONS.KUBECONFIG_CONTENT,
          kubeconfigContent: kubeconfigContent,
        };

        // Navigate to providers page
        await providersPage.goto();
        await providersPage.verifyPageLoaded();

        // Start adding new provider
        await providersPage.clickAddProvider();
        await providersPage.verifyConnectAccountPageLoaded();

        // Select Kubernetes provider
        await providersPage.selectKubernetesProvider();

        // Fill provider details
        await providersPage.fillKubernetesProviderDetails(
          kubernetesProviderData,
        );
        await providersPage.clickNext();

        // Verify credentials page is loaded
        await providersPage.verifyKubernetesCredentialsPageLoaded();

        // Fill static credentials details
        await providersPage.fillKubernetesCredentials(kubernetesCredentials);
        await providersPage.clickNext();

        // Confirm the provider connection without launching a scan
        await providersPage.completeProviderConnectionWithoutLaunchingScan(
          context,
        );
      },
    );
  });

  test.describe.serial("Add GCP Provider", () => {
    // Providers page object
    let providersPage: ProvidersPage;

    // Test data from environment variables
    const projectId = process.env.E2E_GCP_PROJECT_ID ?? "";

    // Setup before each test
    test.beforeEach(async ({ page }) => {
      test.skip(!projectId, "E2E_GCP_PROJECT_ID is not set");
      providersPage = new ProvidersPage(page);
      await deleteProviderIfExists(providersPage, projectId!);
    });

    // Use admin authentication for provider management
    test.use({ storageState: "playwright/.auth/admin_user.json" });

    test(
      "should add a new GCP provider with service account key",
      {
        tag: [
          "@critical",
          "@e2e",
          "@providers",
          "@gcp",
          "@serial",
          "@PROVIDER-E2E-007",
        ],
      },
      async ({ page }) => {
        // Validate required environment variables
        const serviceAccountKeyB64 =
          process.env.E2E_GCP_BASE64_SERVICE_ACCOUNT_KEY ?? "";

        // Verify service account key is base64 encoded
        if (!serviceAccountKeyB64) {
          throw new Error(
            "E2E_GCP_BASE64_SERVICE_ACCOUNT_KEY environment variable is not set",
          );
        }

        // Decode service account key from base64
        const serviceAccountKey = Buffer.from(
          serviceAccountKeyB64,
          "base64",
        ).toString("utf8");

        // Verify service account key is valid JSON
        if (!JSON.parse(serviceAccountKey)) {
          throw new Error("Invalid service account key format");
        }

        // Prepare test data for GCP provider
        const gcpProviderData: GCPProviderData = {
          projectId: projectId,
          alias: "Test E2E GCP Account - Service Account Key",
        };

        // Prepare static credentials
        const gcpCredentials: GCPProviderCredential = {
          type: GCP_CREDENTIAL_OPTIONS.GCP_SERVICE_ACCOUNT,
          serviceAccountKey: serviceAccountKey,
        };

        // Navigate to providers page
        await providersPage.goto();
        await providersPage.verifyPageLoaded();

        // Start adding new provider
        await providersPage.clickAddProvider();
        await providersPage.verifyConnectAccountPageLoaded();

        // Select M365 provider
        await providersPage.selectGCPProvider();

        // Fill provider details
        await providersPage.fillGCPProviderDetails(gcpProviderData);
        await providersPage.clickNext();

        // Select static credentials type
        await providersPage.selectGCPCredentialsType(
          GCP_CREDENTIAL_OPTIONS.GCP_SERVICE_ACCOUNT,
        );

        // Verify GCP service account page is loaded
        await providersPage.verifyGCPServiceAccountPageLoaded();

        // Fill static service account key details
        await providersPage.fillGCPServiceAccountKeyCredentials(gcpCredentials);
        await providersPage.clickNext();

        // Confirm the provider connection without launching a scan
        await providersPage.completeProviderConnectionWithoutLaunchingScan(
          projectId,
        );
      },
    );
  });

  test.describe.serial("Add GitHub Provider", () => {
    // Providers page object
    let providersPage: ProvidersPage;

    test.describe("Add GitHub provider with username", () => {
      const username = process.env.E2E_GITHUB_USERNAME ?? "";

      // Setup before each test
      test.beforeEach(async ({ page }) => {
        test.skip(!username, "E2E_GITHUB_USERNAME is not set");
        providersPage = new ProvidersPage(page);
        await deleteProviderIfExists(providersPage, username!);
      });

      // Use admin authentication for provider management
      test.use({ storageState: "playwright/.auth/admin_user.json" });

      test(
        "should add a new GitHub provider with personal access token",
        {
          tag: [
            "@critical",
            "@e2e",
            "@providers",
            "@github",
            "@serial",
            "@PROVIDER-E2E-008",
          ],
        },
        async ({ page }) => {
          // Validate required environment variables
          const personalAccessToken =
            process.env.E2E_GITHUB_PERSONAL_ACCESS_TOKEN ?? "";

          // Verify username and personal access token are set in environment variables
          if (!personalAccessToken) {
            throw new Error(
              "E2E_GITHUB_PERSONAL_ACCESS_TOKEN environment variables are not set",
            );
          }

          // Prepare test data for GitHub provider
          const githubProviderData: GitHubProviderData = {
            username: username,
            alias: "Test E2E GitHub Account - Personal Access Token",
          };

          // Prepare personal access token credentials
          const githubCredentials: GitHubProviderCredential = {
            type: GITHUB_CREDENTIAL_OPTIONS.GITHUB_PERSONAL_ACCESS_TOKEN,
            personalAccessToken: personalAccessToken,
          };

          // Navigate to providers page
          await providersPage.goto();
          await providersPage.verifyPageLoaded();

          // Start adding new provider
          await providersPage.clickAddProvider();
          await providersPage.verifyConnectAccountPageLoaded();

          // Select GitHub provider
          await providersPage.selectGitHubProvider();

          // Fill provider details
          await providersPage.fillGitHubProviderDetails(githubProviderData);
          await providersPage.clickNext();

          // Select GitHub personal access token credentials type
          await providersPage.selectGitHubCredentialsType(
            GITHUB_CREDENTIAL_OPTIONS.GITHUB_PERSONAL_ACCESS_TOKEN,
          );

          // Verify GitHub personal access token page is loaded
          await providersPage.verifyGitHubPersonalAccessTokenPageLoaded();

          // Fill static personal access token details
          await providersPage.fillGitHubPersonalAccessTokenCredentials(
            githubCredentials,
          );
          await providersPage.clickNext();

          // Confirm the provider connection without launching a scan
          await providersPage.completeProviderConnectionWithoutLaunchingScan(
            username,
          );
        },
      );
      test(
        "should add a new GitHub provider with github app",
        {
          tag: [
            "@critical",
            "@e2e",
            "@providers",
            "@github",
            "@serial",
            "@PROVIDER-E2E-009",
          ],
        },
        async ({ page }) => {
          // Validate required environment variables
          const githubAppId = process.env.E2E_GITHUB_APP_ID ?? "";
          const githubAppPrivateKeyB64 =
            process.env.E2E_GITHUB_BASE64_APP_PRIVATE_KEY ?? "";

          // Verify github app id and private key are set in environment variables
          if (!githubAppId || !githubAppPrivateKeyB64) {
            throw new Error(
              "E2E_GITHUB_APP_ID and E2E_GITHUB_APP_PRIVATE_KEY environment variables are not set",
            );
          }
          // Decode github app private key from base64
          const githubAppPrivateKey = Buffer.from(
            githubAppPrivateKeyB64,
            "base64",
          ).toString("utf8");

          // Prepare test data for GitHub provider
          const githubProviderData: GitHubProviderData = {
            username: username,
            alias: "Test E2E GitHub Account - GitHub App",
          };

          // Prepare github app credentials
          const githubCredentials: GitHubProviderCredential = {
            type: GITHUB_CREDENTIAL_OPTIONS.GITHUB_APP,
            githubAppId: githubAppId,
            githubAppPrivateKey: githubAppPrivateKey,
          };

          // Navigate to providers page
          await providersPage.goto();
          await providersPage.verifyPageLoaded();

          // Start adding new provider
          await providersPage.clickAddProvider();
          await providersPage.verifyConnectAccountPageLoaded();

          // Select GitHub provider
          await providersPage.selectGitHubProvider();

          // Fill provider details
          await providersPage.fillGitHubProviderDetails(githubProviderData);
          await providersPage.clickNext();

          // Select static github app credentials type
          await providersPage.selectGitHubCredentialsType(
            GITHUB_CREDENTIAL_OPTIONS.GITHUB_APP,
          );

          // Verify GitHub github app page is loaded
          await providersPage.verifyGitHubAppPageLoaded();

          // Fill static github app credentials details
          await providersPage.fillGitHubAppCredentials(githubCredentials);
          await providersPage.clickNext();

          // Confirm the provider connection without launching a scan
          await providersPage.completeProviderConnectionWithoutLaunchingScan(
            username,
          );
        },
      );
    });
    test.describe("Add GitHub provider with organization", () => {
      const organization = process.env.E2E_GITHUB_ORGANIZATION ?? "";

      // Setup before each test
      test.beforeEach(async ({ page }) => {
        test.skip(!organization, "E2E_GITHUB_ORGANIZATION is not set");
        providersPage = new ProvidersPage(page);
        await deleteProviderIfExists(providersPage, organization!);
      });

      // Use admin authentication for provider management
      test.use({ storageState: "playwright/.auth/admin_user.json" });
      test(
        "should add a new GitHub provider with organization personal access token",
        {
          tag: [
            "@critical",
            "@e2e",
            "@providers",
            "@github",
            "@serial",
            "@PROVIDER-E2E-010",
          ],
        },
        async ({ page }) => {
          // Validate required environment variables
          const organizationAccessToken =
            process.env.E2E_GITHUB_ORGANIZATION_ACCESS_TOKEN ?? "";

          // Verify username and personal access token are set in environment variables
          if (!organizationAccessToken) {
            throw new Error(
              "E2E_GITHUB_ORGANIZATION_ACCESS_TOKEN environment variables are not set",
            );
          }

          // Prepare test data for GitHub provider
          const githubProviderData: GitHubProviderData = {
            username: organization,
            alias: "Test E2E GitHub Account - Organization Access Token",
          };

          // Prepare personal access token credentials
          const githubCredentials: GitHubProviderCredential = {
            type: GITHUB_CREDENTIAL_OPTIONS.GITHUB_PERSONAL_ACCESS_TOKEN,
            personalAccessToken: organizationAccessToken,
          };

          // Navigate to providers page
          await providersPage.goto();
          await providersPage.verifyPageLoaded();

          // Start adding new provider
          await providersPage.clickAddProvider();
          await providersPage.verifyConnectAccountPageLoaded();

          // Select GitHub provider
          await providersPage.selectGitHubProvider();

          // Fill provider details
          await providersPage.fillGitHubProviderDetails(githubProviderData);
          await providersPage.clickNext();

          // Select GitHub organization personal access token credentials type
          await providersPage.selectGitHubCredentialsType(
            GITHUB_CREDENTIAL_OPTIONS.GITHUB_PERSONAL_ACCESS_TOKEN,
          );

          // Verify GitHub personal access token page is loaded
          await providersPage.verifyGitHubPersonalAccessTokenPageLoaded();

          // Fill static personal access token details
          await providersPage.fillGitHubPersonalAccessTokenCredentials(
            githubCredentials,
          );
          await providersPage.clickNext();

          // Confirm the provider connection without launching a scan
          await providersPage.completeProviderConnectionWithoutLaunchingScan(
            organization,
          );
        },
      );
    });
  });

  test.describe.serial("Add OCI Provider", () => {
    // Providers page object
    let providersPage: ProvidersPage;

    // Test data from environment variables
    const tenancyId = process.env.E2E_OCI_TENANCY_ID ?? "";
    const userId = process.env.E2E_OCI_USER_ID ?? "";
    const fingerprint = process.env.E2E_OCI_FINGERPRINT ?? "";
    const keyContent = process.env.E2E_OCI_KEY_CONTENT ?? "";

    // Setup before each test
    test.beforeEach(async ({ page }) => {
      test.skip(
        !tenancyId || !userId || !fingerprint || !keyContent,
        "OCI E2E env vars are not set",
      );
      providersPage = new ProvidersPage(page);
      await deleteProviderIfExists(providersPage, tenancyId!);
    });

    // Use admin authentication for provider management
    test.use({ storageState: "playwright/.auth/admin_user.json" });

    test(
      "should add a new OCI provider with API key credentials",
      {
        tag: [
          "@critical",
          "@e2e",
          "@providers",
          "@oci",
          "@serial",
          "@PROVIDER-E2E-012",
        ],
      },
      async ({ page }) => {
        // Prepare test data for OCI provider
        const ociProviderData: OCIProviderData = {
          tenancyId: tenancyId,

          alias: "Test E2E OCI Account - API Key",
        };

        // Prepare static credentials
        const ociCredentials: OCIProviderCredential = {
          type: OCI_CREDENTIAL_OPTIONS.OCI_API_KEY,
          tenancyId: tenancyId,
          userId: userId,
          fingerprint: fingerprint,
          keyContent: keyContent,
        };

        // Navigate to providers page
        await providersPage.goto();

        // Start adding new provider
        await providersPage.clickAddProvider();
        await providersPage.verifyConnectAccountPageLoaded();

        // Select OCI provider
        await providersPage.selectOCIProvider();

        // Fill provider details
        await providersPage.fillOCIProviderDetails(ociProviderData);
        await providersPage.clickNext();

        // Verify OCI credentials page is loaded
        await providersPage.verifyOCICredentialsPageLoaded();

        // Fill static credentials details
        await providersPage.fillOCICredentials(ociCredentials);
        await providersPage.clickNext();

        // Confirm the provider connection without launching a scan
        await providersPage.completeProviderConnectionWithoutLaunchingScan(
          tenancyId,
        );
      },
    );
  });

  test.describe.serial("Add AlibabaCloud Provider", () => {
    // Providers page object
    let providersPage: ProvidersPage;

    // Test data from environment variables
    const accountId = process.env.E2E_ALIBABACLOUD_ACCOUNT_ID ?? "";
    const accessKeyId = process.env.E2E_ALIBABACLOUD_ACCESS_KEY_ID ?? "";
    const accessKeySecret =
      process.env.E2E_ALIBABACLOUD_ACCESS_KEY_SECRET ?? "";
    const roleArn = process.env.E2E_ALIBABACLOUD_ROLE_ARN ?? "";

    // Setup before each test
    test.beforeEach(async ({ page }) => {
      test.skip(!accountId, "E2E_ALIBABACLOUD_ACCOUNT_ID is not set");
      providersPage = new ProvidersPage(page);
      await deleteProviderIfExists(providersPage, accountId!);
    });

    // Use admin authentication for provider management
    test.use({ storageState: "playwright/.auth/admin_user.json" });

    test(
      "should add a new AlibabaCloud provider with static credentials",
      {
        tag: [
          "@critical",
          "@e2e",
          "@providers",
          "@alibabacloud",
          "@serial",
          "@PROVIDER-E2E-014",
        ],
      },
      async ({ page }) => {
        // Validate required environment variables
        if (!accessKeyId || !accessKeySecret) {
          throw new Error(
            "E2E_ALIBABACLOUD_ACCESS_KEY_ID and E2E_ALIBABACLOUD_ACCESS_KEY_SECRET environment variables are not set",
          );
        }

        // Prepare test data for AlibabaCloud provider
        const alibabacloudProviderData: AlibabaCloudProviderData = {
          accountId: accountId,
          alias: "Test E2E AlibabaCloud Account - Static Credentials",
        };

        // Prepare static credentials
        const staticCredentials: AlibabaCloudProviderCredential = {
          type: ALIBABACLOUD_CREDENTIAL_OPTIONS.ALIBABACLOUD_CREDENTIALS,
          accessKeyId: accessKeyId,
          accessKeySecret: accessKeySecret,
        };

        // Navigate to providers page
        await providersPage.goto();
        await providersPage.verifyPageLoaded();

        // Start adding new provider
        await providersPage.clickAddProvider();
        await providersPage.verifyConnectAccountPageLoaded();

        // Select AlibabaCloud provider
        await providersPage.selectAlibabaCloudProvider();

        // Fill provider details
        await providersPage.fillAlibabaCloudProviderDetails(
          alibabacloudProviderData,
        );
        await providersPage.clickNext();

        // Verify credentials page is loaded
        await providersPage.verifyAlibabaCloudCredentialsPageLoaded();

        // Select static credentials type
        await providersPage.selectAlibabaCloudCredentialsType(
          ALIBABACLOUD_CREDENTIAL_OPTIONS.ALIBABACLOUD_CREDENTIALS,
        );

        // Verify static credentials page is loaded
        await providersPage.verifyAlibabaCloudStaticCredentialsPageLoaded();

        // Fill static credentials
        await providersPage.fillAlibabaCloudStaticCredentials(
          staticCredentials,
        );
        await providersPage.clickNext();

        // Confirm the provider connection without launching a scan
        await providersPage.completeProviderConnectionWithoutLaunchingScan(
          accountId,
        );
      },
    );

    test(
      "should add a new AlibabaCloud provider with RAM Role credentials",
      {
        tag: [
          "@critical",
          "@e2e",
          "@providers",
          "@alibabacloud",
          "@serial",
          "@PROVIDER-E2E-015",
        ],
      },
      async ({ page }) => {
        // Validate required environment variables
        if (!accessKeyId || !accessKeySecret || !roleArn) {
          throw new Error(
            "E2E_ALIBABACLOUD_ACCESS_KEY_ID, E2E_ALIBABACLOUD_ACCESS_KEY_SECRET, and E2E_ALIBABACLOUD_ROLE_ARN environment variables are not set",
          );
        }

        // Prepare test data for AlibabaCloud provider
        const alibabacloudProviderData: AlibabaCloudProviderData = {
          accountId: accountId,
          alias: "Test E2E AlibabaCloud Account - RAM Role Credentials",
        };

        // Prepare RAM Role credentials
        const roleCredentials: AlibabaCloudProviderCredential = {
          type: ALIBABACLOUD_CREDENTIAL_OPTIONS.ALIBABACLOUD_ROLE,
          accessKeyId: accessKeyId,
          accessKeySecret: accessKeySecret,
          roleArn: roleArn,
        };

        // Navigate to providers page
        await providersPage.goto();
        await providersPage.verifyPageLoaded();

        // Start adding new provider
        await providersPage.clickAddProvider();
        await providersPage.verifyConnectAccountPageLoaded();

        // Select AlibabaCloud provider
        await providersPage.selectAlibabaCloudProvider();

        // Fill provider details
        await providersPage.fillAlibabaCloudProviderDetails(
          alibabacloudProviderData,
        );
        await providersPage.clickNext();

        // Verify credentials page is loaded
        await providersPage.verifyAlibabaCloudCredentialsPageLoaded();

        // Select RAM Role credentials type
        await providersPage.selectAlibabaCloudCredentialsType(
          ALIBABACLOUD_CREDENTIAL_OPTIONS.ALIBABACLOUD_ROLE,
        );

        // Verify RAM Role credentials page is loaded
        await providersPage.verifyAlibabaCloudRoleCredentialsPageLoaded();

        // Fill RAM Role credentials
        await providersPage.fillAlibabaCloudRoleCredentials(roleCredentials);
        await providersPage.clickNext();

        // Confirm the provider connection without launching a scan
        await providersPage.completeProviderConnectionWithoutLaunchingScan(
          accountId,
        );
      },
    );
  });

  test.describe.serial("Add Google Workspace Provider", () => {
    let providersPage: ProvidersPage;

    const customerId = process.env.E2E_GOOGLEWORKSPACE_CUSTOMER_ID ?? "";
    const serviceAccountJson =
      process.env.E2E_GOOGLEWORKSPACE_SERVICE_ACCOUNT_JSON ?? "";
    const delegatedUser = process.env.E2E_GOOGLEWORKSPACE_DELEGATED_USER ?? "";

    test.beforeEach(async ({ page }) => {
      test.skip(
        !customerId || !serviceAccountJson || !delegatedUser,
        "Google Workspace E2E env vars are not set",
      );
      providersPage = new ProvidersPage(page);
      await deleteProviderIfExists(providersPage, customerId!);
    });

    test.use({ storageState: "playwright/.auth/admin_user.json" });

    test(
      "should add a new Google Workspace provider with service account credentials",
      {
        tag: [
          "@critical",
          "@e2e",
          "@providers",
          "@googleworkspace",
          "@serial",
          "@PROVIDER-E2E-017",
        ],
      },
      async ({ page }) => {
        const googleWorkspaceProviderData: GoogleWorkspaceProviderData = {
          customerId: customerId,
          alias: "Test E2E Google Workspace - Service Account",
        };

        const googleWorkspaceCredentials: GoogleWorkspaceProviderCredential = {
          type: GOOGLEWORKSPACE_CREDENTIAL_OPTIONS.GOOGLEWORKSPACE_SERVICE_ACCOUNT,
          serviceAccountJson: serviceAccountJson,
          delegatedUser: delegatedUser,
        };

        // Navigate to providers page
        await providersPage.goto();
        await providersPage.verifyPageLoaded();

        // Start adding new provider
        await providersPage.clickAddProvider();
        await providersPage.verifyConnectAccountPageLoaded();

        // Select Google Workspace provider
        await providersPage.selectGoogleWorkspaceProvider();

        // Fill provider details (customer ID and alias)
        await providersPage.fillGoogleWorkspaceProviderDetails(
          googleWorkspaceProviderData,
        );
        await providersPage.clickNext();

        // Verify credentials page is loaded
        await providersPage.verifyGoogleWorkspaceCredentialsPageLoaded();

        // Fill credentials
        await providersPage.fillGoogleWorkspaceCredentials(
          googleWorkspaceCredentials,
        );
        await providersPage.clickNext();

        // Confirm the provider connection without launching a scan
        await providersPage.completeProviderConnectionWithoutLaunchingScan(
          customerId,
        );
      },
    );
  });

  test.describe.serial("Add Vercel Provider", () => {
    let providersPage: ProvidersPage;

    // Test data from environment variables
    const teamId = process.env.E2E_VERCEL_TEAM_ID ?? "";
    const apiToken = process.env.E2E_VERCEL_API_TOKEN ?? "";

    // Setup before each test
    test.beforeEach(async ({ page }) => {
      test.skip(!teamId || !apiToken, "Vercel E2E env vars are not set");
      providersPage = new ProvidersPage(page);
      await deleteProviderIfExists(providersPage, teamId!);
    });

    // Use admin authentication for provider management
    test.use({ storageState: "playwright/.auth/admin_user.json" });

    test(
      "should add a new Vercel provider with API token",
      {
        tag: [
          "@critical",
          "@e2e",
          "@providers",
          "@vercel",
          "@serial",
          "@PROVIDER-E2E-018",
        ],
      },
      async ({ page }) => {
        // Prepare test data for Vercel provider (Team ID is the provider UID)
        const vercelProviderData: VercelProviderData = {
          teamId: teamId,
          alias: "Test E2E Vercel Account - API Token",
        };

        // Prepare API token credentials
        const vercelCredentials: VercelProviderCredential = {
          type: VERCEL_CREDENTIAL_OPTIONS.VERCEL_API_TOKEN,
          apiToken: apiToken,
        };

        // Navigate to providers page
        await providersPage.goto();
        await providersPage.verifyPageLoaded();

        // Start adding new provider
        await providersPage.clickAddProvider();
        await providersPage.verifyConnectAccountPageLoaded();

        // Select Vercel provider
        await providersPage.selectVercelProvider();

        // Fill provider details (team ID and alias)
        await providersPage.fillVercelProviderDetails(vercelProviderData);
        await providersPage.clickNext();

        // Verify credentials page is loaded
        await providersPage.verifyVercelCredentialsPageLoaded();

        // Fill credentials (API token)
        await providersPage.fillVercelCredentials(vercelCredentials);
        await providersPage.clickNext();

        // Confirm the provider connection without launching a scan
        await providersPage.completeProviderConnectionWithoutLaunchingScan(
          teamId,
        );
      },
    );
  });

  test.describe.serial("Add Okta Provider", () => {
    let providersPage: ProvidersPage;

    // Test data from environment variables
    // Org Domain is lowercased by the form, so normalize here to match the
    // stored provider UID used for cleanup.
    const orgDomain = (process.env.E2E_OKTA_DOMAIN ?? "").toLowerCase();
    const clientId = process.env.E2E_OKTA_CLIENT_ID ?? "";
    const privateKeyB64 = process.env.E2E_OKTA_BASE64_PRIVATE_KEY ?? "";

    // Setup before each test
    test.beforeEach(async ({ page }) => {
      test.skip(
        !orgDomain || !clientId || !privateKeyB64,
        "Okta E2E env vars are not set",
      );
      providersPage = new ProvidersPage(page);
      await deleteProviderIfExists(providersPage, orgDomain!);
    });

    // Use admin authentication for provider management
    test.use({ storageState: "playwright/.auth/admin_user.json" });

    test(
      "should add a new Okta provider with OAuth 2.0 Private Key JWT credentials",
      {
        tag: [
          "@critical",
          "@e2e",
          "@providers",
          "@okta",
          "@serial",
          "@PROVIDER-E2E-019",
        ],
      },
      async ({ page }) => {
        // The Okta app private key is PEM-encoded (multi-line), so it is passed
        // base64-encoded via the environment variable and decoded here.
        const privateKey = Buffer.from(privateKeyB64, "base64").toString(
          "utf8",
        );

        // Prepare test data for Okta provider
        const oktaProviderData: OktaProviderData = {
          orgDomain: orgDomain,
          alias: "Test E2E Okta Account - Private Key JWT",
        };

        // Prepare OAuth 2.0 Private Key JWT credentials
        const oktaCredentials: OktaProviderCredential = {
          type: OKTA_CREDENTIAL_OPTIONS.OKTA_PRIVATE_KEY_JWT,
          clientId: clientId,
          privateKey: privateKey,
        };

        // Navigate to providers page
        await providersPage.goto();
        await providersPage.verifyPageLoaded();

        // Start adding new provider
        await providersPage.clickAddProvider();
        await providersPage.verifyConnectAccountPageLoaded();

        // Select Okta provider
        await providersPage.selectOktaProvider();

        // Fill provider details (org domain and alias)
        await providersPage.fillOktaProviderDetails(oktaProviderData);
        await providersPage.clickNext();

        // Verify Okta credentials page is loaded
        await providersPage.verifyOktaCredentialsPageLoaded();

        // Fill OAuth 2.0 Private Key JWT credentials
        await providersPage.fillOktaCredentials(oktaCredentials);
        await providersPage.clickNext();

        // Confirm the provider connection without launching a scan
        await providersPage.completeProviderConnectionWithoutLaunchingScan(
          orgDomain,
        );
      },
    );
  });
});

test.describe("Update Provider Credentials", () => {
  test.describe.serial("Update OCI Provider Credentials", () => {
    let providersPage: ProvidersPage;

    // Test data from environment variables (same as add OCI provider test)
    const tenancyId = process.env.E2E_OCI_TENANCY_ID ?? "";
    const userId = process.env.E2E_OCI_USER_ID ?? "";
    const fingerprint = process.env.E2E_OCI_FINGERPRINT ?? "";
    const keyContent = process.env.E2E_OCI_KEY_CONTENT ?? "";

    // Setup before each test
    test.beforeEach(async ({ page }) => {
      test.skip(
        !tenancyId || !userId || !fingerprint || !keyContent,
        "OCI E2E env vars are not set",
      );
      providersPage = new ProvidersPage(page);
    });

    // Use admin authentication for provider management
    test.use({ storageState: "playwright/.auth/admin_user.json" });

    test(
      "should update OCI provider credentials successfully",
      {
        tag: ["@e2e", "@providers", "@oci", "@serial", "@PROVIDER-E2E-013"],
      },
      async () => {
        // Prepare updated credentials
        const ociCredentials: OCIProviderCredential = {
          type: OCI_CREDENTIAL_OPTIONS.OCI_API_KEY,
          tenancyId: tenancyId,
          userId: userId,
          fingerprint: fingerprint,
          keyContent: keyContent,
        };

        // Navigate to providers page
        await providersPage.goto();
        await providersPage.verifyPageLoaded();

        // Verify OCI provider exists in the table
        const providerExists =
          await providersPage.verifySingleRowForProviderUID(tenancyId);
        if (!providerExists) {
          throw new Error(
            `OCI provider with tenancy ID ${tenancyId} not found. Run the add OCI provider test first.`,
          );
        }

        // Click update credentials for the OCI provider
        await providersPage.clickUpdateCredentials(tenancyId);

        // Verify update credentials page is loaded
        await providersPage.verifyUpdateCredentialsPageLoaded();

        // Verify OCI credentials form fields are visible (confirms providerUid is loaded)
        // Note: Tenancy OCID is hidden in update flow (auto-populated from provider UID)
        await providersPage.verifyOCIUpdateCredentialsPageLoaded();

        // Fill updated credentials
        await providersPage.fillOCICredentials(ociCredentials);

        // Click Next to submit
        await providersPage.clickNext();

        // Verify successful navigation to test connection page
        await providersPage.verifyTestConnectionPageLoaded();
      },
    );
  });
});
