import type { CSSProperties } from "react";
import type {
  Block,
  ButtonBlockProps,
  FormBlockProps,
  FormCheckboxBlockProps,
  FormCheckboxOption,
  FormFieldConfig,
  FormInputBlockProps,
  FormRadioBlockProps,
  FormRadioOption,
  FormSelectBlockProps,
  FormSelectOption,
} from "@/features/editor/state/editorStore";

export interface FormStyleEscapers {
  escapeAttr: (value: string) => string;
}

const defaultEscapers: FormStyleEscapers = {
  escapeAttr: (value) => value,
};

export interface FormInputExportTokens {
  labelStyleAttr: string;
  inputStyleAttr: string;
}

export interface FormSelectExportTokens {
  labelStyleAttr: string;
  selectStyleAttr: string;
}

export interface FormOptionGroupExportTokens {
  labelStyleAttr: string;
  optionStyleAttr: string;
}

const normalizeTextColor = (raw: unknown): string => {
  if (typeof raw !== "string") return "";
  const trimmed = raw.trim();
  return trimmed !== "" ? trimmed : "";
};

const computeRadiusPx = (radius: unknown): number => {
  const token = typeof radius === "string" ? radius : "md";
  if (token === "none") return 0;
  if (token === "sm") return 2;
  if (token === "lg") return 6;
  if (token === "full") return 9999;
  return 4;
};

const computeWidthMode = (props: { widthMode?: string; fullWidth?: boolean }): "auto" | "full" | "fixed" => {
  if (typeof props.widthMode === "string") {
    return props.widthMode as "auto" | "full" | "fixed";
  }
  if (props.fullWidth) {
    return "full";
  }
  return "auto";
};

export const computeFormInputExportTokens = (
  props: FormInputBlockProps,
  escapers: FormStyleEscapers = defaultEscapers,
): FormInputExportTokens => {
  const { escapeAttr } = escapers;

  const textColorRaw = normalizeTextColor(props.textColorCustom);
  const labelStyleAttr = textColorRaw ? ` style="color:${escapeAttr(textColorRaw)}"` : "";

  const inputStyleParts: string[] = [];
  if (textColorRaw) {
    inputStyleParts.push(`color:${escapeAttr(textColorRaw)}`);
  }

  if (typeof props.fillColorCustom === "string" && props.fillColorCustom.trim() !== "") {
    inputStyleParts.push(`background-color:${escapeAttr(props.fillColorCustom.trim())}`);
  }

  if (typeof props.strokeColorCustom === "string" && props.strokeColorCustom.trim() !== "") {
    inputStyleParts.push(`border-color:${escapeAttr(props.strokeColorCustom.trim())}`);
  }

  if (typeof props.paddingX === "number" && props.paddingX >= 0) {
    const em = props.paddingX / 16;
    inputStyleParts.push(`padding-left:${em}em`);
    inputStyleParts.push(`padding-right:${em}em`);
  }

  if (typeof props.paddingY === "number" && props.paddingY >= 0) {
    const em = props.paddingY / 16;
    inputStyleParts.push(`padding-top:${em}em`);
    inputStyleParts.push(`padding-bottom:${em}em`);
  }

  const widthMode = computeWidthMode({ widthMode: props.widthMode, fullWidth: props.fullWidth });
  if (widthMode === "fixed" && typeof props.widthPx === "number" && props.widthPx > 0) {
    const em = props.widthPx / 16;
    inputStyleParts.push(`width:${em}em`);
  }

  const radiusPx = computeRadiusPx(props.borderRadius);
  inputStyleParts.push(`border-radius:${radiusPx}px`);

  const inputStyleAttr = inputStyleParts.length > 0 ? ` style="${inputStyleParts.join(";")}"` : "";

  return {
    labelStyleAttr,
    inputStyleAttr,
  };
};

export const computeFormSelectExportTokens = (
  props: FormSelectBlockProps,
  escapers: FormStyleEscapers = defaultEscapers,
): FormSelectExportTokens => {
  const { escapeAttr } = escapers;

  const textColorRaw = normalizeTextColor(props.textColorCustom);
  const labelStyleAttr = textColorRaw ? ` style="color:${escapeAttr(textColorRaw)}"` : "";

  const selectStyleParts: string[] = [];
  if (textColorRaw) {
    selectStyleParts.push(`color:${escapeAttr(textColorRaw)}`);
  }

  const widthMode = computeWidthMode({ widthMode: props.widthMode, fullWidth: props.fullWidth });
  if (widthMode === "fixed" && typeof props.widthPx === "number" && props.widthPx > 0) {
    const em = props.widthPx / 16;
    selectStyleParts.push(`width:${em}em`);
  }

  if (typeof props.paddingX === "number" && props.paddingX >= 0) {
    const em = props.paddingX / 16;
    selectStyleParts.push(`padding-left:${em}em`);
    selectStyleParts.push(`padding-right:${em}em`);
  }

  if (typeof props.paddingY === "number" && props.paddingY >= 0) {
    const em = props.paddingY / 16;
    selectStyleParts.push(`padding-top:${em}em`);
    selectStyleParts.push(`padding-bottom:${em}em`);
  }

  if (typeof props.fillColorCustom === "string" && props.fillColorCustom.trim() !== "") {
    selectStyleParts.push(`background-color:${escapeAttr(props.fillColorCustom.trim())}`);
  }

  if (typeof props.strokeColorCustom === "string" && props.strokeColorCustom.trim() !== "") {
    selectStyleParts.push(`border-color:${escapeAttr(props.strokeColorCustom.trim())}`);
  }

  const radiusPx = computeRadiusPx(props.borderRadius);
  selectStyleParts.push(`border-radius:${radiusPx}px`);

  const selectStyleAttr = selectStyleParts.length > 0 ? ` style="${selectStyleParts.join(";")}"` : "";

  return {
    labelStyleAttr,
    selectStyleAttr,
  };
};

const computeOptionGroupExportTokensBase = (
  props: { textColorCustom?: string; paddingX?: number; paddingY?: number; fillColorCustom?: string; strokeColorCustom?: string; borderRadius?: string },
  escapers: FormStyleEscapers,
): FormOptionGroupExportTokens => {
  const { escapeAttr } = escapers;

  const textColorRaw = normalizeTextColor(props.textColorCustom);
  const labelStyleAttr = textColorRaw ? ` style="color:${escapeAttr(textColorRaw)}"` : "";

  const optionStyleParts: string[] = [];
  if (textColorRaw) {
    optionStyleParts.push(`color:${escapeAttr(textColorRaw)}`);
  }

  if (typeof props.paddingX === "number" && props.paddingX >= 0) {
    const em = props.paddingX / 16;
    optionStyleParts.push(`padding-left:${em}em`);
    optionStyleParts.push(`padding-right:${em}em`);
  }

  if (typeof props.paddingY === "number" && props.paddingY >= 0) {
    const em = props.paddingY / 16;
    optionStyleParts.push(`padding-top:${em}em`);
    optionStyleParts.push(`padding-bottom:${em}em`);
  }

  if (typeof props.fillColorCustom === "string" && props.fillColorCustom.trim() !== "") {
    optionStyleParts.push(`background-color:${escapeAttr(props.fillColorCustom.trim())}`);
  }

  if (typeof props.strokeColorCustom === "string" && props.strokeColorCustom.trim() !== "") {
    optionStyleParts.push(`border-color:${escapeAttr(props.strokeColorCustom.trim())}`);
    optionStyleParts.push("border-width:1px");
    optionStyleParts.push("border-style:solid");
  }

  const radiusPx = computeRadiusPx(props.borderRadius);
  optionStyleParts.push(`border-radius:${radiusPx}px`);

  const optionStyleAttr = optionStyleParts.length > 0 ? ` style="${optionStyleParts.join(";")}"` : "";

  return {
    labelStyleAttr,
    optionStyleAttr,
  };
};

export const computeFormCheckboxExportTokens = (
  props: FormCheckboxBlockProps,
  escapers: FormStyleEscapers = defaultEscapers,
): FormOptionGroupExportTokens =>
  computeOptionGroupExportTokensBase(
    {
      textColorCustom: props.textColorCustom,
      paddingX: props.paddingX,
      paddingY: props.paddingY,
      fillColorCustom: props.fillColorCustom,
      strokeColorCustom: props.strokeColorCustom,
      borderRadius: props.borderRadius,
    },
    escapers,
  );

export interface FormInputEditorTokens {
  fieldStyle: CSSProperties;
  widthClass: string;
  inputAlignClass: string;
}

export interface FormFieldEditorTokens {
  fieldStyle: CSSProperties;
}

export const computeFormInputEditorTokens = (props: FormInputBlockProps): FormInputEditorTokens => {
  const fieldStyle: CSSProperties = {};

  if (props.textColorCustom && props.textColorCustom.trim() !== "") {
    fieldStyle.color = props.textColorCustom;
  }
  if (props.fillColorCustom && props.fillColorCustom.trim() !== "") {
    fieldStyle.backgroundColor = props.fillColorCustom;
  }
  if (props.strokeColorCustom && props.strokeColorCustom.trim() !== "") {
    fieldStyle.borderColor = props.strokeColorCustom;
  }

  const widthMode = props.widthMode ?? "full";
  if (widthMode === "fixed" && typeof props.widthPx === "number" && props.widthPx > 0) {
    fieldStyle.width = `${props.widthPx}px`;
  }

  const radius = props.borderRadius ?? "md";
  if (radius === "none") {
    fieldStyle.borderRadius = 0;
  } else if (radius === "sm") {
    fieldStyle.borderRadius = 4;
  } else if (radius === "lg" || radius === "full") {
    fieldStyle.borderRadius = 9999;
  }

  // 에디터에서는 px 기반 padding/타이포 값을 그대로 fieldStyle 에 반영해 미리보기에서 변화가 보이도록 한다.
  if (typeof props.paddingX === "number" && props.paddingX >= 0) {
    fieldStyle.paddingInline = `${props.paddingX}px`;
  }

  if (typeof props.paddingY === "number" && props.paddingY >= 0) {
    fieldStyle.paddingBlock = `${props.paddingY}px`;
  }

  if (props.fontSizeCustom && props.fontSizeCustom.trim() !== "") {
    fieldStyle.fontSize = props.fontSizeCustom.trim();
  }

  if (props.lineHeightCustom && props.lineHeightCustom.trim() !== "") {
    fieldStyle.lineHeight = props.lineHeightCustom.trim();
  }

  if (props.letterSpacingCustom && props.letterSpacingCustom.trim() !== "") {
    fieldStyle.letterSpacing = props.letterSpacingCustom.trim();
  }

  const labelLayout = props.labelLayout ?? "stacked";
  const isInline = labelLayout === "inline";

  const align = props.align ?? "left";
  const inputAlignClass =
    align === "center" ? "text-center" : align === "right" ? "text-right" : "text-left";

  // widthMode 와 labelLayout 에 따라 wrapper 의 Tailwind width/flex 클래스를 결정한다.
  let widthClass = "w-full";
  if (isInline) {
    if (widthMode === "fixed") {
      // 고정 너비일 때는 flex 레이아웃의 너비 확장을 막기 위해 flex-none 으로 둔다.
      widthClass = "flex-none";
    } else if (widthMode === "full") {
      widthClass = "flex-1";
    } else {
      // auto: 인라인 레이아웃에서 내용 기반 너비 사용
      widthClass = "";
    }
  } else {
    if (widthMode === "fixed") {
      widthClass = ""; // 고정 너비는 style.width 로만 제어
    } else {
      widthClass = "w-full";
    }
  }

  return {
    fieldStyle,
    widthClass,
    inputAlignClass,
  };
};

export const computeFormSelectEditorTokens = (props: FormSelectBlockProps): FormFieldEditorTokens => {
  const fieldStyle: CSSProperties = {};

  if (props.textColorCustom && props.textColorCustom.trim() !== "") {
    fieldStyle.color = props.textColorCustom;
  }
  if (props.fillColorCustom && props.fillColorCustom.trim() !== "") {
    fieldStyle.backgroundColor = props.fillColorCustom;
  }
  if (props.strokeColorCustom && props.strokeColorCustom.trim() !== "") {
    fieldStyle.borderColor = props.strokeColorCustom;
  }

  const widthMode = props.widthMode ?? "full";
  if (widthMode === "fixed" && typeof props.widthPx === "number" && props.widthPx > 0) {
    fieldStyle.width = `${props.widthPx}px`;
  }

  const radius = props.borderRadius ?? "md";
  if (radius === "none") {
    fieldStyle.borderRadius = 0;
  } else if (radius === "sm") {
    fieldStyle.borderRadius = 4;
  } else if (radius === "lg" || radius === "full") {
    fieldStyle.borderRadius = 9999;
  }

  // 체크박스/라디오 그룹도 에디터에서 padding/타이포 스타일을 일부 반영해준다.
  if (typeof props.paddingX === "number" && props.paddingX >= 0) {
    fieldStyle.paddingInline = `${props.paddingX}px`;
  }

  if (typeof props.paddingY === "number" && props.paddingY >= 0) {
    fieldStyle.paddingBlock = `${props.paddingY}px`;
  }

  if (props.fontSizeCustom && props.fontSizeCustom.trim() !== "") {
    fieldStyle.fontSize = props.fontSizeCustom.trim();
  }

  if (props.lineHeightCustom && props.lineHeightCustom.trim() !== "") {
    fieldStyle.lineHeight = props.lineHeightCustom.trim();
  }

  if (props.letterSpacingCustom && props.letterSpacingCustom.trim() !== "") {
    fieldStyle.letterSpacing = props.letterSpacingCustom.trim();
  }

  return { fieldStyle };
};

export const computeFormOptionGroupEditorTokens = (
  props: FormCheckboxBlockProps | FormRadioBlockProps,
): FormFieldEditorTokens => {
  const fieldStyle: CSSProperties = {};

  if (props.textColorCustom && props.textColorCustom.trim() !== "") {
    fieldStyle.color = props.textColorCustom;
  }
  if (props.fillColorCustom && props.fillColorCustom.trim() !== "") {
    fieldStyle.backgroundColor = props.fillColorCustom;
  }
  if (props.strokeColorCustom && props.strokeColorCustom.trim() !== "") {
    fieldStyle.borderColor = props.strokeColorCustom;
  }

  const widthMode = props.widthMode ?? "full";
  if (widthMode === "fixed" && typeof props.widthPx === "number" && props.widthPx > 0) {
    fieldStyle.width = `${props.widthPx}px`;
  }

  const radius = props.borderRadius ?? "md";
  if (radius === "none") {
    fieldStyle.borderRadius = 0;
  } else if (radius === "sm") {
    fieldStyle.borderRadius = 4;
  } else if (radius === "lg" || radius === "full") {
    fieldStyle.borderRadius = 9999;
  }
  
  if (typeof props.paddingX === "number" && props.paddingX >= 0) {
    fieldStyle.paddingInline = `${props.paddingX}px`;
  }

  if (typeof props.paddingY === "number" && props.paddingY >= 0) {
    fieldStyle.paddingBlock = `${props.paddingY}px`;
  }

  if (props.fontSizeCustom && props.fontSizeCustom.trim() !== "") {
    fieldStyle.fontSize = props.fontSizeCustom.trim();
  }

  if (props.lineHeightCustom && props.lineHeightCustom.trim() !== "") {
    fieldStyle.lineHeight = props.lineHeightCustom.trim();
  }

  if (props.letterSpacingCustom && props.letterSpacingCustom.trim() !== "") {
    fieldStyle.letterSpacing = props.letterSpacingCustom.trim();
  }

  return { fieldStyle };
};

export const computeFormRadioExportTokens = (
  props: FormRadioBlockProps,
  escapers: FormStyleEscapers = defaultEscapers,
): FormOptionGroupExportTokens =>
  computeOptionGroupExportTokensBase(
    {
      textColorCustom: props.textColorCustom,
      paddingX: props.paddingX,
      paddingY: props.paddingY,
      fillColorCustom: props.fillColorCustom,
      strokeColorCustom: props.strokeColorCustom,
      borderRadius: props.borderRadius,
    },
    escapers,
  );

// 퍼블릭 렌더러용 폼 필드 스타일 토큰

export interface FormInputPublicTokens {
  wrapperLayoutClass: string;
  wrapperStyle: CSSProperties;
  widthClass: string;
  inputStyle: CSSProperties;
}

export interface FormSelectPublicTokens {
  widthClass: string;
  wrapperStyle: CSSProperties;
  selectStyle: CSSProperties;
}

export interface FormOptionGroupPublicTokens {
  widthClass: string;
  textSizeClass: string;
  groupStyle: CSSProperties;
  groupTextStyle: CSSProperties;
  optionContainerStyle: CSSProperties;
  optionTextStyle: CSSProperties;
  optionsStyle: CSSProperties;
}

const pxToEm = (px: number, base = 16) => `${px / base}em`;

const convertPxStringToEm = (value?: string | null) => {
  if (!value) return null;
  const match = value.trim().match(/-?\d+(?:\.\d+)?/);
  if (!match) return null;
  const px = parseFloat(match[0]);
  if (!Number.isFinite(px)) return null;
  return pxToEm(px);
};

export const computeFormInputPublicTokens = (props: FormInputBlockProps): FormInputPublicTokens => {
  const align = props.align ?? "left";
  const labelLayout = props.labelLayout ?? "stacked";
  const widthMode = props.widthMode ?? (props.fullWidth ? "full" : "auto");

  const isInlineLayout = labelLayout === "inline";
  const wrapperLayoutClass = isInlineLayout ? "flex flex-row items-center" : "flex flex-col gap-1";
  const wrapperStyle: CSSProperties = {};

  if (isInlineLayout) {
    const gapPx = typeof props.labelGapPx === "number" ? props.labelGapPx : 8;
    wrapperStyle.columnGap = pxToEm(gapPx);
  }

  const widthClass = widthMode === "full" ? "w-full" : "";

  const inputStyle: CSSProperties = {
    textAlign: align,
  };

  // 너비: fixed 모드일 때 widthPx 를 em 단위로 설정한다.
  if (widthMode === "fixed" && typeof props.widthPx === "number" && props.widthPx > 0) {
    inputStyle.width = pxToEm(props.widthPx);
  }

  // 타이포 관련 커스텀 값
  if (props.fontSizeCustom && props.fontSizeCustom.trim() !== "") {
    const fontSizeValue = props.fontSizeCustom.trim();
    if (fontSizeValue.endsWith("px")) {
      const fontSizeEm = convertPxStringToEm(fontSizeValue);
      if (fontSizeEm) {
        inputStyle.fontSize = fontSizeEm;
      }
    } else {
      inputStyle.fontSize = fontSizeValue;
    }
  }

  if (props.lineHeightCustom && props.lineHeightCustom.trim() !== "") {
    const lineHeightValue = props.lineHeightCustom.trim();
    if (lineHeightValue.endsWith("px")) {
      const lineHeightEm = convertPxStringToEm(lineHeightValue);
      if (lineHeightEm) {
        inputStyle.lineHeight = lineHeightEm;
      }
    } else {
      inputStyle.lineHeight = lineHeightValue;
    }
  }

  if (props.letterSpacingCustom && props.letterSpacingCustom.trim() !== "") {
    const letterSpacingValue = props.letterSpacingCustom.trim();
    if (letterSpacingValue.endsWith("px")) {
      const letterSpacingEm = convertPxStringToEm(letterSpacingValue);
      if (letterSpacingEm) {
        inputStyle.letterSpacing = letterSpacingEm;
      }
    } else {
      inputStyle.letterSpacing = letterSpacingValue;
    }
  }

  // 색상 관련 커스텀 값
  if (props.textColorCustom && props.textColorCustom.trim() !== "") {
    inputStyle.color = props.textColorCustom.trim();
  } else {
    inputStyle.color = "#f9fafb";
  }

  if (props.fillColorCustom && props.fillColorCustom.trim() !== "") {
    inputStyle.backgroundColor = props.fillColorCustom.trim();
  } else {
    inputStyle.backgroundColor = "#020617";
  }

  if (props.strokeColorCustom && props.strokeColorCustom.trim() !== "") {
    inputStyle.borderColor = props.strokeColorCustom.trim();
  } else {
    inputStyle.borderColor = "#334155";
  }

  if (typeof props.paddingX === "number" && props.paddingX >= 0) {
    inputStyle.paddingInline = pxToEm(props.paddingX);
  }

  if (typeof props.paddingY === "number" && props.paddingY >= 0) {
    inputStyle.paddingBlock = pxToEm(props.paddingY);
  }

  // 모서리 둥글기: borderRadius 토큰을 px 값으로 변환한다.
  const radiusToken = props.borderRadius ?? "md";
  const radiusPx =
    radiusToken === "none" ? 0 : radiusToken === "sm" ? 2 : radiusToken === "lg" ? 6 : radiusToken === "full" ? 9999 : 4;
  inputStyle.borderRadius = `${radiusPx}px`;

  return {
    wrapperLayoutClass,
    wrapperStyle,
    widthClass,
    inputStyle,
  };
};

export const computeFormSelectPublicTokens = (props: FormSelectBlockProps): FormSelectPublicTokens => {
  const widthMode = props.widthMode ?? (props.fullWidth ? "full" : "auto");
  const widthClass = widthMode === "full" ? "w-full" : "";

  const wrapperStyle: CSSProperties = {};
  const selectStyle: CSSProperties = {};

  if (widthMode === "fixed" && typeof props.widthPx === "number" && props.widthPx > 0) {
    wrapperStyle.width = pxToEm(props.widthPx);
  }

  if (props.fontSizeCustom && props.fontSizeCustom.trim() !== "") {
    const fontSizeValue = props.fontSizeCustom.trim();
    if (fontSizeValue.endsWith("px")) {
      const fontSizeEm = convertPxStringToEm(fontSizeValue);
      if (fontSizeEm) {
        wrapperStyle.fontSize = fontSizeEm;
        selectStyle.fontSize = fontSizeEm;
      }
    } else {
      wrapperStyle.fontSize = fontSizeValue;
      selectStyle.fontSize = fontSizeValue;
    }
  }

  if (props.lineHeightCustom && props.lineHeightCustom.trim() !== "") {
    const lineHeightValue = props.lineHeightCustom.trim();
    if (lineHeightValue.endsWith("px")) {
      const lineHeightEm = convertPxStringToEm(lineHeightValue);
      if (lineHeightEm) {
        wrapperStyle.lineHeight = lineHeightEm;
        selectStyle.lineHeight = lineHeightEm;
      }
    } else {
      wrapperStyle.lineHeight = lineHeightValue;
      selectStyle.lineHeight = lineHeightValue;
    }
  }

  if (props.letterSpacingCustom && props.letterSpacingCustom.trim() !== "") {
    const letterSpacingValue = props.letterSpacingCustom.trim();
    if (letterSpacingValue.endsWith("px")) {
      const letterSpacingEm = convertPxStringToEm(letterSpacingValue);
      if (letterSpacingEm) {
        wrapperStyle.letterSpacing = letterSpacingEm;
        selectStyle.letterSpacing = letterSpacingEm;
      }
    } else {
      wrapperStyle.letterSpacing = letterSpacingValue;
      selectStyle.letterSpacing = letterSpacingValue;
    }
  }

  // 텍스트 색상: textColorCustom 이 설정되어 있으면 해당 색상을 사용하고, 없으면 기본 밝은 텍스트 색상을 사용한다.
  if (props.textColorCustom && props.textColorCustom.trim() !== "") {
    const colorValue = props.textColorCustom.trim();
    wrapperStyle.color = colorValue;
    selectStyle.color = colorValue;
  } else {
    wrapperStyle.color = "#f9fafb";
    selectStyle.color = "#f9fafb";
  }

  // 배경/테두리 색상: fillColorCustom/strokeColorCustom 이 있으면 select 에 적용한다.
  if (props.fillColorCustom && props.fillColorCustom.trim() !== "") {
    selectStyle.backgroundColor = props.fillColorCustom.trim();
  }

  if (props.strokeColorCustom && props.strokeColorCustom.trim() !== "") {
    selectStyle.borderColor = props.strokeColorCustom.trim();
  }

  // 모서리 둥글기: borderRadius 토큰을 px 로 변환한다.
  const selectRadiusToken = props.borderRadius ?? "md";
  const selectRadiusPx =
    selectRadiusToken === "none"
      ? 0
      : selectRadiusToken === "sm"
        ? 2
        : selectRadiusToken === "lg"
          ? 6
          : selectRadiusToken === "full"
            ? 9999
            : 4;
  selectStyle.borderRadius = `${selectRadiusPx}px`;

  if (typeof props.paddingX === "number" && props.paddingX >= 0) {
    const paddingEm = pxToEm(props.paddingX);
    selectStyle.paddingInline = paddingEm;
  }

  if (typeof props.paddingY === "number" && props.paddingY >= 0) {
    const paddingEm = pxToEm(props.paddingY);
    selectStyle.paddingBlock = paddingEm;
  }

  return {
    widthClass,
    wrapperStyle,
    selectStyle,
  };
};

const computeOptionGroupPublicTokensBase = (
  props: FormCheckboxBlockProps | FormRadioBlockProps,
): FormOptionGroupPublicTokens => {
  const widthMode = props.widthMode ?? (props.fullWidth ? "full" : "auto");
  const widthClass = widthMode === "full" ? "w-full" : "";

  const groupStyle: CSSProperties = {};
  const optionContainerStyle: CSSProperties = {};
  const optionTextStyle: CSSProperties = {};
  const groupTextStyle: CSSProperties = {};
  const optionsStyle: CSSProperties = {};

  const textSizeClass = props.fontSizeCustom && props.fontSizeCustom.trim() !== "" ? "" : "text-xs";

  if (widthMode === "fixed" && typeof props.widthPx === "number" && props.widthPx > 0) {
    groupStyle.width = pxToEm(props.widthPx);
  }

  if (props.fontSizeCustom && props.fontSizeCustom.trim() !== "") {
    const fontSizeValue = props.fontSizeCustom.trim();
    if (fontSizeValue.endsWith("px")) {
      const fontSizeEm = convertPxStringToEm(fontSizeValue);
      if (fontSizeEm) {
        groupTextStyle.fontSize = fontSizeEm;
        optionTextStyle.fontSize = fontSizeEm;
      }
    } else {
      groupTextStyle.fontSize = fontSizeValue;
      optionTextStyle.fontSize = fontSizeValue;
    }
  }

  if (props.lineHeightCustom && props.lineHeightCustom.trim() !== "") {
    const lineHeightValue = props.lineHeightCustom.trim();
    if (lineHeightValue.endsWith("px")) {
      const lineHeightEm = convertPxStringToEm(lineHeightValue);
      if (lineHeightEm) {
        groupTextStyle.lineHeight = lineHeightEm;
        optionTextStyle.lineHeight = lineHeightEm;
      }
    } else {
      groupTextStyle.lineHeight = lineHeightValue;
      optionTextStyle.lineHeight = lineHeightValue;
    }
  }

  if (props.letterSpacingCustom && props.letterSpacingCustom.trim() !== "") {
    const letterSpacingValue = props.letterSpacingCustom.trim();
    if (letterSpacingValue.endsWith("px")) {
      const letterSpacingEm = convertPxStringToEm(letterSpacingValue);
      if (letterSpacingEm) {
        groupTextStyle.letterSpacing = letterSpacingEm;
        optionTextStyle.letterSpacing = letterSpacingEm;
      }
    } else {
      groupTextStyle.letterSpacing = letterSpacingValue;
      optionTextStyle.letterSpacing = letterSpacingValue;
    }
  }

  if (props.textColorCustom && props.textColorCustom.trim() !== "") {
    const colorValue = props.textColorCustom.trim();
    groupTextStyle.color = colorValue;
    optionTextStyle.color = colorValue;
  } else {
    groupTextStyle.color = "#e5e7eb";
    optionTextStyle.color = "#e5e7eb";
  }

  if (typeof props.paddingX === "number" && props.paddingX >= 0) {
    optionContainerStyle.paddingInline = pxToEm(props.paddingX);
  }

  if (typeof props.paddingY === "number" && props.paddingY >= 0) {
    optionContainerStyle.paddingBlock = pxToEm(props.paddingY);
  }

  // 옵션 컨테이너 배경/테두리 색상
  if (props.fillColorCustom && props.fillColorCustom.trim() !== "") {
    optionContainerStyle.backgroundColor = props.fillColorCustom.trim();
  }

  if (props.strokeColorCustom && props.strokeColorCustom.trim() !== "") {
    const strokeValue = props.strokeColorCustom.trim();
    optionContainerStyle.borderColor = strokeValue;
    optionContainerStyle.borderWidth = "1px";
    optionContainerStyle.borderStyle = "solid";
  }

  // 옵션 컨테이너 모서리 둥글기
  const radiusToken = props.borderRadius ?? "md";
  const radiusPx =
    radiusToken === "none"
      ? 0
      : radiusToken === "sm"
        ? 2
        : radiusToken === "lg"
          ? 6
          : radiusToken === "full"
            ? 9999
            : 4;
  optionContainerStyle.borderRadius = `${radiusPx}px`;

  if (typeof props.optionGapPx === "number" && props.optionGapPx >= 0) {
    optionsStyle.rowGap = pxToEm(props.optionGapPx);
  }

  return {
    widthClass,
    textSizeClass,
    groupStyle,
    groupTextStyle,
    optionContainerStyle,
    optionTextStyle,
    optionsStyle,
  };
};

export const computeFormCheckboxPublicTokens = (
  props: FormCheckboxBlockProps,
): FormOptionGroupPublicTokens => computeOptionGroupPublicTokensBase(props);

export const computeFormRadioPublicTokens = (props: FormRadioBlockProps): FormOptionGroupPublicTokens =>
  computeOptionGroupPublicTokensBase(props);

export interface FormControllerFieldPublicConfig {
  id: string;
  name: string;
  label: string;
  type: "text" | "email" | "textarea" | "select" | "checkbox" | "radio";
  required?: boolean;
  options?: Array<FormSelectOption | FormCheckboxOption | FormRadioOption>;
  groupLabelMode?: "text" | "image";
  groupLabelImageUrl?: string;
}

export interface FormControllerPublicTokens {
  fields: FormControllerFieldPublicConfig[];
  formClassName: string;
  formStyle: CSSProperties;
  submitLabel: string | null;
}

export const computeFormControllerPublicTokens = (
  formBlock: Block,
  blocks: Block[],
): FormControllerPublicTokens => {
  const props = formBlock.props as FormBlockProps;

  const hasControllerFields = Array.isArray(props.fieldIds) && props.fieldIds.length > 0;

  const controllerFields: FormControllerFieldPublicConfig[] = hasControllerFields
    ? (props.fieldIds ?? [])
        .map((fieldId) => blocks.find((b) => b.id === fieldId))
        .filter((b): b is Block => Boolean(b))
        .filter(
          (b) =>
            b.type === "formInput" ||
            b.type === "formSelect" ||
            b.type === "formCheckbox" ||
            b.type === "formRadio",
        )
        .map((fieldBlock) => {
          const anyProps: any = fieldBlock.props ?? {};

          if (fieldBlock.type === "formInput") {
            const name = anyProps.formFieldName ?? fieldBlock.id;
            const label = anyProps.label ?? anyProps.formFieldName ?? "입력 필드";

            return {
              id: fieldBlock.id,
              name,
              label,
              // 기존 PublicPageRenderer 컨트롤러 로직과 동일하게 formInput 은 항상 type "text" 로 취급한다.
              type: "text",
              required: Boolean(anyProps.required),
            } satisfies FormControllerFieldPublicConfig;
          }

          if (fieldBlock.type === "formSelect") {
            const options: FormSelectOption[] = Array.isArray(anyProps.options) ? anyProps.options : [];
            const name = anyProps.formFieldName ?? fieldBlock.id;
            const label = anyProps.label ?? anyProps.formFieldName ?? "선택 필드";

            return {
              id: fieldBlock.id,
              name,
              label,
              type: "select",
              options,
              required: Boolean(anyProps.required),
            } satisfies FormControllerFieldPublicConfig;
          }

          if (fieldBlock.type === "formCheckbox") {
            const options: FormCheckboxOption[] = Array.isArray(anyProps.options) ? anyProps.options : [];
            const name = anyProps.formFieldName ?? fieldBlock.id;
            const label = anyProps.groupLabel ?? anyProps.formFieldName ?? "체크박스";

            return {
              id: fieldBlock.id,
              name,
              label,
              type: "checkbox",
              options,
              groupLabelMode: anyProps.groupLabelMode,
              groupLabelImageUrl: anyProps.groupLabelImageUrl,
              required: Boolean(anyProps.required),
            } satisfies FormControllerFieldPublicConfig;
          }

          const options: FormRadioOption[] = Array.isArray(anyProps.options) ? anyProps.options : [];
          const name = anyProps.formFieldName ?? fieldBlock.id;
          const label = anyProps.groupLabel ?? anyProps.formFieldName ?? "라디오 그룹";

          return {
            id: fieldBlock.id,
            name,
            label,
            type: "radio",
            options,
            groupLabelMode: anyProps.groupLabelMode,
            groupLabelImageUrl: anyProps.groupLabelImageUrl,
            required: Boolean(anyProps.required),
          } satisfies FormControllerFieldPublicConfig;
        })
    : [];

  const fields: FormControllerFieldPublicConfig[] =
    hasControllerFields && controllerFields.length > 0
      ? controllerFields
      : Array.isArray(props.fields) && props.fields.length > 0
        ? props.fields.map((field) => ({
            id: field.id,
            name: field.name,
            label: field.label,
            type: field.type,
            required: field.required,
          }))
        : [];

  const mappedSubmitButton = blocks.find(
    (b) => b.type === "button" && b.id === props.submitButtonId,
  );
  const mappedSubmitLabel = (mappedSubmitButton?.props as ButtonBlockProps | undefined)?.label ?? null;

  // FormBlock 은 레이아웃/스타일을 가지지 않는 순수 컨트롤러이므로
  // formClassName 은 고정 기본값만 사용하고, formStyle 은 항상 빈 객체로 유지한다.
  const formClassNames = ["space-y-3"];
  const formStyle: CSSProperties = {};

  return {
    fields,
    formClassName: formClassNames.join(" "),
    formStyle,
    submitLabel: mappedSubmitLabel,
  };
};

export interface FormBlockExportTokens {
  hasControllerFields: boolean;
  controllerFields: Block[];
  fallbackFields: FormFieldConfig[];
  formStyleParts: string[];
}

export const computeFormBlockExportTokens = (
  formBlock: Block,
  blocks: Block[],
): FormBlockExportTokens => {
  const props = formBlock.props as FormBlockProps;

  const fieldIds = Array.isArray(props.fieldIds) ? props.fieldIds : [];
  const controllerFields = fieldIds
    .map((id) => blocks.find((b) => b.id === id))
    .filter((b): b is Block => Boolean(b))
    .filter(
      (b) =>
        b.type === "formInput" ||
        b.type === "formSelect" ||
        b.type === "formCheckbox" ||
        b.type === "formRadio",
    );

  let fallbackFields: FormFieldConfig[] = [];
  if (Array.isArray(props.fields) && props.fields.length > 0) {
    fallbackFields = props.fields;
  }

  // FormBlock 은 Export 레이어에서도 컨테이너 배경/레이아웃 스타일을 가지지 않는다.
  const formStyleParts: string[] = [];

  return {
    hasControllerFields: controllerFields.length > 0,
    controllerFields,
    fallbackFields,
    formStyleParts,
  };
};
