import { Form, Space } from "antd";
import { useTranslation } from "react-i18next";
import AlertComponent from "../alert/alert.component";
import "./form-fields-changed.styles.scss";
import Prompt from "../../utils/prompt";

export default function FormsFieldChanged({ form, skipPrompt, onErrorNavigate, onReset, onDirtyChange }) {
  const { t } = useTranslation();

  const normalizeNamePath = (namePath) => (Array.isArray(namePath) ? namePath.filter((part) => part !== undefined) : [namePath]);

  const getFieldIdCandidates = (namePath) => {
    const normalizedNamePath = normalizeNamePath(namePath).map((part) => String(part));
    const underscoreId = normalizedNamePath.join("_");
    const dashId = normalizedNamePath.join("-");
    const dotName = normalizedNamePath.join(".");

    return [underscoreId, dashId, dotName].filter(Boolean);
  };

  const clearFormMeta = () => {
    const fieldMeta = form.getFieldsError().map(({ name }) => ({
      name,
      touched: false,
      validating: false,
      errors: [],
      warnings: []
    }));

    if (fieldMeta.length > 0) {
      form.setFields(fieldMeta);
    }

    onDirtyChange?.(false);
  };

  const handleReset = () => {
    if (onReset) {
      onReset();
    } else {
      form.resetFields();
    }

    window.requestAnimationFrame(() => {
      clearFormMeta();
    });
  };

  const getFieldDomNode = (namePath) => {
    const fieldInstance = form.getFieldInstance?.(namePath);
    const fieldIdCandidates = getFieldIdCandidates(namePath);
    const domCandidates = [
      fieldInstance?.nativeElement,
      fieldInstance?.input,
      fieldInstance?.resizableTextArea?.textArea,
      fieldInstance
    ];

    fieldIdCandidates.forEach((fieldId) => {
      const escapedFieldId = CSS.escape(fieldId);
      const directNode = document.getElementById(fieldId) || document.querySelector(`#${escapedFieldId}`);
      const labelNode = document.querySelector(`label[for="${escapedFieldId}"]`);
      const namedNode = document.querySelector(`[name="${escapedFieldId}"]`);
      const formItemNode =
        directNode?.closest?.(".ant-form-item") ||
        labelNode?.closest?.(".ant-form-item") ||
        namedNode?.closest?.(".ant-form-item");

      domCandidates.push(directNode);
      domCandidates.push(namedNode);
      domCandidates.push(formItemNode);
      domCandidates.push(formItemNode?.querySelector?.("input, textarea, select, .ant-select-selector"));
    });

    return domCandidates.find((candidate) => candidate instanceof HTMLElement) ?? null;
  };

  const waitForAnimationFrames = (frameCount = 1) =>
    new Promise((resolve) => {
      let remainingFrames = frameCount;
      const nextFrame = () => {
        if (remainingFrames <= 0) {
          resolve();
          return;
        }
        remainingFrames -= 1;
        window.requestAnimationFrame(nextFrame);
      };
      window.requestAnimationFrame(nextFrame);
    });

  const getFieldOwningTabMeta = (namePath) => {
    const fieldDomNode = getFieldDomNode(namePath);
    const owningTabPane = fieldDomNode?.closest?.(".ant-tabs-tabpane");
    const paneId = owningTabPane?.getAttribute?.("id") || null;
    const owningTabButton = paneId
      ? document.querySelector(`[role="tab"][aria-controls="${paneId.replace(/"/g, '\\"')}"]`)
      : null;
    const tabLabel = owningTabButton?.textContent?.trim() || null;

    return {
      owningTabPane,
      owningTabButton,
      tabLabel
    };
  };

  const openFieldOwningTab = async (namePath) => {
    const { owningTabPane, owningTabButton } = getFieldOwningTabMeta(namePath);
    if (!owningTabPane || owningTabPane.classList.contains("ant-tabs-tabpane-active")) return false;

    if (!(owningTabButton instanceof HTMLElement)) return false;

    owningTabButton.click();

    for (let index = 0; index < 24; index += 1) {
      await waitForAnimationFrames();
      if (owningTabPane.classList.contains("ant-tabs-tabpane-active")) return true;
    }

    return owningTabPane.classList.contains("ant-tabs-tabpane-active");
  };

  const scrollToErrorField = (namePath) => {
    const normalizedNamePath = normalizeNamePath(namePath);
    if (!normalizedNamePath.length) return;

    try {
      form.scrollToField(normalizedNamePath, {
        behavior: "smooth",
        block: "center",
        focus: true
      });
      window.requestAnimationFrame(() => {
        const fallbackNode = getFieldDomNode(normalizedNamePath);
        fallbackNode?.focus?.();
      });
      return;
    } catch {
      const fallbackTarget = document.getElementById(normalizedNamePath[0]?.toString?.() ?? "");
      fallbackTarget?.scrollIntoView({
        behavior: "smooth",
        block: "center"
      });
    }
  };

  const handleErrorClick = async (namePath) => {
    const normalizedNamePath = normalizeNamePath(namePath);
    if (!normalizedNamePath.length) return;

    const switchedTab = await openFieldOwningTab(normalizedNamePath);
    if (!switchedTab) {
      const navigationDelayMs = onErrorNavigate?.(normalizedNamePath) ?? 0;
      if (navigationDelayMs > 0) {
        window.setTimeout(() => {
          window.requestAnimationFrame(() => {
            scrollToErrorField(normalizedNamePath);
          });
        }, navigationDelayMs);
        return;
      }
    }

    await waitForAnimationFrames(switchedTab ? 2 : 1);
    scrollToErrorField(normalizedNamePath);
  };
  //if (!form.isFieldsTouched()) return <></>;
  return (
    <Form.Item className="form-fields-changed" shouldUpdate style={{ margin: 0, padding: 0, minHeight: "unset" }}>
      {() => {
        const errors = form
          .getFieldsError()
          .filter((fieldError) => fieldError.errors.length > 0)
          .flatMap((fieldError) => {
            const tabMeta = getFieldOwningTabMeta(fieldError.name);

            return fieldError.errors.map((errorMessage, errorIndex) => ({
              key: `${(fieldError.name || []).join(".")}-${errorIndex}-${errorMessage}`,
              message: errorMessage,
              namePath: fieldError.name,
              tabLabel: tabMeta.tabLabel
            }));
          });

        const groupedErrors = errors.reduce((groups, error) => {
          const groupKey = error.tabLabel || "__ungrouped__";
          if (!groups[groupKey]) {
            groups[groupKey] = {
              key: groupKey,
              label: error.tabLabel,
              errors: []
            };
          }
          groups[groupKey].errors.push(error);
          return groups;
        }, {});
        const errorGroups = Object.values(groupedErrors);
        const hasTabbedErrorGroups = errorGroups.some((group) => Boolean(group.label));

        if (form.isFieldsTouched())
          return (
            <Space orientation="vertical" style={{ width: "100%", marginBottom: 10 }}>
              <Prompt when={!skipPrompt} beforeUnload={true} message={t("general.messages.unsavedchangespopup")} />
              <AlertComponent
                type="warning"
                title={
                  <div>
                    <span>{t("general.messages.unsavedchanges")} </span>
                    <span
                      onClick={handleReset}
                      style={{
                        cursor: "pointer",
                        textDecoration: "underline"
                      }}
                    >
                      {t("general.actions.reset")}
                    </span>
                  </div>
                }
              />
              {errors.length > 0 && (
                <AlertComponent
                  type="error"
                  title={t("general.labels.validationerror")}
                  description={
                    <div className="form-fields-changed__error-groups">
                      {errorGroups.map((group) => (
                        <div key={group.key} className="form-fields-changed__error-group">
                          {hasTabbedErrorGroups && group.label ? (
                            <div className="form-fields-changed__error-group-title">{group.label}</div>
                          ) : null}
                          <ul className="form-fields-changed__error-list">
                            {group.errors.map((error) => (
                              <li key={error.key}>
                                {Array.isArray(error.namePath) && error.namePath.length > 0 ? (
                                  <button
                                    type="button"
                                    className="form-fields-changed__error-link"
                                    onClick={() => {
                                      handleErrorClick(error.namePath);
                                    }}
                                  >
                                    {error.message}
                                  </button>
                                ) : (
                                  error.message
                                )}
                              </li>
                            ))}
                          </ul>
                        </div>
                      ))}
                    </div>
                  }
                  showIcon
                />
              )}
            </Space>
          );
        return <div style={{ display: "none" }}></div>;
      }}
    </Form.Item>
  );
}
