import { useCallback, useMemo, useState } from "react";
import { __ } from "@wordpress/i18n";
import { buildUrl } from "@libs/url";
import { getProfileDefaults, PRO_ADDITIONAL_FEATURES } from "./wizardDefaults";
import {
  findStepIndexByQuestionKey,
  getVisibleQuestions,
  WIZARD_STEPS,
} from "./wizardQuestions";

const isEmptyValue = (value) => {
  if (Array.isArray(value)) {
    return value.length === 0;
  }

  return value === undefined || value === null || value === "";
};

const stripUnavailableSelections = (answers, isProActive) => {
  if (isProActive) {
    return {
      ...answers,
      billing_flexibility: [...(answers.billing_flexibility || [])],
      retention_offer_types: [...(answers.retention_offer_types || [])],
      custom_emails: [...(answers.custom_emails || [])],
      admin_emails: [...(answers.admin_emails || [])],
      additional_features: [...(answers.additional_features || [])],
    };
  }

  return {
    ...answers,
    billing_flexibility: [...(answers.billing_flexibility || [])],
    retention_offer_types: [...(answers.retention_offer_types || [])],
    custom_emails: [...(answers.custom_emails || [])],
    admin_emails: [...(answers.admin_emails || [])],
    additional_features: (answers.additional_features || []).filter(
      (item) => !PRO_ADDITIONAL_FEATURES.includes(item),
    ),
  };
};

const createInitialAnswers = (businessType, isProActive) => {
  return stripUnavailableSelections(
    getProfileDefaults(businessType),
    isProActive,
  );
};

const useWizardState = ({ isProActive }) => {
  const [currentStep, setCurrentStep] = useState(0);
  const [answers, setAnswersState] = useState(() =>
    createInitialAnswers("other", isProActive),
  );
  const [validationErrors, setValidationErrors] = useState({});
  const [isSubmitting, setIsSubmitting] = useState(false);
  const [submitError, setSubmitError] = useState("");

  const totalSteps = WIZARD_STEPS.length;
  const stepMeta = WIZARD_STEPS[currentStep] || WIZARD_STEPS[0];
  const activeProfile = useMemo(
    () => createInitialAnswers(answers.business_type, isProActive),
    [answers.business_type, isProActive],
  );
  const visibleQuestions = useMemo(
    () => getVisibleQuestions(stepMeta, answers, isProActive),
    [answers, isProActive, stepMeta],
  );

  const resetWizard = useCallback(() => {
    setCurrentStep(0);
    setAnswersState(createInitialAnswers("other", isProActive));
    setValidationErrors({});
    setIsSubmitting(false);
    setSubmitError("");
  }, [isProActive]);

  const runValidation = useCallback(
    (questions, nextAnswers = answers) => {
      const nextErrors = {};

      questions.forEach((question) => {
        const value = nextAnswers[question.key];

        if (question.required && isEmptyValue(value)) {
          nextErrors[question.key] = __("This field is required.", "arraysubs");
          return;
        }

        if (typeof question.validate === "function") {
          const message = question.validate(value, nextAnswers);
          if (message) {
            nextErrors[question.key] = message;
          }
        }
      });

      return nextErrors;
    },
    [answers],
  );

  const setAnswer = useCallback(
    (key, value) => {
      setValidationErrors((previous) => {
        if (!previous[key]) {
          return previous;
        }

        const nextErrors = { ...previous };
        delete nextErrors[key];
        return nextErrors;
      });

      setSubmitError("");

      if (key === "business_type") {
        setAnswersState(createInitialAnswers(value, isProActive));
        setCurrentStep(0);
        setValidationErrors({});
        return;
      }

      setAnswersState((previous) =>
        stripUnavailableSelections(
          {
            ...previous,
            [key]: value,
          },
          isProActive,
        ),
      );
    },
    [isProActive],
  );

  const setAnswers = useCallback(
    (partialAnswers) => {
      setAnswersState((previous) =>
        stripUnavailableSelections(
          {
            ...previous,
            ...partialAnswers,
          },
          isProActive,
        ),
      );
    },
    [isProActive],
  );

  const goToStep = useCallback(
    (stepIndex) => {
      setCurrentStep(Math.max(0, Math.min(stepIndex, totalSteps - 1)));
      setValidationErrors({});
      setSubmitError("");
    },
    [totalSteps],
  );

  const goBack = useCallback(() => {
    setCurrentStep((previous) => Math.max(previous - 1, 0));
    setValidationErrors({});
    setSubmitError("");
  }, []);

  const goNext = useCallback(() => {
    if (currentStep >= totalSteps - 1) {
      return true;
    }

    const nextErrors = runValidation(visibleQuestions);
    setValidationErrors(nextErrors);

    if (Object.keys(nextErrors).length > 0) {
      return false;
    }

    setCurrentStep((previous) => Math.min(previous + 1, totalSteps - 1));
    setSubmitError("");
    return true;
  }, [currentStep, runValidation, totalSteps, visibleQuestions]);

  const skipCurrentStep = useCallback(() => {
    if (currentStep >= totalSteps - 1) {
      return;
    }

    setAnswersState((previous) => {
      const nextAnswers = { ...previous };

      visibleQuestions.forEach((question) => {
        if (activeProfile[question.key] !== undefined) {
          nextAnswers[question.key] = activeProfile[question.key];
        }
      });

      return stripUnavailableSelections(nextAnswers, isProActive);
    });

    setValidationErrors({});
    setSubmitError("");
    setCurrentStep((previous) => Math.min(previous + 1, totalSteps - 1));
  }, [activeProfile, currentStep, isProActive, totalSteps, visibleQuestions]);

  const submitWizard = useCallback(async () => {
    const url = buildUrl(
      `${window.arraySubs?.env?.apiBaseUrl}arraysubs/v1/easy-setup/wizard`,
    );

    setIsSubmitting(true);
    setSubmitError("");

    try {
      const response = await fetch(url, {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          "X-WP-Nonce": window.arraySubs?.env?.nonce,
        },
        body: JSON.stringify({ answers }),
      });

      if (!response.ok) {
        const errBody = await response.json().catch(() => null);
        const serverErrors = errBody?.data?.errors;

        if (serverErrors && typeof serverErrors === "object") {
          setValidationErrors(serverErrors);

          const firstErrorKey = Object.keys(serverErrors)[0];
          const errorStepIndex = findStepIndexByQuestionKey(firstErrorKey);
          if (errorStepIndex >= 0) {
            setCurrentStep(errorStepIndex);
          }
        }

        throw new Error(
          errBody?.message ||
            __("Failed to apply the setup wizard.", "arraysubs"),
        );
      }

      const result = await response.json();
      return result?.content || result;
    } catch (error) {
      setSubmitError(
        error?.message || __("Failed to apply the setup wizard.", "arraysubs"),
      );
      return null;
    } finally {
      setIsSubmitting(false);
    }
  }, [answers]);

  return {
    currentStep,
    totalSteps,
    answers,
    setAnswer,
    setAnswers,
    activeProfile,
    stepMeta,
    visibleQuestions,
    validationErrors,
    goNext,
    goBack,
    goToStep,
    skipCurrentStep,
    resetWizard,
    isFirstStep: currentStep === 0,
    isReviewStep: currentStep === totalSteps - 1,
    isLastQuestionStep: currentStep === totalSteps - 2,
    canGoBack: currentStep > 0,
    canGoNext: Object.keys(runValidation(visibleQuestions)).length === 0,
    isSubmitting,
    submitError,
    submitWizard,
  };
};

export default useWizardState;
