<template>
    <div class="fmt-drawer" :class="{ 'fmt-drawer--open': Boolean(field), 'fmt-drawer--placement-pinned-canvas': placement === 'pinned-canvas' }">
        <div v-if="field" class="fmt-drawer__inner">
            <header class="fmt-drawer__header">
                <h3>{{ field.label || __("Field settings") }}</h3>
                <button
                    type="button"
                    class="fmt-close-btn"
                    @click="emit('close')"
                    :aria-label="__('Close', 'formatrica')"
                >
                    <img :src="ICON_CLOSE" alt="" aria-hidden="true" />
                </button>
            </header>
            <div class="fmt-drawer__content">
                <!-- Unknown (Pro) field type in this edition: inert placeholder,
                     config preserved untouched (plan §5.4). -->
                <PreservedProField v-if="isPreserved" :field="field" />
                <template v-else>
                <h4 class="fmt-drawer__section">{{ __("Basics", "formatrica") }}</h4>
                <label class="fmt-control" v-if="!hideLabelInput">
                    <span>{{ labelFieldLabel }}</span>
                    <input
                        type="text"
                        v-model="local.label"
                        @input="commit()"
                    />
                </label>
                <!-- Type-specific editor panel (basics placement) from the field
                     registry — Pro panels register under src/admin-pro/fields. -->
                <component
                    v-if="typeEditor && typeEditorPlacement === 'basics'"
                    :is="typeEditor"
                    :local="local"
                    :commit="commit"
                    :fields="fields"
                    :field-key="field?.key"
                />
                <label class="fmt-control" v-if="!isStatic">
                    <span>{{ __("Field name") }}</span>
                    <input type="text" v-model="local.name" @input="commit()" />
                </label>
                <label class="fmt-control" v-if="local.type === 'hidden'">
                    <span>{{ __("Value", "formatrica") }}</span>
                    <input type="text" v-model="local.value" @input="commit()" />
                    <small class="fmt-drawer__hint">
                        {{ __("Submitted with the form but never shown to the visitor — e.g. a campaign tag or source marker.", "formatrica") }}
                    </small>
                </label>
                <label class="fmt-control" v-if="supportsPlaceholder">
                    <span>{{ __("Placeholder") }}</span>
                    <input
                        type="text"
                        v-model="local.placeholder"
                        @input="commit()"
                    />
                </label>
                <label class="fmt-control" v-if="supportsRequired">
                    <span class="fmt-control__switch">
                        <input
                            type="checkbox"
                            v-model="local.required"
                            @change="commit()"
                        />
                        {{ __("Required") }}
                    </span>
                </label>
                <div class="fmt-control" v-if="supportsAccept">
                    <span>{{
                        __("Allowed file types", "formatrica")
                    }}</span>
                    <label class="fmt-control__switch">
                        <input
                            type="checkbox"
                            v-model="local.acceptImages"
                            @change="commit()"
                        />
                        {{ __("Images", "formatrica") }}
                    </label>
                    <label class="fmt-control__switch">
                        <input
                            type="checkbox"
                            v-model="local.acceptDocuments"
                            @change="commit()"
                        />
                        {{ __("Documents (PDF, Word, Text)", "formatrica") }}
                    </label>
                    <label class="fmt-control__switch">
                        <input
                            type="checkbox"
                            v-model="local.acceptSpreadsheets"
                            @change="commit()"
                        />
                        {{ __("Spreadsheets (Excel)", "formatrica") }}
                    </label>
                    <small class="fmt-drawer__hint">
                        {{
                            __(
                                "Select at least one file type",
                                "formatrica",
                            )
                        }}
                    </small>
                </div>
                <label class="fmt-control" v-if="supportsAccept">
                    <span>{{
                        __("Max file size (MB)", "formatrica")
                    }}</span>
                    <input
                        type="number"
                        v-model.number="local.maxFileSize"
                        @input="commit()"
                        min="1"
                        max="50"
                        step="1"
                    />
                    <small class="fmt-drawer__hint">
                        {{
                            __(
                                "Maximum: 50MB. Default: 5MB.",
                                "formatrica",
                            )
                        }}
                    </small>
                </label>
                <!-- Type-specific editor panel (body placement) from the field
                     registry — Pro panels register under src/admin-pro/fields. -->
                <component
                    v-if="typeEditor && typeEditorPlacement === 'body'"
                    :is="typeEditor"
                    :local="local"
                    :commit="commit"
                    :fields="fields"
                    :field-key="field?.key"
                />
                <label class="fmt-control" v-if="local.type === 'custom_text'">
                    <span>{{ __("Content", "formatrica") }}</span>
                    <textarea
                        rows="6"
                        v-model="local.content"
                        @input="commit()"
                    ></textarea>
                </label>
                <div
                    class="fmt-control"
                    v-if="supportsOptions"
                >
                    <span>{{ __("Options (one per line)") }}</span>
                    <textarea
                        rows="5"
                        v-model="optionsText"
                        @input="updateOptions"
                    ></textarea>
                </div>
                <div
                    class="fmt-control"
                    v-if="supportsWooCatalog"
                >
                    <div class="fmt-woo-toggle">
                        <button type="button" class="button button-small" @click="toggleWooSection()">
                            <span v-if="!wooSectionOpen">{{ __('Show WooCommerce options', 'formatrica') }}</span>
                            <span v-else>{{ __('Hide WooCommerce options', 'formatrica') }}</span>
                        </button>
                        <span class="fmt-help-icon-wrap">
                            <img
                                class="fmt-help-icon"
                                :src="ICON_HELP"
                                :alt="__('Help', 'formatrica')"
                                :title="wooHelpTitle"
                            />
                        </span>
                    </div>
                    <div v-if="wooSectionOpen">
                    <div class="fmt-setting__inline">
                        <button
                            type="button"
                            class="button button-secondary"
                            @click="loadWooCatalog('products')"
                            :disabled="wooCatalogLoading"
                        >
                            <span v-if="wooCatalogLoading && wooCatalogLoadingType === 'products'">
                                {{ __("Loading products…", "formatrica") }}
                            </span>
                            <span v-else>
                                {{ __("Load products", "formatrica") }}
                            </span>
                        </button>
                        <button
                            type="button"
                            class="button button-secondary"
                            @click="loadWooCatalog('categories')"
                            :disabled="wooCatalogLoading"
                        >
                            <span v-if="wooCatalogLoading && wooCatalogLoadingType === 'categories'">
                                {{ __("Loading categories…", "formatrica") }}
                            </span>
                            <span v-else>
                                {{ __("Load categories", "formatrica") }}
                            </span>
                        </button>
                    </div>
                    <small class="fmt-drawer__hint">
                        {{ __("Values will be set to the resource ID (products and variations use their numeric ID; categories are prefixed with cat:).", "formatrica") }}
                    </small>
                    <small class="fmt-drawer__hint">
                        {{ __("After loading, click “Save form”. To create WooCommerce orders from this field, open Form Settings → WP → WooCommerce and set this field as the Product field.", "formatrica") }}
                    </small>
                    <small
                        v-if="wooCatalogError"
                        class="fmt-drawer__hint fmt-drawer__hint--error"
                    >
                        {{ wooCatalogError }}
                    </small>
                    </div>
                </div>
                <label class="fmt-control" v-if="local.type === 'select'">
                    <span class="fmt-control__switch">
                        <input
                            type="checkbox"
                            v-model="local.multiple"
                            @change="commit()"
                        />
                        {{ __("Allow multiple selections", "formatrica") }}
                    </span>
                </label>
                <label class="fmt-control" v-if="local.type === 'country'">
                    <span>{{ __("WooCommerce country filter", "formatrica") }}</span>
                    <select v-model="local.woocommerce_mode" @change="commit()">
                        <option value="all">{{ __("All countries", "formatrica") }}</option>
                        <option value="shipping">{{ __("Shipping countries only", "formatrica") }}</option>
                        <option value="selling">{{ __("Selling countries only", "formatrica") }}</option>
                        <option value="both">{{ __("Both shipping & selling", "formatrica") }}</option>
                    </select>
                    <small class="fmt-drawer__hint">
                        {{ __("Requires WooCommerce to be active. Falls back to all countries if WooCommerce is not available.", "formatrica") }}
                    </small>
                </label>
                <div class="fmt-control" v-if="local.type === 'state'">
                    <label>
                        <span>{{ __("Linked country field", "formatrica") }}</span>
                        <select v-model="local.country_field" @change="commit()">
                            <option value="">{{ __("Select country field", "formatrica") }}</option>
                            <option
                                v-for="field in countryFields"
                                :key="field.name"
                                :value="field.name"
                            >
                                {{ field.label || field.name }}
                            </option>
                        </select>
                        <small class="fmt-drawer__hint">
                            {{ __("States will update when the selected country changes.", "formatrica") }}
                        </small>
                    </label>
                    <label class="fmt-control__switch">
                        <input
                            type="checkbox"
                            v-model="local.allow_text_input"
                            @change="commit()"
                        />
                        {{ __("Allow text input for countries without states", "formatrica") }}
                    </label>
                </div>
                <h4
                    class="fmt-drawer__section"
                    v-if="supportsWidth || supportsNumericBounds || !isStatic"
                >
                    {{ __("Advanced", "formatrica") }}
                </h4>
                <div class="fmt-control fmt-width" v-if="supportsWidth">
                    <span>{{ __("Column width", "formatrica") }}</span>
                    <div class="fmt-width__options">
                        <button
                            v-for="option in widthOptions"
                            :key="option.value"
                            type="button"
                            class="fmt-width__option"
                            :class="{
                                'fmt-width__option--active': local.layout.width === option.value,
                            }"
                            @click="selectWidth(option)"
                        >
                            <span>{{ option.label }}</span>
                        </button>
                    </div>
                </div>
                <div class="fmt-control fmt-bounds" v-if="supportsNumericBounds">
                    <span>{{ __("Numeric range", "formatrica") }}</span>
                    <div class="fmt-bounds__row">
                        <label>
                            <small>{{ __("Min", "formatrica") }}</small>
                            <input type="number" v-model.number="local.min" @input="commit()" />
                        </label>
                        <label>
                            <small>{{ __("Max", "formatrica") }}</small>
                            <input type="number" v-model.number="local.max" @input="commit()" />
                        </label>
                        <label>
                            <small>{{ __("Step", "formatrica") }}</small>
                            <input type="number" v-model.number="local.step" @input="commit()" />
                        </label>
                    </div>
                </div>
                <h4 class="fmt-drawer__section" v-if="supportsValidation">
                    {{ __("Validation", "formatrica") }}
                </h4>
                <div class="fmt-control fmt-validation" v-if="supportsValidation">
                    <label class="fmt-control__switch">
                        <input
                            type="checkbox"
                            v-model="local.validation.advanced_enabled"
                            @change="commit()"
                        />
                        {{ __("Advanced validation", "formatrica") }}
                    </label>
                    <template v-if="local.validation.advanced_enabled">
                        <label class="fmt-control">
                            <span>
                                {{ __("Rule", "formatrica") }}
                                <span v-if="PRO_UI && !hasProRules" class="fmt-width__pro">{{ PRO_RULES_LOCKED_LABEL }}</span>
                            </span>
                            <select v-model="local.validation.rule" @change="onRuleChange()">
                                <option value="">{{ __("Select a rule…", "formatrica") }}</option>
                                <optgroup :label="__('Free', 'formatrica')">
                                    <option
                                        v-for="rule in RULE_OPTIONS"
                                        :key="rule.value"
                                        :value="rule.value"
                                    >
                                        {{ rule.label }}
                                    </option>
                                </optgroup>
                                <optgroup v-if="proRuleOptions.length" :label="__('Pro', 'formatrica')">
                                    <option
                                        v-for="rule in proRuleOptions"
                                        :key="rule.value"
                                        :value="rule.value"
                                        :disabled="!hasProRules && local.validation.rule !== rule.value"
                                    >
                                        {{ rule.label }}{{ PRO_UI && !hasProRules ? PRO_SUFFIX : "" }}
                                    </option>
                                </optgroup>
                            </select>
                        </label>

                        <!-- Pro rule params -->
                        <label class="fmt-control" v-if="local.validation.rule === 'custom'">
                            <span>{{ __("Allowed characters", "formatrica") }}</span>
                            <input type="text" v-model="local.validation.params.charset" @input="commit()" placeholder="abcABC0123-_" />
                            <small class="fmt-drawer__hint">{{ __("The value may contain only these characters.", "formatrica") }}</small>
                        </label>
                        <label class="fmt-control" v-if="local.validation.rule === 'regex'">
                            <span>{{ __("Pattern (PCRE, without delimiters)", "formatrica") }}</span>
                            <input type="text" v-model="local.validation.params.pattern" @input="commit()" spellcheck="false" placeholder="[A-Z]{2}\d{4}" />
                            <small class="fmt-drawer__hint">{{ __("Anchored to the whole value. Checked on the server only.", "formatrica") }}</small>
                        </label>
                        <label class="fmt-control" v-if="local.validation.rule === 'restrictedwords'">
                            <span>{{ __("Restricted words (one per line)", "formatrica") }}</span>
                            <textarea rows="4" v-model="local.validation.params.list" @input="commit()"></textarea>
                            <small class="fmt-drawer__hint">{{ __("Submission is rejected if the value contains any of these. Server-only.", "formatrica") }}</small>
                        </label>
                        <label class="fmt-control fmt-control--switch" v-if="local.validation.rule === 'emaildns'">
                            <input type="checkbox" v-model="local.validation.params.strict" @change="commit()" />
                            <span>{{ __("Strict: reject if the domain has no mail server", "formatrica") }}</span>
                        </label>
                        <label class="fmt-control" v-if="local.validation.rule === 'password'">
                            <span>{{ __("Passphrase", "formatrica") }}</span>
                            <input
                                type="password"
                                v-model="passphraseInput"
                                @input="onPassphraseInput"
                                autocomplete="new-password"
                                :placeholder="hasPasswordHash ? __('•••••••• (set — type to change)', 'formatrica') : __('Enter a passphrase', 'formatrica')"
                            />
                            <small class="fmt-drawer__hint">{{ __("The visitor must enter this exact value. Stored hashed; the submitted answer is redacted.", "formatrica") }}</small>
                        </label>

                        <template v-if="local.validation.rule === 'multiplerules'">
                            <label class="fmt-control">
                                <span>{{ __("Match", "formatrica") }}</span>
                                <select v-model="local.validation.params.match" @change="commit()">
                                    <option value="all">{{ __("All rules must pass", "formatrica") }}</option>
                                    <option value="any">{{ __("Any one rule may pass", "formatrica") }}</option>
                                </select>
                            </label>
                            <div class="fmt-control">
                                <span>{{ __("Rules", "formatrica") }}</span>
                                <div
                                    v-for="(nested, i) in local.validation.params.rules"
                                    :key="i"
                                    class="fmt-logic__rule"
                                >
                                    <select v-model="nested.rule" @change="commit()">
                                        <option v-for="r in NESTABLE_RULE_OPTIONS" :key="r.value" :value="r.value">{{ r.label }}</option>
                                    </select>
                                    <input
                                        v-if="['minlength', 'maxlength'].includes(nested.rule)"
                                        type="number"
                                        min="0"
                                        v-model.number="nested.params.n"
                                        @input="commit()"
                                        :placeholder="__('length', 'formatrica')"
                                    />
                                    <button type="button" class="fmt-logic__remove" :aria-label="__('Remove rule', 'formatrica')" @click="removeNestedRule(i)">×</button>
                                </div>
                                <button type="button" class="fmt-logic__add" @click="addNestedRule">+ {{ __("Add rule", "formatrica") }}</button>
                            </div>
                        </template>

                        <label class="fmt-control" v-if="isLengthRule">
                            <span>{{ local.validation.rule === 'minlength' ? __("Minimum length", "formatrica") : __("Maximum length", "formatrica") }}</span>
                            <input
                                type="number"
                                min="0"
                                v-model.number="local.validation.params.n"
                                @input="commit()"
                            />
                        </label>
                        <label class="fmt-control" v-if="isSameasRule">
                            <span>{{ __("Must match field", "formatrica") }}</span>
                            <select v-model="local.validation.params.field_key" @change="commit()">
                                <option value="">{{ __("Select a field…", "formatrica") }}</option>
                                <option
                                    v-for="peer in peerFields"
                                    :key="peer.key"
                                    :value="peer.key"
                                >
                                    {{ peer.label || peer.name }}
                                </option>
                            </select>
                        </label>
                        <label class="fmt-control" v-if="local.validation.rule">
                            <span>{{ __("Custom error message (optional)", "formatrica") }}</span>
                            <input
                                type="text"
                                v-model="local.validation.message"
                                @input="commit()"
                                :placeholder="__('Leave blank for the default message', 'formatrica')"
                            />
                        </label>
                        <small class="fmt-drawer__hint">
                            {{ __("Rules run on non-empty values. Use “Required” to enforce a value.", "formatrica") }}
                        </small>
                    </template>
                </div>

                <div class="fmt-control fmt-logic" v-if="!isStatic && (PRO_UI || local.logic.enabled)">
                    <div class="fmt-logic__head">
                        <label class="fmt-toggle">
                            <input
                                type="checkbox"
                                :checked="local.logic.enabled"
                                :disabled="!hasLogic && !local.logic.enabled"
                                @change="toggleLogic"
                            />
                            <span>{{ __("Conditional logic", "formatrica") }}</span>
                        </label>
                        <span v-if="PRO_UI && !hasLogic" class="fmt-width__pro">{{ __("Pro", "formatrica") }}</span>
                    </div>

                    <template v-if="local.logic.enabled && canEditLogic">
                        <div class="fmt-logic__summary">
                            <select v-model="local.logic.action" @change="commit()">
                                <option value="show">{{ __("Show this field", "formatrica") }}</option>
                                <option value="hide">{{ __("Hide this field", "formatrica") }}</option>
                            </select>
                            <span>{{ __("when", "formatrica") }}</span>
                            <select v-model="local.logic.match" @change="commit()">
                                <option value="all">{{ __("all", "formatrica") }}</option>
                                <option value="any">{{ __("any", "formatrica") }}</option>
                            </select>
                            <span>{{ __("match:", "formatrica") }}</span>
                        </div>

                        <div
                            v-for="(rule, i) in local.logic.rules"
                            :key="i"
                            class="fmt-logic__rule"
                        >
                            <select v-model="rule.field_key" @change="commit()">
                                <option
                                    v-for="peer in logicPeerFields"
                                    :key="peer.key"
                                    :value="peer.key"
                                >
                                    {{ peer.label || peer.name }}
                                </option>
                            </select>
                            <select v-model="rule.operator" @change="commit()">
                                <option
                                    v-for="op in LOGIC_OPERATORS"
                                    :key="op.value"
                                    :value="op.value"
                                >
                                    {{ op.label }}
                                </option>
                            </select>
                            <input
                                v-if="!VALUELESS_OPERATORS.includes(rule.operator)"
                                type="text"
                                v-model="rule.value"
                                :placeholder="__('Value', 'formatrica')"
                                @input="commit()"
                            />
                            <button
                                type="button"
                                class="fmt-logic__remove"
                                :aria-label="__('Remove rule', 'formatrica')"
                                @click="removeLogicRule(i)"
                            >
                                ×
                            </button>
                        </div>

                        <button type="button" class="fmt-logic__add" @click="addLogicRule">
                            + {{ __("Add rule", "formatrica") }}
                        </button>
                        <small class="fmt-drawer__hint" v-if="!logicPeerFields.length">
                            {{ __("Add another field first to reference it in a rule.", "formatrica") }}
                        </small>
                    </template>
                    <small class="fmt-drawer__hint" v-else-if="PRO_UI && !hasLogic">
                        {{ HINT_LOGIC_PRO }}
                    </small>
                </div>

                <div class="fmt-control fmt-attrs" v-if="!isStatic && (PRO_UI || local.customAttrs.length > 0)">
                    <div class="fmt-logic__head">
                        <span>{{ __("Custom HTML attributes", "formatrica") }}</span>
                        <span v-if="PRO_UI && !hasCustomAttrs" class="fmt-width__pro">{{ __("Pro", "formatrica") }}</span>
                    </div>
                    <template v-if="canEditAttrs">
                        <div
                            v-for="(row, i) in local.customAttrs"
                            :key="i"
                            class="fmt-logic__rule"
                        >
                            <input
                                type="text"
                                v-model="row.name"
                                :placeholder="__('name (e.g. data-x)', 'formatrica')"
                                @input="commit()"
                            />
                            <input
                                type="text"
                                v-model="row.value"
                                :placeholder="__('value', 'formatrica')"
                                @input="commit()"
                            />
                            <button
                                type="button"
                                class="fmt-logic__remove"
                                :aria-label="__('Remove attribute', 'formatrica')"
                                @click="removeCustomAttr(i)"
                            >
                                ×
                            </button>
                        </div>
                        <button type="button" class="fmt-logic__add" @click="addCustomAttr">
                            + {{ __("Add attribute", "formatrica") }}
                        </button>
                        <small class="fmt-drawer__hint">
                            {{ __("Allowed: data-*, aria-*, and autocomplete, dir, inputmode, lang, readonly, spellcheck, tabindex, title. Others are dropped.", "formatrica") }}
                        </small>
                    </template>
                    <small class="fmt-drawer__hint" v-else-if="PRO_UI && !hasCustomAttrs">
                        {{ HINT_ATTRS_PRO }}
                    </small>
                </div>
                </template>
            </div>
        </div>
    </div>
</template>

<script setup>
import { computed, reactive, ref, watch, onMounted } from "vue";
import { __ } from "@/utils/i18n";
import { useCapabilities } from "@/admin/composables/useCapabilities";
import { fieldTypeDef, fieldTypeList, typeFlag } from "@/admin/fields/type-registry";
import PreservedProField from "./PreservedProField.vue";
// Vite define — a literal after build, so the minifier deletes dead branches.
// eslint-disable-next-line no-undef
const PRO_UI = __FMT_PRO_UI__;
// Literal ternaries fold at build time — the free bundle carries empty strings.
// eslint-disable-next-line no-undef
const PRO_RULES_LOCKED_LABEL = __FMT_PRO_UI__ ? __("Pro rules locked", "formatrica") : "";
// eslint-disable-next-line no-undef
const PRO_SUFFIX = __FMT_PRO_UI__ ? " (Pro)" : "";
/* eslint-disable no-undef */
const HINT_LOGIC_PRO = __FMT_PRO_UI__ ? __("Show or hide this field based on another field's value (Pro).", "formatrica") : "";
const HINT_ATTRS_PRO = __FMT_PRO_UI__ ? __("Add data-*, aria-*, and other safe HTML attributes to this field (Pro).", "formatrica") : "";
/* eslint-enable no-undef */
import ICON_HELP from "../../../assets/icons/help-hexagon.svg";
import ICON_CLOSE from "../../../assets/icons/hexagon-letter-x.svg";

const props = defineProps({
    field: {
        type: Object,
        default: null,
    },
    // 'default' = fixed right-edge overlay; 'pinned-canvas' = absolute inside
    // the builder grid, floating over the canvas column while the pinned
    // preview stays visible.
    placement: {
        type: String,
        default: "default",
        validator: (v) => v === "default" || v === "pinned-canvas",
    },
    fields: {
        type: Array,
        default: () => [],
    },
});

const emit = defineEmits(["update", "close"]);

const local = reactive({
    id: null,
    type: "",
    label: "",
    name: "",
    placeholder: "",
    required: true,
    options: [],
    multiple: false,
    content: "",
    value: "",
    accept: "",
    acceptImages: false,
    acceptDocuments: false,
    acceptSpreadsheets: false,
    maxFileSize: 5,
    woocommerce_mode: "all",
    country_field: "",
    allow_text_input: true,
    min: "",
    max: "",
    step: "",
    validation: { advanced_enabled: false, rule: "", params: {}, message: "" },
    layout: { width: "full" },
    logic: { enabled: false, action: "show", match: "all", rules: [] },
    customAttrs: [],
    // Type-specific keys (next_label, formula, ratingMax, …) are declared by
    // each type definition's localDefaults and merged in by the hydrator —
    // this edition-blind shell no longer hard-codes them.
});

// Field-type registry lookups (Phase 7): the current type's definition, its
// editor panel, and whether this is an unknown (preserved Pro) type.
const typeDef = computed(() => fieldTypeDef(local.type));
const isPreserved = computed(() => local.type !== "" && !typeDef.value);
const typeEditor = computed(() => typeDef.value?.editor || null);
const typeEditorPlacement = computed(() => typeDef.value?.editorPlacement || "body");
const hideLabelInput = computed(() => typeFlag(local.type, "hideLabelInput"));
const supportsOptions = computed(() => typeFlag(local.type, "supportsOptions"));

const labelFieldLabel = computed(
    () => typeDef.value?.labelText || __("Field label", "formatrica"),
);

// Server-resolved capability map (UX gating only — never a security boundary).
// Declared before its first use below; the derived hasX flags depend on it.
const { has: hasCapability } = useCapabilities();

// Custom HTML attributes (fields.custom_attrs). Repeater of {name, value}.
const hasCustomAttrs = hasCapability("fields.custom_attrs");
const canEditAttrs = computed(() => hasCustomAttrs || local.customAttrs.length > 0);
const addCustomAttr = () => {
    local.customAttrs.push({ name: "", value: "" });
    commit();
};
const removeCustomAttr = (index) => {
    local.customAttrs.splice(index, 1);
    commit();
};

// Conditional visibility logic (logic.visibility).
const hasLogic = hasCapability("logic.visibility");
const LOGIC_OPERATORS = [
    { value: "equals", label: __("equals", "formatrica") },
    { value: "not_equals", label: __("does not equal", "formatrica") },
    { value: "contains", label: __("contains", "formatrica") },
    { value: "not_contains", label: __("does not contain", "formatrica") },
    { value: "greater_than", label: __("greater than", "formatrica") },
    { value: "less_than", label: __("less than", "formatrica") },
    { value: "is_empty", label: __("is empty", "formatrica") },
    { value: "is_not_empty", label: __("is not empty", "formatrica") },
];
const VALUELESS_OPERATORS = ["is_empty", "is_not_empty"];
// A field can't be gated by itself or by a valueless field (registry flag;
// unknown/preserved types stay eligible, matching pre-registry behavior).
const logicPeerFields = computed(() =>
    (props.fields || []).filter(
        (f) =>
            f.key &&
            f.key !== props.field?.key &&
            typeFlag(f.type, "logicPeer", true),
    ),
);
// Show the builder when licensed OR when logic already exists (grandfathered).
const canEditLogic = computed(() => hasLogic || local.logic.enabled);
const toggleLogic = (event) => {
    if (!hasLogic && !local.logic.enabled) {
        event.preventDefault();
        return;
    }
    local.logic.enabled = event.target.checked;
    if (local.logic.enabled && local.logic.rules.length === 0) {
        addLogicRule();
        return;
    }
    commit();
};
const addLogicRule = () => {
    local.logic.rules.push({
        field_key: logicPeerFields.value[0]?.key || "",
        operator: "equals",
        value: "",
    });
    commit();
};
const removeLogicRule = (index) => {
    local.logic.rules.splice(index, 1);
    commit();
};

// Column-width control. full / half / third are available in Free.
const widthOptions = [
    { value: "full", label: __("Full", "formatrica") },
    { value: "half", label: __("Half", "formatrica") },
    { value: "third", label: __("Third", "formatrica") },
];
const supportsWidth = computed(() => typeFlag(local.type, "grid"));
const selectWidth = (option) => {
    local.layout.width = option.value;
    commit();
};

// Free-tier advanced validation rules (mirrors Rule_Validator::FREE_RULES).
const RULE_OPTIONS = [
    { value: "alpha", label: __("Letters only", "formatrica") },
    { value: "alphaspaces", label: __("Letters and spaces", "formatrica") },
    { value: "alphanumeric", label: __("Letters and numbers", "formatrica") },
    { value: "numeric", label: __("Numbers only", "formatrica") },
    { value: "numericspaces", label: __("Numbers and spaces", "formatrica") },
    { value: "alphaaccented", label: __("Letters only (accented)", "formatrica") },
    { value: "alphaspacesaccented", label: __("Letters and spaces (accented)", "formatrica") },
    { value: "alphanumericaccented", label: __("Letters and numbers (accented)", "formatrica") },
    { value: "minlength", label: __("Minimum length", "formatrica") },
    { value: "maxlength", label: __("Maximum length", "formatrica") },
    { value: "email", label: __("Email address", "formatrica") },
    { value: "validurl", label: __("URL", "formatrica") },
    { value: "ipaddress", label: __("IP address", "formatrica") },
    { value: "uszipcode", label: __("US ZIP code", "formatrica") },
    { value: "phonenumber", label: __("Phone number", "formatrica") },
    { value: "sameas", label: __("Matches another field", "formatrica") },
];

// Pro advanced validation rules (P12, fields.validation_pro_rules).
const PRO_RULE_OPTIONS = [
    { value: "custom", label: __("Custom character set", "formatrica") },
    { value: "creditcard", label: __("Credit card", "formatrica") },
    { value: "iban", label: __("IBAN", "formatrica") },
    { value: "regex", label: __("Regular expression", "formatrica") },
    { value: "restrictedwords", label: __("Restricted words", "formatrica") },
    { value: "emaildns", label: __("Email (DNS check)", "formatrica") },
    { value: "password", label: __("Passphrase", "formatrica") },
    { value: "multiplerules", label: __("Multiple rules", "formatrica") },
];
// Rules selectable inside a multiplerules compound (no nesting compounds).
const NESTABLE_RULE_OPTIONS = [...RULE_OPTIONS, ...PRO_RULE_OPTIONS.filter((r) => r.value !== "multiplerules")];

const hasProRules = hasCapability("fields.validation_pro_rules");
// Free bundle: only a grandfathered Pro rule (the currently-saved one) stays
// visible/selectable; the rest of the Pro set is absent, not locked.
const proRuleOptions = computed(() =>
    PRO_UI
        ? PRO_RULE_OPTIONS
        : PRO_RULE_OPTIONS.filter((r) => r.value === local.validation.rule),
);
const hasPasswordHash = computed(() => typeof local.validation.params?.hash === "string" && local.validation.params.hash !== "");

// Passphrase is transient UI state — never seeded from the store (only the hash
// round-trips). Typing sets params.passphrase; the server hashes + drops it.
const passphraseInput = ref("");
const onPassphraseInput = () => {
    local.validation.params.passphrase = passphraseInput.value;
    commit();
};
const addNestedRule = () => {
    if (!Array.isArray(local.validation.params.rules)) {
        local.validation.params.rules = [];
    }
    local.validation.params.rules.push({ rule: "alpha", params: {} });
    commit();
};
const removeNestedRule = (index) => {
    local.validation.params.rules.splice(index, 1);
    commit();
};

const optionsText = computed({
    get() {
        return (local.options || []).join("\n");
    },
    set(value) {
        local.options = value
            .split("\n")
            .map((entry) => entry.trim())
            .filter(Boolean);
    },
});

// Behavior flags from the field-type registry (Phase 7): the shell stays
// edition-blind, each type declares its own drawer semantics.
const supportsPlaceholder = computed(() => typeFlag(local.type, "supportsPlaceholder"));
const supportsNumericBounds = computed(() =>
    ["number", "range"].includes(local.type),
);
const supportsRequired = computed(() => typeFlag(local.type, "supportsRequired"));
const supportsAccept = computed(() => typeFlag(local.type, "supportsAccept"));
const isStatic = computed(() => typeFlag(local.type, "static"));
const supportsValidation = computed(() =>
    ["text", "email", "tel", "textarea", "password", "url"].includes(local.type),
);
const isLengthRule = computed(() =>
    ["minlength", "maxlength"].includes(local.validation.rule),
);
const isSameasRule = computed(() => local.validation.rule === "sameas");
const peerFields = computed(() =>
    (props.fields || []).filter(
        (f) =>
            f.key &&
            f.key !== props.field?.key &&
            !["button", "custom_text", "file"].includes(f.type),
    ),
);
const onRuleChange = () => {
    // Reset params when switching rules so stale n/field_key/charset don't linger.
    local.validation.params = {};
    passphraseInput.value = "";
    if (local.validation.rule === "multiplerules") {
        local.validation.params = { match: "all", rules: [] };
    }
    commit();
};
const countryFields = computed(() => {
    return (props.fields || []).filter((f) => f.type === "country");
});
const builderSettings = window.formatrica?.builder || {};
const wooActive = builderSettings?.woo?.active === true;
const wooCurrency = builderSettings?.woo?.currency || "";
const wooCatalogLoading = ref(false);
const wooCatalogLoadingType = ref(null);
const wooCatalogError = ref("");
const supportsWooCatalog = computed(
    () => wooActive && ["select", "radio"].includes(local.type)
);

const wooHelpTooltip = computed(() =>
    __(
        'Loaded options are applied immediately to this field. Remember to save the form. To generate WooCommerce orders from user selections, map this field as the Product field in Form Settings → WP → WooCommerce.',
        'formatrica'
    )
);

const wooHelpTitle = computed(() =>
    `${__("Populate options from WooCommerce", "formatrica")}\n${wooHelpTooltip.value}`
);

const WOO_TOGGLE_KEY = 'fmt_woo_loader_open';
const wooSectionOpen = ref(false);

const readWooToggle = () => {
    try {
        return localStorage.getItem(WOO_TOGGLE_KEY) === '1';
    } catch {
        return false;
    }
};

const writeWooToggle = (value) => {
    try {
        localStorage.setItem(WOO_TOGGLE_KEY, value ? '1' : '0');
    } catch {
        // ignore
    }
};

const toggleWooSection = () => {
    wooSectionOpen.value = !wooSectionOpen.value;
    writeWooToggle(wooSectionOpen.value);
};

onMounted(() => {
    wooSectionOpen.value = readWooToggle();
});

watch(supportsWooCatalog, (enabled) => {
    if (!enabled) {
        wooCatalogError.value = "";
    }
});

watch(
    () => props.field,
    (field) => {
        if (!field) {
            local.id = null;
            return;
        }

        Object.assign(local, {
            id: field.id,
            type: field.type,
            label: field.label,
            name: field.name,
            placeholder: field.placeholder,
            required: field.required,
            options: Array.isArray(field.options) ? [...field.options] : [],
            multiple: field.type === "select" ? !!field.multiple : false,
        });
        local.content = typeof field.content === "string" ? field.content : "";
        local.value = typeof field.value === "string" ? field.value : "";

        const acceptStr = typeof field.accept === "string" ? field.accept : "";
        local.accept = acceptStr;

        local.acceptImages = acceptStr.includes("image/");
        local.acceptDocuments = acceptStr.includes("application/pdf") || acceptStr.includes("application/msword");
        local.acceptSpreadsheets = acceptStr.includes("application/vnd.ms-excel") || acceptStr.includes("spreadsheet");

        local.maxFileSize = typeof field.maxFileSize === "number" && field.maxFileSize > 0 ? field.maxFileSize : 5;

        // Country field properties
        local.woocommerce_mode = field.type === "country" && typeof field.woocommerce_mode === "string"
            ? field.woocommerce_mode
            : "all";

        // State field properties
        local.country_field = field.type === "state" && typeof field.country_field === "string"
            ? field.country_field
            : "";
        local.allow_text_input = field.type === "state"
            ? field.allow_text_input !== false
            : true;

        // Number / range bounds.
        local.min = field.min ?? "";
        local.max = field.max ?? "";
        local.step = field.step ?? "";

        // Column width.
        local.layout = {
            width: field.layout && typeof field.layout === "object" && field.layout.width
                ? field.layout.width
                : "full",
        };

        // Type-specific drawer state (Phase 7): reset every registered type's
        // local keys to their defaults (so a previously-edited field's values
        // can't linger), then let the current type hydrate from the stored
        // field. Defaults are deep-cloned so shared def objects never leak
        // into the reactive state.
        fieldTypeList().forEach((def) => {
            if (def.localDefaults) {
                Object.assign(local, JSON.parse(JSON.stringify(def.localDefaults)));
            }
        });
        fieldTypeDef(field.type)?.hydrate?.(field, local);

        // Custom HTML attributes (map -> editable rows).
        local.customAttrs =
            field.attrs && typeof field.attrs === "object"
                ? Object.entries(field.attrs).map(([name, value]) => ({
                      name: String(name),
                      value: value == null ? "" : String(value),
                  }))
                : [];

        // Conditional logic.
        const fl = field.logic && typeof field.logic === "object" ? field.logic : {};
        local.logic = {
            enabled: !!fl.enabled,
            action: fl.action === "hide" ? "hide" : "show",
            match: fl.match === "any" ? "any" : "all",
            rules: Array.isArray(fl.rules)
                ? fl.rules.map((r) => ({
                      field_key: r.field_key || "",
                      operator: r.operator || "equals",
                      value: r.value || "",
                  }))
                : [],
        };

        // Advanced validation block (stable shape). params is deep-cloned so the
        // nested multiplerules array isn't shared with the store copy.
        const v = field.validation && typeof field.validation === "object" ? field.validation : {};
        local.validation = {
            advanced_enabled: !!v.advanced_enabled,
            rule: typeof v.rule === "string" ? v.rule : "",
            params: v.params && typeof v.params === "object" ? JSON.parse(JSON.stringify(v.params)) : {},
            message: typeof v.message === "string" ? v.message : "",
        };
        // Passphrase is never seeded from storage — only the hash round-trips.
        passphraseInput.value = "";
    },
    { immediate: true },
);

const loadWooCatalog = async (resource = "products") => {
    if (!supportsWooCatalog.value) {
        if (!wooActive) {
            wooCatalogError.value = __("WooCommerce is not active on this site.", "formatrica");
        }
        return;
    }

    if (!builderSettings?.restUrl || wooCatalogLoading.value) {
        return;
    }

    wooCatalogLoading.value = true;
    wooCatalogLoadingType.value = resource;
    wooCatalogError.value = "";

    const formatPrice = (price) => {
        if (!price) {
            return "";
        }
        return wooCurrency ? ` ${wooCurrency} ${price}` : ` ${price}`;
    };

    try {
        const response = await fetch(
            `${builderSettings.restUrl}/woocommerce/catalog?type=${resource}`,
            {
                headers: {
                    "X-WP-Nonce": builderSettings.nonce || "",
                },
            }
        );

        if (!response.ok) {
            throw new Error(response.statusText || 'Request failed');
        }

        const result = await response.json();
        if (!result.success) {
            wooCatalogError.value =
                result.message ||
                (resource === "categories"
                    ? __("Unable to load WooCommerce categories.", "formatrica")
                    : __("Unable to load WooCommerce products.", "formatrica"));
            return;
        }

        const linesOutput = [];
        if (resource === "categories") {
            if (Array.isArray(result.items)) {
                result.items.forEach((category) => {
                    linesOutput.push(`cat:${category.id} - ${category.name}`);
                });
            }
        } else if (Array.isArray(result.items)) {
            result.items.forEach((product) => {
                const baseLabel = `${product.id} - ${product.name}${formatPrice(product.price)}`;
                linesOutput.push(baseLabel);

                if (Array.isArray(product.variations)) {
                    product.variations.forEach((variation) => {
                        const variationLabel = `${variation.id} - ${product.name} (${variation.name || __('Variation', 'formatrica')})${formatPrice(variation.price)}`;
                        linesOutput.push(variationLabel);
                    });
                }
            });
        }

        if (linesOutput.length === 0) {
            wooCatalogError.value =
                resource === "categories"
                    ? __("No categories were returned from WooCommerce.", "formatrica")
                    : __("No products were returned from WooCommerce.", "formatrica");
            return;
        }

        optionsText.value = linesOutput.join("\n");
        commit();
    } catch (error) {
        wooCatalogError.value =
            error?.message ||
            __("Unexpected WooCommerce API error.", "formatrica");
    } finally {
        wooCatalogLoading.value = false;
        wooCatalogLoadingType.value = null;
    }
};
const commit = () => {
    if (!local.id) {
        return;
    }

    // Preserved (unknown-type) fields are never edited, never committed.
    if (isPreserved.value) {
        return;
    }

    let acceptString = "";
    if (supportsAccept.value) {
        const acceptTypes = [];
        if (local.acceptImages) {
            acceptTypes.push("image/jpeg", "image/png", "image/gif", "image/webp");
        }
        if (local.acceptDocuments) {
            acceptTypes.push(
                "application/pdf",
                "application/msword",
                "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
                "text/plain"
            );
        }
        if (local.acceptSpreadsheets) {
            acceptTypes.push(
                "application/vnd.ms-excel",
                "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
                "text/csv"
            );
        }
        acceptString = acceptTypes.join(",");
    } else {
        acceptString = local.accept;
    }

    const multipleValue = local.type === "select" ? !!local.multiple : false;

    const updated = {
        ...local,
        options: [...(local.options || [])],
        multiple: multipleValue,
        accept: acceptString,
        maxFileSize: supportsAccept.value ? Math.max(1, Math.min(50, local.maxFileSize || 5)) : undefined,
    };

    // Explicitly include country field properties
    if (local.type === "country") {
        updated.woocommerce_mode = local.woocommerce_mode || "all";
    }

    // Explicitly include state field properties
    if (local.type === "state") {
        updated.country_field = local.country_field || "";
        updated.allow_text_input = local.allow_text_input !== false;
    }

    // Number / range bounds — only carried on those types.
    if (["number", "range"].includes(local.type)) {
        updated.min = local.min;
        updated.max = local.max;
        updated.step = local.step;
    } else {
        delete updated.min;
        delete updated.max;
        delete updated.step;
    }

    // Custom HTML attributes — rows -> map (server re-applies the allow-list).
    const attrMap = {};
    (local.customAttrs || []).forEach((row) => {
        const name = (row.name || "").trim();
        if (name !== "") {
            attrMap[name] = row.value || "";
        }
    });
    if (Object.keys(attrMap).length > 0) {
        updated.attrs = attrMap;
    } else {
        delete updated.attrs;
    }

    // Conditional logic — deep-cloned so the stored copy doesn't share the
    // reactive rules array.
    // Advanced validation — deep-cloned so the stored copy doesn't share the
    // reactive params (nested multiplerules array). Passphrase rides in params
    // only when the admin typed one; the server hashes + drops it.
    updated.validation = JSON.parse(JSON.stringify(local.validation));

    updated.logic = {
        enabled: !!local.logic.enabled,
        action: local.logic.action === "hide" ? "hide" : "show",
        match: local.logic.match === "any" ? "any" : "all",
        rules: (local.logic.rules || []).map((r) => ({
            field_key: r.field_key || "",
            operator: r.operator || "equals",
            value: VALUELESS_OPERATORS.includes(r.operator) ? "" : r.value || "",
        })),
    };

    // Type-specific write-back from the field registry (Phase 7) — replaces
    // the per-type branches that used to live here. Runs after the generic
    // deletes above so a type hook can re-set keys like rating's `max`.
    fieldTypeDef(local.type)?.commitProps?.(local, updated);

    emit("update", updated);
};

const updateOptions = () => {
    commit();
};
</script>

<style scoped>
.fmt-drawer {
    position: fixed;
    top: 32px;
    right: -440px;
    width: 384px;
    max-width: calc(100vw - 40px);
    height: calc(100% - 32px);
    background: #fff;
    border-left: 1px solid #dcdcde;
    box-shadow: -4px 0 24px rgba(0, 0, 0, 0.1);
    transition: right 0.25s ease;
    z-index: 1000;
}

/* Pinned preview docked: the drawer anchors ABSOLUTELY inside the builder
   grid and floats over the canvas column only — its right edge stops at the
   canvas/preview gutter so the pinned preview stays visible.
   50% - 46px = (rail 64 + 2 x gap 24) / 2 - 10px buffer. */
@media (min-width: 768px) {
    .fmt-drawer.fmt-drawer--placement-pinned-canvas {
        position: absolute;
        top: 12px;
        bottom: 12px;
        right: -440px;
        height: auto;
        max-height: none;
    }

    .fmt-drawer.fmt-drawer--placement-pinned-canvas.fmt-drawer--open {
        right: calc(50% - 46px);
    }
}

/* Mobile: full-width bottom sheet sliding up. 46px = the WP
   admin bar height below the 783px admin breakpoint. */
@media (max-width: 767.98px) {
    .fmt-drawer {
        top: auto;
        right: 0;
        left: 0;
        bottom: 0;
        width: 100%;
        max-width: none;
        height: auto;
        max-height: calc(100dvh - 46px);
        transform: translateY(100%);
        transition: transform 0.25s ease;
        border-left: none;
        border-top: 1px solid #dcdcde;
        border-top-left-radius: 12px;
        border-top-right-radius: 12px;
        box-shadow: 0 -8px 24px rgba(0, 0, 0, 0.18);
    }

    .fmt-drawer.fmt-drawer--open {
        right: 0;
        transform: translateY(0);
    }

    .fmt-drawer__content {
        padding-bottom: max(32px, calc(env(safe-area-inset-bottom, 0px) + 32px));
    }
}

.fmt-close-drawer {
    width: 34px;
    height: 34px;
    text-align: center;
    border-radius: 50%;
    font-size: 24px;
    text-decoration: none;
    display: flex;
    align-content: center;
    justify-content: center;
    line-height: 32px;
}

.fmt-drawer--open {
    right: 0;
}

.fmt-drawer__inner {
    display: flex;
    flex-direction: column;
    height: 100%;
}

.fmt-drawer__header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 16px;
    border-bottom: 1px solid #dcdcde;
}

.fmt-drawer__header h3 {
    font-size: 1.15rem;
    margin: 0;
}

.fmt-drawer__content {
    padding: 18px 20px;
    display: grid;
    gap: 14px;
    overflow-y: auto;
}

.fmt-drawer__section {
    margin: 8px 0 2px;
    padding-top: 14px;
    border-top: 1px solid #ececed;
    font-size: 0.72rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: #757a82;
}

.fmt-drawer__section:first-child {
    margin-top: 0;
    padding-top: 0;
    border-top: none;
}

.fmt-control {
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.fmt-control > span {
    font-size: 0.9rem;
    font-weight: 600;
    color: #1d2327;
}

.fmt-drawer__hint {
    color: #6c757d;
    font-size: 0.92rem;
}

.fmt-drawer__hint--error {
    color: #b32d2e;
}

.fmt-label-with-help { display: inline-flex; align-items: center; gap: 6px; }
.fmt-help { width: 16px; height: 16px; display: inline-flex; align-items: center; justify-content: center; border-radius: 50%; background: #f0f0f1; color: #50575e; font-size: 12px; line-height: 1; cursor: help; user-select: none; }
.fmt-help-icon-wrap { display: inline-flex; align-items: center; }
.fmt-help-icon { width: 18px; height: 18px; opacity: 0.9; cursor: help; }

.fmt-woo-toggle { display: flex; align-items: center; gap: 10px; justify-content: space-between; }

.fmt-control__switch {
    display: flex;
    gap: 8px;
    align-items: center;
    font-size: 0.98rem;
}

input[type="text"],
input[type="number"],
textarea {
    width: 100%;
    font-size: 1rem;
    padding: 6px 8px;
}

.fmt-bounds__row {
    display: flex;
    gap: 8px;
    margin-top: 4px;
}
.fmt-bounds__row label {
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: 2px;
}
.fmt-bounds__row small {
    color: #646970;
    font-size: 0.8rem;
}
/* Column width control */
.fmt-width__options {
    display: flex;
    gap: 6px;
    margin-top: 6px;
}
.fmt-width__option {
    flex: 1 1 auto;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 4px;
    padding: 6px 8px;
    border: 1px solid #c3c4c7;
    background: #fff;
    border-radius: 6px;
    cursor: pointer;
    font-size: 12px;
}
.fmt-width__option--active {
    border-color: #2271b1;
    box-shadow: inset 0 0 0 1px #2271b1;
}
.fmt-width__option--locked {
    opacity: 0.55;
    cursor: not-allowed;
}
.fmt-width__pro {
    font-size: 0.6rem;
    font-weight: 700;
    text-transform: uppercase;
    color: #8b5cf6;
    border: 1px solid currentColor;
    border-radius: 4px;
    padding: 0 4px;
}
/* Conditional logic builder */
.fmt-logic__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
}
.fmt-logic__summary {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
    margin: 10px 0;
    font-size: 12px;
}
.fmt-logic__rule {
    display: flex;
    align-items: center;
    gap: 6px;
    margin-bottom: 6px;
}
.fmt-logic__rule select,
.fmt-logic__rule input {
    flex: 1 1 auto;
    min-width: 0;
}
.fmt-logic__remove {
    flex: 0 0 auto;
    border: none;
    background: none;
    cursor: pointer;
    font-size: 18px;
    line-height: 1;
    color: #d63638;
}
.fmt-logic__add {
    border: 1px dashed #c3c4c7;
    background: none;
    cursor: pointer;
    padding: 4px 10px;
    border-radius: 4px;
    font-size: 12px;
}
</style>
