"use client";

import { zodResolver } from "@hookform/resolvers/zod";
import { Send } from "lucide-react";
import { type Dispatch, type SetStateAction, useEffect, useState } from "react";
import { useForm } from "react-hook-form";
import { z } from "zod";

import {
  getJiraIntegrations,
  getJiraIssueTypes,
  pollJiraDispatchTask,
  sendFindingToJira,
} from "@/actions/integrations/jira-dispatch";
import { Modal } from "@/components/shadcn/modal";
import { EnhancedMultiSelect } from "@/components/shadcn/select/enhanced-multi-select";
import { Skeleton } from "@/components/shadcn/skeleton/skeleton";
import { useToast } from "@/components/ui";
import { CustomBanner } from "@/components/ui/custom/custom-banner";
import { Form, FormField, FormMessage } from "@/components/ui/form";
import { FormButtons } from "@/components/ui/form/form-buttons";
import { IntegrationProps } from "@/types/integrations";

interface SendToJiraModalProps {
  isOpen: boolean;
  onOpenChange: (open: boolean) => void;
  findingId: string;
  findingTitle?: string;
}

const sendToJiraSchema = z.object({
  integration: z.string().min(1, "Please select a Jira integration"),
  project: z.string().min(1, "Please select a project"),
  issueType: z.string().min(1, "Please select an issue type"),
});

type SendToJiraFormData = z.infer<typeof sendToJiraSchema>;

export const SendToJiraModal = ({
  isOpen,
  onOpenChange,
  findingId,
  findingTitle,
}: SendToJiraModalProps) => {
  const { toast } = useToast();
  const [integrations, setIntegrations] = useState<IntegrationProps[]>([]);
  const [isFetchingIntegrations, setIsFetchingIntegrations] = useState(false);
  const [fetchedIssueTypes, setFetchedIssueTypes] = useState<
    Record<string, string[]>
  >({});
  const [isFetchingIssueTypes, setIsFetchingIssueTypes] = useState(false);

  const form = useForm<SendToJiraFormData>({
    resolver: zodResolver(sendToJiraSchema),
    defaultValues: {
      integration: "",
      project: "",
      issueType: "",
    },
  });

  const selectedIntegration = form.watch("integration");

  const hasConnectedIntegration = integrations.some(
    (i) => i.attributes.connected === true,
  );

  const setOpenForFormButtons: Dispatch<SetStateAction<boolean>> = (value) => {
    const next = typeof value === "function" ? value(isOpen) : value;
    onOpenChange(next);
  };

  // Fetch Jira integrations when modal opens
  useEffect(() => {
    if (isOpen) {
      const fetchJiraIntegrations = async () => {
        setIsFetchingIntegrations(true);

        try {
          const result = await getJiraIntegrations();
          if (!result.success) {
            throw new Error(
              result.error || "Unable to fetch Jira integrations",
            );
          }
          setIntegrations(result.data);
          // Auto-select if only one integration
          if (result.data.length === 1) {
            form.setValue("integration", result.data[0].id);
          }
        } catch (error) {
          const message =
            error instanceof Error && error.message
              ? error.message
              : "Failed to load Jira integrations";
          toast({
            variant: "destructive",
            title: "Failed to load integrations",
            description: message,
          });
        } finally {
          setIsFetchingIntegrations(false);
        }
      };

      fetchJiraIntegrations();
    } else {
      // Reset form and fetched data when modal closes
      form.reset();
      setFetchedIssueTypes({});
    }
  }, [isOpen, form, toast]);

  const handleSubmit = async (data: SendToJiraFormData) => {
    // Close modal immediately; continue processing in background
    onOpenChange(false);

    void (async () => {
      try {
        // Send the finding to Jira
        const result = await sendFindingToJira(
          data.integration,
          findingId,
          data.project,
          data.issueType,
        );

        if (!result.success) {
          throw new Error(result.error || "Failed to send to Jira");
        }

        // Poll for task completion and notify once
        const taskResult = await pollJiraDispatchTask(result.taskId);

        if (!taskResult.success) {
          throw new Error(taskResult.error || "Failed to create Jira issue");
        }

        toast({
          title: "Success!",
          description:
            taskResult.message || "Finding sent to Jira successfully",
        });
      } catch (error) {
        const message =
          error instanceof Error && error.message
            ? error.message
            : "Failed to send finding to Jira";
        toast({
          variant: "destructive",
          title: "Error",
          description: message,
        });
      }
    })();
  };

  const selectedProject = form.watch("project");

  const selectedIntegrationData = integrations.find(
    (i) => i.id === selectedIntegration,
  );

  const projects: Record<string, string> =
    selectedIntegrationData?.attributes.configuration.projects ??
    ({} as Record<string, string>);

  const projectEntries = Object.entries(projects);

  // Get issue types from config (new dict format), falling back to fetched data
  const configIssueTypes = selectedIntegrationData?.attributes.configuration
    .issue_types as Record<string, string[]> | undefined;
  const issueTypesFromConfig =
    configIssueTypes &&
    typeof configIssueTypes === "object" &&
    !Array.isArray(configIssueTypes)
      ? (configIssueTypes[selectedProject] ?? [])
      : [];
  const issueTypesForProject =
    issueTypesFromConfig.length > 0
      ? issueTypesFromConfig
      : (fetchedIssueTypes[selectedProject] ?? []);

  // Fetch issue types from API when project is selected but no types are available
  useEffect(() => {
    let ignore = false;

    if (
      selectedIntegration &&
      selectedProject &&
      issueTypesFromConfig.length === 0 &&
      !fetchedIssueTypes[selectedProject]
    ) {
      const fetchIssueTypes = async () => {
        setIsFetchingIssueTypes(true);
        try {
          const result = await getJiraIssueTypes(
            selectedIntegration,
            selectedProject,
          );
          if (ignore) return;
          if (result.success) {
            setFetchedIssueTypes((prev) => ({
              ...prev,
              [selectedProject]: result.issueTypes,
            }));
          } else {
            toast({
              variant: "destructive",
              title: "Failed to load issue types",
              description:
                result.error || "Unable to fetch issue types for this project",
            });
          }
        } finally {
          if (!ignore) setIsFetchingIssueTypes(false);
        }
      };

      fetchIssueTypes();
    }

    return () => {
      ignore = true;
    };
  }, [
    selectedIntegration,
    selectedProject,
    issueTypesFromConfig.length,
    fetchedIssueTypes,
    toast,
  ]);

  const issueTypeOptions = issueTypesForProject.map((type) => ({
    value: type,
    label: type,
  }));

  const integrationOptions = integrations.map((integration) => ({
    value: integration.id,
    label: integration.attributes.configuration.domain || integration.id,
  }));

  const projectOptions = projectEntries.map(([key, name]) => ({
    value: key,
    label: `${key} - ${name}`,
  }));

  return (
    <Modal
      open={isOpen}
      onOpenChange={onOpenChange}
      title="Send Finding to Jira"
      description={
        findingTitle
          ? `Create a Jira issue for: "${findingTitle}"`
          : "Select integration, project and issue type to create a Jira issue"
      }
    >
      <Form {...form}>
        <form
          onSubmit={form.handleSubmit(handleSubmit)}
          className="flex flex-col gap-4"
        >
          {/* Loading skeleton for project selector */}
          {isFetchingIntegrations && (
            <div className="flex flex-col gap-1.5">
              <Skeleton className="h-3 w-16" />
              <Skeleton className="h-12 w-full rounded-md" />
            </div>
          )}

          {/* Integration Selection */}
          {!isFetchingIntegrations && integrations.length > 1 && (
            <FormField
              control={form.control}
              name="integration"
              render={({ field }) => (
                <div className="flex flex-col gap-1.5">
                  <label
                    htmlFor="jira-integration-select"
                    className="text-text-neutral-secondary text-xs font-light tracking-tight"
                  >
                    Jira Integration
                  </label>
                  <EnhancedMultiSelect
                    id="jira-integration-select"
                    options={integrationOptions}
                    onValueChange={(values) => {
                      const selectedValue = values.at(-1) ?? "";
                      field.onChange(selectedValue);
                      // Reset dependent fields
                      form.setValue("project", "");
                      form.setValue("issueType", "");
                      setFetchedIssueTypes({});
                    }}
                    defaultValue={field.value ? [field.value] : []}
                    placeholder="Select a Jira integration"
                    searchable={true}
                    emptyIndicator="No integrations found."
                    disabled={isFetchingIntegrations}
                    hideSelectAll={true}
                    maxCount={1}
                    closeOnSelect={true}
                    resetOnDefaultValueChange={true}
                  />
                  <FormMessage className="text-text-error text-xs" />
                </div>
              )}
            />
          )}

          {/* Project Selection */}
          {!isFetchingIntegrations &&
            selectedIntegration &&
            projectEntries.length > 0 && (
              <FormField
                control={form.control}
                name="project"
                render={({ field }) => (
                  <div className="flex flex-col gap-1.5">
                    <label
                      htmlFor="jira-project-select"
                      className="text-text-neutral-secondary text-xs font-light tracking-tight"
                    >
                      Project
                    </label>
                    <EnhancedMultiSelect
                      id="jira-project-select"
                      options={projectOptions}
                      onValueChange={(values) => {
                        const selectedValue = values.at(-1) ?? "";
                        field.onChange(selectedValue);
                        // Reset issue type when project changes
                        form.setValue("issueType", "");
                      }}
                      defaultValue={field.value ? [field.value] : []}
                      placeholder="Select a Jira project"
                      searchable={true}
                      emptyIndicator="No projects found."
                      hideSelectAll={true}
                      maxCount={1}
                      closeOnSelect={true}
                      resetOnDefaultValueChange={true}
                    />
                    <FormMessage className="text-text-error text-xs" />
                  </div>
                )}
              />
            )}

          {/* Issue Type Selection */}
          {selectedProject && (
            <FormField
              control={form.control}
              name="issueType"
              render={({ field }) => (
                <div className="flex flex-col gap-1.5">
                  <label
                    htmlFor="jira-issue-type-select"
                    className="text-text-neutral-secondary text-xs font-light tracking-tight"
                  >
                    Issue Type
                  </label>
                  <EnhancedMultiSelect
                    id="jira-issue-type-select"
                    options={issueTypeOptions}
                    onValueChange={(values) => {
                      const selectedValue = values.at(-1) ?? "";
                      field.onChange(selectedValue);
                    }}
                    defaultValue={field.value ? [field.value] : []}
                    placeholder={
                      isFetchingIssueTypes
                        ? "Loading issue types..."
                        : "Select an issue type"
                    }
                    searchable={true}
                    emptyIndicator="No issue types found."
                    disabled={isFetchingIssueTypes}
                    hideSelectAll={true}
                    maxCount={1}
                    closeOnSelect={true}
                    resetOnDefaultValueChange={true}
                  />
                  <FormMessage className="text-text-error text-xs" />
                </div>
              )}
            />
          )}

          {/* No integrations or none connected message */}
          {!isFetchingIntegrations &&
          (integrations.length === 0 || !hasConnectedIntegration) ? (
            <CustomBanner
              title="Jira integration is not available"
              message="Please add or connect an integration first"
              buttonLabel="Configure"
              buttonLink="/integrations/jira"
            />
          ) : (
            <FormButtons
              setIsOpen={setOpenForFormButtons}
              onCancel={() => onOpenChange(false)}
              submitText="Send to Jira"
              cancelText="Cancel"
              loadingText="Sending..."
              isDisabled={
                !form.formState.isValid ||
                form.formState.isSubmitting ||
                isFetchingIntegrations ||
                isFetchingIssueTypes ||
                integrations.length === 0 ||
                !hasConnectedIntegration
              }
              rightIcon={<Send size={20} />}
            />
          )}
        </form>
      </Form>
    </Modal>
  );
};
