import React, { useEffect, useState } from 'react';
import {
  useAccountId,
  useAppStateDispatch,
  useCompetitorUrls,
  useDraft,
  useDrupal,
  useExcludedCompetitorUrls,
  useKeywords,
  useRankSource,
} from '../Context.js';
import useSWRImmutable from 'swr/immutable';
import { put, post } from './fetcher.js';

const DraftManager = ({
  isLoading = (_) => false,
  hasError = (_) => false,
}: {
  isLoading?: (_: boolean) => void;
  hasError?: (_: boolean) => void;
}) => {
  const dispatch = useAppStateDispatch();
  const draft = useDraft();
  const accountId = useAccountId();
  const keywords = useKeywords();
  const competitorUrls = useCompetitorUrls();
  const excludedCompetitorUrls = useExcludedCompetitorUrls();
  const rankSource = useRankSource();
  const drupal = useDrupal();
  // Changes to any of these should cause an update to the draft in Conductor.
  const draftData = {
    draftTitle: draft.title,
    phrases: keywords,
    competitorUrls: competitorUrls.filter((url: string) => !excludedCompetitorUrls.includes(url)),
    rankSourceId: rankSource.id,
    title: draft.title,
    metaDescription: draft.metaDescription,
    bodyCopy: draft.bodyCopy,
  };
  const [debouncedDraftData, setDebouncedDraftData] = useState(draftData);

  useEffect(() => {
    if (JSON.stringify(draftData) !== JSON.stringify(debouncedDraftData)) {
      const timer = setTimeout(() => {
        setDebouncedDraftData({ ...draftData });
      }, 500);

      return () => clearTimeout(timer);
    }
  }, [draftData]);

  // Create a draft.
  const {
    data: createDraftData,
    error: createDraftError,
    isLoading: createDraftIsLoading,
  } = useSWRImmutable(
    !draft.id
      ? [`/conductor/proxy/v3/accounts/${accountId}/drafts/writing-assistant`, draftData]
      : null,
    post,
  );
  useEffect(() => {
    if (!draft.id && createDraftData?.id) {
      dispatch({
        type: 'updateDraft',
        draft: { id: createDraftData.id, lastUpdated: createDraftData.updated },
      });
      if (window?.drupalSettings?.conductor && createDraftData.id) {
        window.drupalSettings.conductor.draftId = createDraftData.id;
      }
      if (window?.drupalSettings?.conductor?.usedDrafts) {
        window.drupalSettings.conductor.usedDrafts++;
      }
    }
    // Successful return, but no valid data.
    else if (!createDraftError && !createDraftIsLoading && createDraftData) {
      throw new Error('Unable to create draft');
    }
  }, [createDraftData]);

  // Link the draft with an entity in Drupal.
  const {
    data: drupalData,
    error: linkDraftError,
    isLoading: linkDraftIsLoading,
  } = useSWRImmutable(
    drupal.entity.id && drupal.entity.type && draft?.id && !drupal.draftLinked
      ? [
          `/conductor/api/draft/${drupal.entity.type}/${drupal.entity.id}`,
          {
            draftId: draft.id,
          },
        ]
      : null,
    post,
  );
  useEffect(() => {
    if (drupalData?.message === 'success') {
      dispatch({ type: 'setDrupalDraftLinked', draftLinked: true });
    }
    // Successful return, but no valid data.
    else if (drupalData && !linkDraftError && !linkDraftIsLoading) {
      if (drupalData?.error) {
        throw new Error(drupalData.error);
      }
      throw new Error('Unable link draft to Drupal');
    }
  }, [drupalData]);

  // Update draft.
  //
  // @todo if this fails with the following, re-fetch the data and update the last updated timestamp
  // {"timestamp":1763054169916,"status":400,"error":"Bad Request","path":"/customer-api/v3/accounts/24936/drafts/bead88f1-bd37-48a7-9861-46f04058141d/writing-assistant"}⏎
  // but we should probably warn the users that someone else has made changes
  const { data: updateDraftData, error: updateDraftError } = useSWRImmutable(
    draft.id && draft.lastUpdated && debouncedDraftData
      ? [
          `/conductor/proxy/v3/accounts/${accountId}/drafts/${draft.id}/writing-assistant`,
          debouncedDraftData,
        ]
      : null,
    ([url]) => put([url, { ...debouncedDraftData, lastUpdateTime: draft.lastUpdated }]),
  );
  useEffect(() => {
    if (updateDraftError) {
      hasError(true);
    } else {
      hasError(false);
    }

    if (updateDraftData?.updated) {
      dispatch({ type: 'updateDraft', draft: { lastUpdated: updateDraftData.updated } });
    }
  }, [updateDraftData, updateDraftError]);

  // Request content insights - without this content generation won't work.
  const { data: insights, error: insightsError } = useSWRImmutable(
    draft.id
      ? [
          `/conductor/proxy/v3/accounts/${accountId}/insights/${draft.id}/writing-assistant`,
          {
            insight: {
              input: {
                topic: {
                  phrases: draftData.phrases,
                  rankSourceId: draftData.rankSourceId,
                  webPropertyId: 0,
                  competitorUrls: draftData.competitorUrls,
                },
              },
              request: {
                insights: [
                  'PAA_INSIGHT',
                  'BODY_CONTENT_COMMON',
                  'CONTENT_ANALYSIS_INSIGHT',
                  'HTML_HEADING1_COMMON',
                  'HTML_HEADING2_COMMON',
                  'HTML_HEADING3_COMMON',
                  'HTML_META_DESCRIPTION_COMMON',
                  'HTML_TITLE_COMMON',
                  'CONTENT_LENGTH_INSIGHT',
                  'READABILITY_INSIGHT',
                  'OBJECTIVE_INSIGHT',
                  'AUDIENCE_INSIGHT',
                  'JOURNEY_STAGE_INSIGHT',
                  'CONTENT_TYPE_INSIGHT',
                  'SUBTOPIC_INSIGHT',
                  'OPPORTUNITIES_SNIPPET',
                  'MSV_SNIPPET',
                ],
              },
            },
          },
        ]
      : null,
    post,
  );

  useEffect(() => {
    if (!draft.id || !draft.lastUpdated || !drupal.draftLinked || !insights) {
      isLoading(true);
    } else {
      isLoading(false);
    }
  }, [draft, drupal, insights]);

  useEffect(() => {
    if (createDraftError || linkDraftError || insightsError) {
      hasError(true);
    }
  });

  return <></>;
};

export default DraftManager;
