"use client";

import { zodResolver } from "@hookform/resolvers/zod";
import { Check, Copy, ExternalLink } from "lucide-react";
import { useSession } from "next-auth/react";
import type { FormEvent } from "react";
import { useEffect, useRef, useState } from "react";
import { Controller, useForm } from "react-hook-form";
import { z } from "zod";

import { updateOrganizationName } from "@/actions/organizations/organizations";
import { AWSProviderBadge } from "@/components/icons/providers-badge";
import type { WizardFooterConfig } from "@/components/providers/wizard/steps/footer-controls";
import { WIZARD_FOOTER_ACTION_TYPE } from "@/components/providers/wizard/steps/footer-controls";
import type { OrgWizardIntent } from "@/components/providers/wizard/types";
import { ORG_WIZARD_INTENT } from "@/components/providers/wizard/types";
import { WizardInputField } from "@/components/providers/workflow/forms/fields";
import { useToast } from "@/components/shadcn";
import { Alert, AlertDescription } from "@/components/shadcn/alert";
import { Button } from "@/components/shadcn/button/button";
import { Checkbox } from "@/components/shadcn/checkbox/checkbox";
import { Form } from "@/components/shadcn/form";
import { Spinner } from "@/components/shadcn/spinner/spinner";
import { getAWSOrgDeploymentQuickLink } from "@/lib";
import { useOrgSetupStore } from "@/store/organizations/store";
import type { OrgSetupPhase } from "@/types/organizations";
import { ORG_SETUP_PHASE } from "@/types/organizations";

import { useOrgSetupSubmission } from "./hooks/use-org-setup-submission";

const orgSetupSchema = z.object({
  organizationName: z.string().trim().optional(),
  awsOrgId: z
    .string()
    .trim()
    .min(1, "Organization ID is required")
    .regex(
      /^o-[a-z0-9]{10,32}$/,
      "Must be a valid AWS Organization ID (e.g., o-abc123def4)",
    ),
  roleArn: z
    .string()
    .trim()
    .min(1, "IAM Role ARN is required")
    .regex(
      /^arn:aws:iam::\d{12}:role\//,
      "Must be a valid IAM Role ARN (e.g., arn:aws:iam::123456789012:role/ProwlerScan)",
    ),
  // OU or root id the StackSet deploys to. UI-only: used to build the
  // CloudFormation quick-create link, not sent to the backend. Its format is
  // validated inline (isOrgUnitIdValid) to gate the deployment button, so a
  // malformed value never blocks the Authenticate submit.
  organizationalUnitId: z.string().trim().optional(),
  deployFromDelegatedAdmin: z.boolean().optional(),
  stackSetDeployed: z.boolean().refine((value) => value, {
    error: "You must confirm the deployment before continuing.",
  }),
});

type OrgSetupFormData = z.infer<typeof orgSetupSchema>;

interface OrgSetupFormInitialValues {
  organizationName: string;
  awsOrgId: string;
}

interface OrgSetupFormProps {
  onBack: () => void;
  onClose?: () => void;
  onNext: () => void;
  onFooterChange: (config: WizardFooterConfig) => void;
  onPhaseChange: (phase: OrgSetupPhase) => void;
  initialPhase?: OrgSetupPhase;
  initialValues?: OrgSetupFormInitialValues;
  intent?: OrgWizardIntent;
}

export function OrgSetupForm({
  onBack,
  onClose,
  onNext,
  onFooterChange,
  onPhaseChange,
  initialPhase = ORG_SETUP_PHASE.DETAILS,
  initialValues,
  intent = ORG_WIZARD_INTENT.FULL,
}: OrgSetupFormProps) {
  const { data: session } = useSession();
  const stackSetExternalId = session?.tenantId ?? "";
  const { organizationId } = useOrgSetupStore();
  const { toast } = useToast();
  const COPY_RESET_TIMEOUT = 1500;
  const [isExternalIdCopied, setIsExternalIdCopied] = useState(false);
  const externalIdCopyTimer = useRef<ReturnType<typeof setTimeout>>(undefined);

  // Copies text and flips the copied flag back after the timeout, without effects
  const copyWithFeedback = (
    text: string,
    setCopied: (copied: boolean) => void,
    timerRef: { current: ReturnType<typeof setTimeout> | undefined },
  ) => {
    navigator.clipboard.writeText(text).then(() => {
      setCopied(true);
      clearTimeout(timerRef.current);
      timerRef.current = setTimeout(() => setCopied(false), COPY_RESET_TIMEOUT);
    });
  };

  const copyExternalId = (text: string) =>
    copyWithFeedback(text, setIsExternalIdCopied, externalIdCopyTimer);
  const [setupPhase, setSetupPhase] = useState<OrgSetupPhase>(initialPhase);
  const [isSaving, setIsSaving] = useState(false);
  const formId = "org-wizard-setup-form";

  const isReadOnlyOrgId = Boolean(initialValues?.awsOrgId);

  const form = useForm<OrgSetupFormData>({
    resolver: zodResolver(orgSetupSchema),
    mode: "onChange",
    reValidateMode: "onChange",
    defaultValues: {
      organizationName: initialValues?.organizationName ?? "",
      awsOrgId: initialValues?.awsOrgId ?? "",
      roleArn: "",
      organizationalUnitId: "",
      deployFromDelegatedAdmin: false,
      stackSetDeployed: false,
    },
  });
  const {
    control,
    handleSubmit,
    formState: { errors, isSubmitting, isValid },
    setError,
    watch,
  } = form;

  const awsOrgId = watch("awsOrgId") || "";
  const isOrgIdValid = /^o-[a-z0-9]{10,32}$/.test(awsOrgId.trim());

  const organizationalUnitId = watch("organizationalUnitId") || "";
  const deployFromDelegatedAdmin = watch("deployFromDelegatedAdmin") || false;
  const deploymentAccountName = deployFromDelegatedAdmin
    ? "delegated administrator account"
    : "management account";
  const deploymentAccountLabel = deployFromDelegatedAdmin
    ? "Delegated Administrator Account"
    : "Management Account";
  const isOrgUnitIdValid =
    /^(ou-[a-z0-9]{4,32}-[a-z0-9]{8,32}|r-[a-z0-9]{4,32})$/.test(
      organizationalUnitId.trim(),
    );
  const orgQuickLink =
    stackSetExternalId && isOrgUnitIdValid
      ? getAWSOrgDeploymentQuickLink({
          externalId: stackSetExternalId,
          organizationalUnitId: organizationalUnitId.trim(),
          deployFromDelegatedAdmin,
        })
      : null;

  const { apiError, setApiError, submitOrganizationSetup } =
    useOrgSetupSubmission({
      stackSetExternalId,
      onNext,
      setFieldError: (field, message) => {
        setError(field, { message });
      },
    });

  useEffect(() => {
    onPhaseChange(setupPhase);
  }, [onPhaseChange, setupPhase]);

  useEffect(() => {
    if (setupPhase === ORG_SETUP_PHASE.DETAILS) {
      const isEditName = intent === ORG_WIZARD_INTENT.EDIT_NAME;
      onFooterChange({
        showBack: true,
        backLabel: "Back",
        onBack,
        showAction: true,
        actionLabel: isEditName ? "Save" : "Next",
        actionDisabled: isEditName ? isSaving : !isOrgIdValid,
        actionType: WIZARD_FOOTER_ACTION_TYPE.SUBMIT,
        actionFormId: formId,
      });
      return;
    }

    const isEditCredentials = intent === ORG_WIZARD_INTENT.EDIT_CREDENTIALS;
    onFooterChange({
      showBack: !isEditCredentials,
      backLabel: "Back",
      backDisabled: isSubmitting,
      onBack: () => setSetupPhase(ORG_SETUP_PHASE.DETAILS),
      showAction: true,
      actionLabel: "Authenticate",
      actionDisabled: isSubmitting || !isValid || !stackSetExternalId,
      actionType: WIZARD_FOOTER_ACTION_TYPE.SUBMIT,
      actionFormId: formId,
    });
  }, [
    formId,
    intent,
    isOrgIdValid,
    isSaving,
    isSubmitting,
    isValid,
    onBack,
    onFooterChange,
    stackSetExternalId,
    setupPhase,
  ]);

  const handleContinueToAccess = () => {
    setApiError(null);

    if (!isOrgIdValid) {
      setError("awsOrgId", {
        message: awsOrgId.trim()
          ? "Must be a valid AWS Organization ID (e.g., o-abc123def4)"
          : "Organization ID is required",
      });
      return;
    }

    setSetupPhase(ORG_SETUP_PHASE.ACCESS);
  };

  const handleSaveNameOnly = async () => {
    if (!organizationId) return;
    setIsSaving(true);
    const name = form.getValues("organizationName")?.trim() || "";

    const result = await updateOrganizationName(organizationId, name);

    setIsSaving(false);

    if (result?.error || result?.errors) {
      const errorMsg =
        result.errors?.[0]?.detail ?? result.error ?? "Failed to update name";
      toast({
        variant: "destructive",
        title: "Oops! Something went wrong",
        description: errorMsg,
      });
      return;
    }

    toast({
      title: "Success!",
      description: "Organization name updated successfully.",
    });
    onClose?.();
  };

  const handleFormSubmit = (event: FormEvent<HTMLFormElement>) => {
    if (setupPhase === ORG_SETUP_PHASE.DETAILS) {
      event.preventDefault();

      if (intent === ORG_WIZARD_INTENT.EDIT_NAME) {
        void handleSaveNameOnly();
        return;
      }

      handleContinueToAccess();
      return;
    }

    void handleSubmit((data) => submitOrganizationSetup(data))(event);
  };

  useEffect(() => {
    if (!apiError) return;
    document
      .getElementById(formId)
      ?.scrollIntoView({ block: "start", behavior: "smooth" });
  }, [apiError, formId]);

  return (
    <Form {...form}>
      <form
        id={formId}
        onSubmit={handleFormSubmit}
        className="flex flex-col gap-5"
      >
        {setupPhase === ORG_SETUP_PHASE.DETAILS && (
          <div className="flex flex-col gap-6">
            <div className="flex items-center gap-4">
              <AWSProviderBadge size={32} />
              <h3 className="text-base font-semibold">
                Amazon Web Services (AWS) / Organization Details
              </h3>
            </div>

            <p className="text-muted-foreground text-sm">
              Enter the Organization ID for the accounts you want to add to
              Prowler.
            </p>
          </div>
        )}

        {setupPhase === ORG_SETUP_PHASE.ACCESS && (
          <div className="flex flex-col gap-8">
            <div className="flex items-center gap-4">
              <AWSProviderBadge size={32} />
              <h3 className="text-base font-semibold">
                Amazon Web Services (AWS) / Authentication Details
              </h3>
            </div>
          </div>
        )}

        {setupPhase === ORG_SETUP_PHASE.ACCESS && isSubmitting && (
          <div className="flex min-h-[220px] items-center justify-center">
            <div className="flex items-center gap-3 py-2">
              <Spinner className="size-6" />
              <p className="text-sm font-medium">Gathering AWS Accounts...</p>
            </div>
          </div>
        )}

        {apiError && (
          <Alert variant="error">
            <AlertDescription className="text-text-error-primary">
              {apiError}
            </AlertDescription>
          </Alert>
        )}

        {setupPhase === ORG_SETUP_PHASE.DETAILS && (
          <div className="flex flex-col gap-4">
            <WizardInputField
              control={control}
              name="awsOrgId"
              label="Organization ID"
              labelPlacement="outside"
              placeholder="e.g. o-123456789-abcdefg"
              isRequired
              normalizeValue={(value) => value.toLowerCase()}
              autoCapitalize="none"
              autoCorrect="off"
              spellCheck={false}
              isReadOnly={isReadOnlyOrgId}
              isDisabled={isReadOnlyOrgId}
            />

            <WizardInputField
              control={control}
              name="organizationName"
              label="Name (optional)"
              labelPlacement="outside"
              placeholder=""
              isRequired={false}
            />

            <p className="text-muted-foreground text-sm">
              If left blank, Prowler will use the Organization name stored in
              AWS.
            </p>
          </div>
        )}

        {setupPhase === ORG_SETUP_PHASE.ACCESS && !isSubmitting && (
          <div className="flex flex-col gap-8">
            {/* External ID - shown first for both deployment steps */}
            <div className="flex flex-col gap-4">
              <p className="text-text-neutral-primary text-sm leading-7 font-normal">
                Use the following <strong>External ID</strong> when deploying
                the CloudFormation Stack and StackSet.
              </p>
              <div className="flex items-center gap-3">
                <span className="text-text-neutral-tertiary text-xs">
                  External ID:
                </span>
                <div className="bg-bg-neutral-tertiary border-border-input-primary flex h-10 max-w-full items-center gap-3 rounded-full border px-4">
                  <span className="truncate text-xs font-medium">
                    {stackSetExternalId ||
                      "Loading organization external ID..."}
                  </span>
                  <button
                    type="button"
                    disabled={!stackSetExternalId}
                    onClick={() => copyExternalId(stackSetExternalId)}
                    className="text-text-neutral-secondary hover:text-text-neutral-primary shrink-0 transition-colors"
                    aria-label="Copy external ID"
                  >
                    {isExternalIdCopied ? (
                      <Check className="size-4" />
                    ) : (
                      <Copy className="size-4" />
                    )}
                  </button>
                </div>
              </div>
            </div>

            {/* Step 1: Choose the deployment target */}
            <div className="flex flex-col gap-4">
              <p className="text-text-neutral-primary text-sm leading-7 font-normal">
                1) Choose the AWS <strong>Organizational Unit</strong> (or root)
                to deploy to. Prowler creates the IAM Role in your deployment
                account and rolls it out to every member account under this
                target.
              </p>
              <WizardInputField
                control={control}
                name="organizationalUnitId"
                label="Organizational Unit or Root ID"
                labelPlacement="outside"
                placeholder="e.g. r-abcd or ou-abcd-1a2b3c4d"
                isRequired={false}
                normalizeValue={(value) => value.toLowerCase()}
                autoCapitalize="none"
                autoCorrect="off"
                spellCheck={false}
              />
              <p className="text-text-neutral-tertiary text-xs leading-5">
                Find this in the AWS Organizations console. Use your{" "}
                <strong>root ID</strong> (starts with <code>r-</code>) to deploy
                to the whole organization, or an <strong>OU ID</strong> (starts
                with <code>ou-</code>) to target a specific unit.
              </p>
              <div className="flex items-center gap-3">
                <Controller
                  name="deployFromDelegatedAdmin"
                  control={control}
                  render={({ field }) => (
                    <>
                      <Checkbox
                        id="deployFromDelegatedAdmin"
                        size="sm"
                        checked={field.value}
                        onCheckedChange={(checked) =>
                          field.onChange(Boolean(checked))
                        }
                      />
                      <label
                        htmlFor="deployFromDelegatedAdmin"
                        className="text-text-neutral-secondary text-sm leading-5 font-medium"
                      >
                        I&apos;m deploying from a Delegated Administrator
                        Account (not the Management Account)
                      </label>
                    </>
                  )}
                />
              </div>
            </div>

            {/* Step 2: Single CloudFormation Stack (role + StackSet) */}
            <div className="flex flex-col gap-4">
              <p className="text-text-neutral-primary text-sm leading-7 font-normal">
                2) Create the CloudFormation Stack in your{" "}
                <strong>{deploymentAccountName}</strong>. It deploys the
                ProwlerScan IAM Role and a service-managed StackSet that rolls
                the IAM Role out to your member accounts in one step.
              </p>
              {orgQuickLink ? (
                <Button
                  variant="default"
                  size="xl"
                  className="w-full justify-start"
                  asChild
                >
                  <a
                    href={orgQuickLink}
                    target="_blank"
                    rel="noopener noreferrer"
                  >
                    <ExternalLink className="size-5" />
                    <span>{`Create Stack in ${deploymentAccountLabel}`}</span>
                  </a>
                </Button>
              ) : (
                <Button
                  type="button"
                  variant="default"
                  size="xl"
                  className="w-full justify-start"
                  disabled
                >
                  <ExternalLink className="size-5" />
                  <span>{`Create Stack in ${deploymentAccountLabel}`}</span>
                </Button>
              )}
              {!isOrgUnitIdValid && (
                <p className="text-text-neutral-tertiary text-xs leading-5">
                  Enter a valid Organizational Unit or Root ID above to enable
                  deployment.
                </p>
              )}
            </div>

            {/* Step 3: Role ARN + confirm */}
            <div className="flex flex-col gap-4">
              <p className="text-text-neutral-primary text-sm leading-7 font-normal">
                3) Paste the {deploymentAccountName} IAM Role ARN and confirm
                the deployment is complete.
              </p>
            </div>

            <WizardInputField
              control={control}
              name="roleArn"
              label={`${deploymentAccountLabel} IAM Role ARN`}
              labelPlacement="outside"
              placeholder="e.g. arn:aws:iam::123456789012:role/ProwlerScan"
              isRequired={false}
              requiredIndicator
            />

            <p className="text-text-neutral-tertiary text-sm">
              * It may take up to 60 seconds for AWS to generate the IAM Role
              ARN
            </p>

            <div className="flex items-center gap-3">
              <Controller
                name="stackSetDeployed"
                control={control}
                render={({ field }) => (
                  <>
                    <Checkbox
                      id="stackSetDeployed"
                      size="sm"
                      checked={field.value}
                      onCheckedChange={(checked) =>
                        field.onChange(Boolean(checked))
                      }
                    />
                    <label
                      htmlFor="stackSetDeployed"
                      className="text-text-neutral-tertiary text-xs leading-5 font-normal"
                    >
                      The Stack has been successfully deployed in AWS
                      <span className="text-text-error-primary">*</span>
                    </label>
                  </>
                )}
              />
            </div>
            {errors.stackSetDeployed && (
              <span className="text-text-error-primary text-xs">
                {errors.stackSetDeployed.message}
              </span>
            )}
          </div>
        )}
      </form>
    </Form>
  );
}
