import { FLAGS, useFeatureIsOn } from "@komi-app/flags-sdk";

import React, { useEffect, useState } from "react";

import { segmentsUrl } from "constants/dca/segments";

import { useDebouncedCallback } from "hooks/useDebouncedCallback";

import { services } from "services";
import { Prompt, useHistory } from "react-router-dom";
import { Location } from "history";

import {
  SegmentMenuAction,
  SegmentMode,
  Segment,
  ZSegmentIdObject,
  SegmentProperty,
} from "@komi-app/fans-sdk";

import notification from "utils/notification";
import { createDefaultSegment } from "utils/dca/segments";
import { useTalentProfileId } from "redux/User/utils";

import classnames from "classnames";
import "./SegmentQueryBuilderPage.scss";
import { getSegmentPropertyAttributes } from "./attributes";
import { SegmentPage } from "./BuilderPage/BuilderPage";

export interface SegmentQueryBuilderProps
  extends React.HTMLProps<HTMLDivElement> {
  mode?: SegmentMode;
  segmentId?: string;
}

const SegmentQueryBuilder: React.FC<SegmentQueryBuilderProps> = ({
  mode,
  segmentId,
  ...props
}) => {
  const router = useHistory();
  const talentProfileId = useTalentProfileId();

  const [segment, setSegment] = useState<Segment>(
    createDefaultSegment(talentProfileId),
  );
  const [contactCount, setContactCount] = useState(0);
  const [navigatingLocation, setNavigatingLocation] =
    useState<Location<unknown> | null>(null);

  const [loading, setLoading] = useState(false);
  const [isUnsaved, setIsUnsaved] = useState(false);

  const fetchSegment = async (segmentId: string) => {
    setLoading(true);

    const fetchedSegment = await services.segment().getSegment(segmentId);
    if (fetchedSegment) {
      setSegment(fetchedSegment);
    }

    setLoading(false);
  };

  const fetchContactCount = async () => {
    const res = ZSegmentIdObject.safeParse(segment);
    if (!res.success) return;

    // TODO: modify to accept entire segment for querying, so that
    //   we may handle unsaved segments
    const count = (await services.segment().countSegmentQuery(segment)) || 0;
    setContactCount(count);
  };
  const debouncedFetchContactCount = useDebouncedCallback(
    fetchContactCount,
    750,
  );

  /**
   * Updates the segment state and fetches the contact count
   * @param {Segment} updatedSegment
   */
  const handleSegmentChange = (updatedSegment: Segment) => {
    setIsUnsaved(true);
    setSegment(updatedSegment);
  };

  /**
   * Navigates back to the segments list
   */
  const handleBackClick = () => {
    setIsUnsaved(false);
    router.push(segmentsUrl);
  };

  /**
   * Saves the segment
   */
  const handleSaveClick = async () => {
    const { segmentId } = segment;

    const segmentName = encodeURIComponent(segment.name);

    if (!segment.name) {
      return false;
    }
    const nameExists = await services.segment().exists(segmentName);

    const fetchedSegment = await services
      .segment()
      .getSegmentByName(segmentName);
    const isCurrentSegment = Boolean(fetchedSegment?.segmentId === segmentId);

    if (!isCurrentSegment && nameExists) {
      notification.error({
        message: "A segment with that name already exists.",
      });
      return false;
    }

    // Attempt to save or create
    // TODO: create an upsert endpoint?
    try {
      if (mode === SegmentMode.Edit) {
        await services.segment().updateSegment(segment);
      } else {
        await services.segment().createSegment(segment);
      }

      notification.success({ message: "Segment saved successfully." });

      setIsUnsaved(false);
      router.push(segmentsUrl);

      return true;
    } catch (error) {
      notification.error({ message: "There was an issue saving the segment." });

      return false;
    }
  };

  const handleMenuOptionClick = async (option: SegmentMenuAction) => {
    switch (option) {
      case SegmentMenuAction.ExportCsv:
        break;

      case SegmentMenuAction.Delete:
        await services.segment().deleteSegment(segment.segmentId);
        router.push(segmentsUrl);

        break;

      case SegmentMenuAction.Send:
        break;
    }
  };

  const handleBlockedNavigation = (nextLocation: Location<unknown>) => {
    if (isUnsaved) {
      setNavigatingLocation(nextLocation);
    }

    // Allow navigation if there are no unsaved changes
    return !isUnsaved;
  };

  useEffect(() => {
    if (navigatingLocation && !isUnsaved) {
      // Navigate to the previous blocked location with your navigate function
      window.location.href = navigatingLocation.pathname;
    }
  }, [isUnsaved, navigatingLocation]);

  /**
   * Fetches the segment on component load
   */
  useEffect(() => {
    if (mode === SegmentMode.Edit && segmentId) {
      fetchSegment(segmentId);
    }
  }, [mode, segmentId]);

  /**
   * Fetches the contact count on segment change
   */
  useEffect(() => void debouncedFetchContactCount(), [segment]);

  const classNames = classnames("segment-page");

  return (
    <div {...props} className={classNames}>
      <Prompt when={isUnsaved} message={handleBlockedNavigation} />

      <SegmentPage
        loading={false}
        segment={segment}
        segmentPropertyAttributes={getSegmentPropertyAttributes()}
        contactCount={contactCount}
        isMarketingPermissionFixEnabled={true}
        isNavigatingWhenUnsaved={isUnsaved && Boolean(navigatingLocation)}
        onSegmentChange={handleSegmentChange}
        onBackClick={handleBackClick}
        onSaveClick={handleSaveClick}
        onMenuOptionClick={handleMenuOptionClick}
      />
    </div>
  );
};

export default SegmentQueryBuilder;
