import React, { useEffect, useRef, useState } from "react";
import Form from "rc-field-form";
import { __, sprintf } from "@wordpress/i18n";
import {
  ArrowLeft,
  ArrowRight,
  CircleCheck,
  ExternalLink,
  LockKeyhole,
} from "lucide-react";
import Modal from "@libs/modal";
import FormBuilder from "@libs/form-builder";
import { useConfirm } from "@libs/confirm-dialog";
import SpinnerButton from "@libs/confirm-dialog/SpinnerButton";
import { useToast, ToastContainer } from "@libs/toast";
import { buildUrl } from "@libs/url";
import { getProTrialOffer } from "../pro-trial-offer";
import BoxConfigEditor from "../subscription-box/BoxConfigEditor";
import SyncRenewalsBuilder, {
  nominalCycleDays,
  normalizeRenewalSync,
} from "../subscription-box/SyncRenewalsBuilder";
import ProductReview from "./ProductReview";
import ProductTypePicker, { getTypeRequirements } from "./ProductTypePicker";
import VariableProductGuide from "./VariableProductGuide";
import { getFields, initialValues, initialSync, STEP_LABELS, daysInMonth } from "./fields";
import { QUICK_PRODUCT_CREATED_EVENT } from "./launch";
import "@scss/subscription-box/admin.scss";
import "./quick-product.scss";

async function request(path, body, signal) {
  const { apiBaseUrl, nonce } = window.arraySubs?.env || {};
  const response = await fetch(
    buildUrl(`${apiBaseUrl}arraysubs/v1/quick-products${path}`),
    {
      method: body ? "POST" : "GET",
      credentials: "same-origin",
      signal,
      headers: {
        "X-WP-Nonce": nonce,
        ...(body ? { "Content-Type": "application/json" } : {}),
      },
      ...(body ? { body: JSON.stringify(body) } : { cache: "no-store" }),
    },
  );
  const result = await response.json();
  if (!response.ok || result.success === false)
    throw new Error(
      result.message ||
        __("Could not save the product. Please try again.", "arraysubs"),
    );
  return result.content || result.data || result;
}

export default function QuickProductWizard({ onClose }) {
  const [form] = Form.useForm();
  const [options, setOptions] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState("");
  const [step, setStep] = useState("type");
  const [type, setType] = useState("simple");
  const [values, setValues] = useState(initialValues);
  const [sync, setSync] = useState(initialSync);
  const [config, setConfig] = useState(null);
  const [configOpen, setConfigOpen] = useState(false);
  const [saving, setSaving] = useState(false);
  const [created, setCreated] = useState(null);
  const proTrial = getProTrialOffer();
  const busy = useRef(false);
  const dirty = useRef(false);
  const requestId = useRef(window.crypto.randomUUID());
  const contentRef = useRef(null);
  const advanceAfterConfig = useRef(false);
  const previousInterval = useRef(null);
  const { confirm, confirmDialog } = useConfirm();
  const { toasts, showToast, removeToast } = useToast();
  const container = ["box", "bundle"].includes(type);
  const lifetime = values._subscription_period === "lifetime";
  const syncAllowed =
    options?.capabilities?.renewal_sync &&
    !lifetime &&
    !Number(values._trial_length) &&
    !values._enable_renewal_price &&
    nominalCycleDays(
      values._subscription_period,
      values._subscription_interval,
    ) >= 3;
  const steps =
    type === "variable"
      ? ["type", "variable-guide"]
      : type === "simple"
      ? ["type", "details", "billing", "trial", "sync", "membership", "shipping", "review"]
      : container
      ? ["type", "details", "billing", "other", "review"]
      : ["type", "details", "other", "review"];
  const fields = options ? getFields(step, values, options, type) : [];
  const selectedOption = options?.types.find((option) => option.value === type);
  const typeAvailable = selectedOption && !getTypeRequirements(selectedOption).length;
  const Editor =
    type === "box" ? BoxConfigEditor : window.arraySubsProductEditors?.bundle;
  const configureLabel =
    type === "box"
      ? __("Configure box", "arraysubs")
      : __("Configure bundle", "arraysubs");

  const load = async (signal) => {
    setLoading(true);
    setError("");
    try {
      const data = await request("/options", null, signal);
      if (data.box) window.arraySubsBox = data.box;
      setOptions(data);
      const defaults = { ...initialValues, ...data.defaults };
      if (defaults._arraysubs_fixed_end_date_type === "recurring_annual" && !defaults._arraysubs_fixed_end_date)
        defaults._arraysubs_fixed_end_date = "01-01";
      form.setFieldsValue(defaults);
      setValues(defaults);
    } catch (e) {
      if (e.name !== "AbortError") {
        setError(e.message);
        showToast(e.message, "error");
      }
    } finally {
      if (!signal?.aborted) setLoading(false);
    }
  };
  useEffect(() => {
    const controller = new AbortController();
    load(controller.signal);
    return () => controller.abort();
  }, []);
  useEffect(() => {
    if (options && !typeAvailable && !created) {
      advanceAfterConfig.current = false;
      setType("simple");
      setConfig(null);
      setConfigOpen(false);
      setStep("type");
    }
  }, [options, typeAvailable, created]);
  useEffect(() => {
    if (!syncAllowed)
      setSync((previous) =>
        previous.enabled ? { ...previous, enabled: false } : previous,
      );
  }, [syncAllowed]);
  useEffect(() => {
    setSync((previous) =>
      normalizeRenewalSync(previous, {
        period: values._subscription_period,
        interval: values._subscription_interval,
      }),
    );
  }, [values._subscription_period, values._subscription_interval]);
  useEffect(() => {
    if (contentRef.current) contentRef.current.scrollTop = 0;
    contentRef.current?.querySelector("h2")?.focus({ preventScroll: true });
  }, [step, created]);
  useEffect(() => {
    if (error && contentRef.current) contentRef.current.scrollTop = 0;
  }, [error]);

  const changeValues = (changed) => {
    const next = { ...values, ...changed };
    if (changed._subscription_period === "lifetime")
      Object.assign(next, {
        _subscription_interval: 1,
        _subscription_length: 0,
        _trial_length: 0,
        _enable_renewal_price: false,
        _arraysubs_subscription_mode: "fixed",
        _arraysubs_fixed_end_date_enabled: false,
      });
    if (changed._arraysubs_subscription_mode === "full_flexible" && values._arraysubs_subscription_mode !== "full_flexible")
      previousInterval.current = values._subscription_interval;
    if (changed._arraysubs_subscription_mode && changed._arraysubs_subscription_mode !== "full_flexible" && previousInterval.current !== null) {
      next._subscription_interval = previousInterval.current;
      previousInterval.current = null;
    }
    if (next._arraysubs_subscription_mode === "full_flexible") {
      next._subscription_interval = 1;
      if (next._arraysubs_flexible_periods.length && !next._arraysubs_flexible_periods.includes(next._subscription_period))
        next._subscription_period = next._arraysubs_flexible_periods[0];
    }
    if (next._arraysubs_fixed_end_date_enabled) {
      if (previousInterval.current !== null) {
        next._subscription_interval = previousInterval.current;
        previousInterval.current = null;
      }
      next._arraysubs_subscription_mode = "fixed";
      next._subscription_length = 0;
    }
    if (changed._arraysubs_fixed_end_date_type) next._arraysubs_fixed_end_date = "";
    if (next._arraysubs_fixed_end_date_type === "recurring_annual") {
      if (next.annualDay) next.annualDay = String(Math.min(Number(next.annualDay), daysInMonth(next.annualMonth)));
      next._arraysubs_fixed_end_date = next.annualMonth && next.annualDay
        ? `${String(next.annualMonth).padStart(2, "0")}-${String(next.annualDay).padStart(2, "0")}` : "";
    }
    if (next.virtual) {
      next._arraysubs_shipping_type = "recurring";
      next._arraysubs_initial_shipping_override = "";
      next._arraysubs_renewal_shipping_override = "";
    } else if (next._arraysubs_shipping_type === "one-time") next._arraysubs_renewal_shipping_override = "";
    if (!next._enable_renewal_price) next._renewal_price_after = 1;
    form.setFieldsValue(next);
    setValues(next);
    setError("");
    dirty.current = true;
  };
  const goToStep = (next) => {
    setError("");
    setStep(next);
  };
  const close = async () => {
    if (busy.current) return;
    if (dirty.current && !created) {
      const discard = await confirm({
        title: __("Discard product?", "arraysubs"),
        message: __(
          "Your product has not been created. Discard the details you entered?",
          "arraysubs",
        ),
        confirmText: __("Discard product", "arraysubs"),
        cancelText: __("Keep editing", "arraysubs"),
        variant: "warning",
      });
      if (!discard) return;
    }
    onClose();
  };
  const next = async () => {
    try {
      if (!typeAvailable) throw new Error(__("Choose an available product type before continuing.", "arraysubs"));
      await form.validateFields(fields.map((f) => f.name));
      if (step === "details" && container) {
        advanceAfterConfig.current = true;
        setConfigOpen(true);
        return;
      }
      if (step === "billing" && container && !config)
        throw new Error(
          __("Save a configuration before continuing.", "arraysubs"),
        );
      goToStep(steps[steps.indexOf(step) + 1]);
    } catch (e) {
      const message = e.errorFields?.[0]?.errors?.[0] || e.message;
      setError(message);
      showToast(message, "error");
    }
  };
  const create = async () => {
    if (busy.current) return;
    busy.current = true;
    try {
      const allFields = steps.flatMap((item) => getFields(item, values, options, type));
      await form.validateFields(allFields.filter((item) => !item.disabled).map((item) => item.name));
      await confirm({
        title: __("Create product?", "arraysubs"),
        message: sprintf(
          __("Create and publish \u201c%s\u201d in your store?", "arraysubs"),
          values.title,
        ),
        confirmText: __("Create product", "arraysubs"),
        cancelText: __("Keep reviewing", "arraysubs"),
        loadingText: __("Creating product\u2026", "arraysubs"),
        variant: "info",
        onConfirm: async () => {
          setSaving(true);
          setError("");
          try {
            const settings = Object.fromEntries(
              Object.entries(values).filter(([key]) => key.startsWith("_")),
            );
            if (type === "simple")
              Object.entries(sync).forEach(([key, value]) => {
                settings[`_arraysubs_flex_sync_${key}`] = value;
              });
            const product = await request("", {
              request_id: requestId.current,
              type,
              title: values.title,
              description: values.description,
              regular_price: values.regular_price,
              sale_price: values.sale_price,
              virtual: type === "store_credit" || values.virtual,
              settings,
              config,
            });
            setCreated(product);
            window.dispatchEvent(new CustomEvent(QUICK_PRODUCT_CREATED_EVENT));
            showToast(__("Product created successfully.", "arraysubs"));
          } finally {
            setSaving(false);
          }
        },
      });
    } catch (e) {
      const invalid = e.errorFields?.[0];
      const message = invalid?.errors?.[0] || e.message;
      if (invalid) {
        const target = steps.find((item) => getFields(item, values, options, type).some((field) => field.name === invalid.name[0]));
        if (target) setStep(target);
      }
      setError(message);
      showToast(message, "error");
    } finally {
      busy.current = false;
    }
  };

  return (
    <>
      <Modal
        isOpen
        onClose={close}
        size="lg"
        title={__("Create subscription product", "arraysubs")}
        className="arraysubs-quick-product"
        closeOnBackdrop={false}
        closeOnEsc={!saving && !configOpen}
        showCloseButton={!saving}
      >
        {!created && (
          <div
            className="arraysubs-quick-product__progress"
            aria-label={__("Product creation progress", "arraysubs")}
          >
            <span>
              {sprintf(
                __("Step %1$d of %2$d", "arraysubs"),
                steps.indexOf(step) + 1,
                steps.length,
              )}
            </span>
            <progress value={steps.indexOf(step) + 1} max={steps.length} />
          </div>
        )}
        <div ref={contentRef} className="arraysubs-quick-product__body">
          {error && (
            <p className="arraysubs-quick-product__error" role="alert">
              {error}
            </p>
          )}
          {loading ? (
            <p role="status">{__("Loading product options…", "arraysubs")}</p>
          ) : created ? (
            <div className="arraysubs-quick-product__success">
              <CircleCheck size={54} aria-hidden="true" />
              <h2 tabIndex={-1}>
                {__("Congratulations! Your product is ready.", "arraysubs")}
              </h2>
              <p className="arraysubs-quick-product__created-title">{created.title}</p>
              <div className="arraysubs-quick-product__links">
                {proTrial.visible && (
                  <a
                    className="button button-primary arraysubs-quick-product__link-card arraysubs-quick-product__link-card--trial"
                    href={proTrial.href}
                    target="_blank"
                    rel="noopener noreferrer"
                    aria-label={proTrial.action}
                  >
                    <strong>{proTrial.title}</strong>
                    <span>{proTrial.description}</span>
                    <span className="arraysubs-quick-product__trial-action">
                      {proTrial.action}
                    </span>
                  </a>
                )}
                <a
                  className="button arraysubs-quick-product__link-card"
                  href={created.product_url}
                  target="_blank"
                  rel="noopener noreferrer"
                >
                  <strong>{__("View product page", "arraysubs")}</strong>
                  <span>
                    {__(
                      "Open this product’s public page to see what your customers see.",
                      "arraysubs",
                    )}
                  </span>
                </a>
                <a
                  className="button arraysubs-quick-product__link-card"
                  href={created.edit_url}
                  target="_blank"
                  rel="noopener noreferrer"
                >
                  <strong>{__("Edit product", "arraysubs")}</strong>
                  <span>
                    {__(
                      "Setup upgrade/ downgrade options and more advanced features.",
                      "arraysubs",
                    )}
                  </span>
                </a>
                <a
                  className="button arraysubs-quick-product__link-card"
                  href={created.member_access_url}
                  target="_blank"
                  rel="noopener noreferrer"
                >
                  <strong>{__("Set up member access", "arraysubs")}</strong>
                  <span>
                    {__(
                      "Create exclusive member benefits that keep subscribers coming back.",
                      "arraysubs",
                    )}
                  </span>
                </a>
              </div>
            </div>
          ) : (
            options && (
              <>
                <h2 tabIndex={-1}>{STEP_LABELS[step]}</h2>
                {step === "type" && (
                  <ProductTypePicker
                    options={options.types}
                    type={type}
                    onChange={(value) => {
                      setType(value);
                      setConfig(null);
                    }}
                  />
                )}
                {step === "variable-guide" && <VariableProductGuide />}
                {["membership", "shipping"].includes(step) && (
                  <p className="arraysubs-quick-product__step-description">
                    {step === "membership"
                      ? lifetime ? __("Lifetime deals have no membership end date.", "arraysubs") : __("Choose a shared end date and optionally limit when customers can enroll.", "arraysubs")
                      : __("These settings apply to physical products. Shipping amounts use your store currency.", "arraysubs")}
                    {!options.capabilities[step === "membership" ? "fixed_period_membership" : "shipping"] && <> <span className="arraysubs-renewal-price-pro-badge">{__("Pro", "arraysubs")}</span> {__("Enable this module in ArraySubs Pro to configure these options.", "arraysubs")}</>}
                  </p>
                )}
                <Form
                  form={form}
                  component="div"
                  initialValues={initialValues}
                  onValuesChange={changeValues}
                >
                  {steps.filter((item) => !["type", "review", "variable-guide", "sync"].includes(item)).map((item) => (
                    <div key={item} hidden={item !== step}>
                      <FormBuilder form={form} formItems={getFields(item, values, options, type)} />
                    </div>
                  ))}
                </Form>
                {step === "sync" &&
                  (syncAllowed ? (
                    <SyncRenewalsBuilder
                      productContext
                      sync={sync}
                      schedule={{
                        mode: values._arraysubs_subscription_mode,
                        flexible_periods: values._arraysubs_flexible_periods,
                        period: values._subscription_period,
                        interval: values._subscription_interval,
                      }}
                      onChange={(value) => {
                        setSync(value);
                        dirty.current = true;
                      }}
                    />
                  ) : (
                    <p className="arraysubs-quick-product__notice">
                      {lifetime
                        ? __("Lifetime products do not renew.", "arraysubs")
                        : !options.capabilities.renewal_sync
                        ? <>
                          {__(
                            "Renewals follow your store-wide settings. Custom segment plans are available with the Flexible Renewal Sync module.",
                            "arraysubs",
                          )}{" "}
                          <span className="arraysubs-quick-product__type-status">
                            <LockKeyhole size={12} aria-hidden="true" />
                            {__("Pro", "arraysubs")}
                          </span>
                        </>
                        : __(
                            "Custom renewal sync requires no trial, no different renewal price, and a billing cycle of at least three days. This product will use the standard renewal rules.",
                            "arraysubs",
                          )}
                    </p>
                  ))}
                {step === "billing" && container && (
                  <p>
                    {__(
                      "Billing, discounts, and renewal sync are managed in the product configuration below. Product-level trials and signup fees are not used for this product type.",
                      "arraysubs",
                    )}
                  </p>
                )}
                {step === "review" && (
                  <ProductReview
                    values={values}
                    options={options}
                    type={type}
                    steps={steps}
                    sync={sync}
                    goToStep={goToStep}
                  />
                )}
              </>
            )
          )}
          {container && Editor && !created && (
            <div hidden={!["billing", "review"].includes(step)}>
              <Editor
                key={type}
                initialConfig={config}
                modalOpen={configOpen}
                configureLabel={configureLabel}
                hideSummary={false}
                onSave={setConfig}
                onClose={() => {
                  setConfigOpen(false);
                  if (advanceAfterConfig.current) {
                    advanceAfterConfig.current = false;
                    goToStep("billing");
                  }
                }}
              />
            </div>
          )}
        </div>
        <div className="arraysubs-quick-product__footer">
          {created ? (
            <button
              type="button"
              className="button button-primary"
              onClick={onClose}
            >
              {__("Done", "arraysubs")}
            </button>
          ) : (
            <>
              <button
                type="button"
                className="button"
                disabled={saving}
                onClick={
                  step === "type"
                    ? close
                    : () => goToStep(steps[steps.indexOf(step) - 1])
                }
              >
                {step !== "type" && <ArrowLeft size={16} aria-hidden="true" />}
                {step === "type"
                  ? __("Cancel", "arraysubs")
                  : __("Previous", "arraysubs")}
              </button>
              {!options && !loading ? (
                <SpinnerButton
                  className="button button-primary"
                  loading={loading}
                  onClick={() => load()}
                >
                  {__("Try again", "arraysubs")}
                </SpinnerButton>
              ) : step === "variable-guide" ? (
                <a
                  className="button button-primary"
                  href={buildUrl(`${window.arraySubs?.env?.wpAdminUrl || `${window.location.origin}/wp-admin/`}post-new.php`, { post_type: "product" })}
                  target="_blank"
                  rel="noopener noreferrer"
                >
                  {__("Add new product", "arraysubs")}
                  <span className="screen-reader-text">{__("(opens in a new tab)", "arraysubs")}</span>
                  <ExternalLink size={16} aria-hidden="true" />
                </a>
              ) : step === "review" ? (
                <SpinnerButton
                  className="button button-primary"
                  loading={saving}
                  loadingText={__("Creating product…", "arraysubs")}
                  onClick={create}
                >
                  {__("Create product", "arraysubs")}
                </SpinnerButton>
              ) : (
                <SpinnerButton
                  className="button button-primary"
                  loading={loading}
                  loadingText={__("Loading…", "arraysubs")}
                  onClick={next}
                  disabled={!options || !typeAvailable || configOpen}
                >
                  {step === "details" && container
                    ? configureLabel
                    : __("Next", "arraysubs")}
                  <ArrowRight size={16} aria-hidden="true" />
                </SpinnerButton>
              )}
            </>
          )}
        </div>
      </Modal>
      {confirmDialog}
      <ToastContainer toasts={toasts} removeToast={removeToast} />
    </>
  );
}
