<template>
    <div>
        <div class="bm-admin__toolbar">
            <button
                type="button"
                class="bm-back-button"
                @click="$emit('back')"
            >← All blocks</button>
            <input
                v-model="name"
                type="text"
                placeholder="Block name"
                class="bm-name-input"
            />
            <button
                type="button"
                class="bm-button-primary"
                :disabled="saving || !name.trim()"
                @click="save"
            >{{ saving ? 'Saving…' : (currentId ? 'Update' : 'Create') }}</button>
            <button
                type="button"
                class="bm-button-primary bm-button-primary--ghost"
                :disabled="shipping || !currentId"
                @click="ship"
            >{{ shipping ? 'Shipping…' : 'Ship' }}</button>
            <span v-if="lastMessage">{{ lastMessage }}</span>
        </div>

        <div class="bm-admin">
            <div class="bm-admin__pane">
                <ElementPicker
                    :elements="elements"
                    :loading="loadingElements"
                    @add="addInstance"
                />
            </div>
            <div class="bm-admin__pane bm-admin__pane--canvas">
                <BlockPreviewCanvas
                    v-model="instances"
                    :selected-id="selectedInstanceId"
                    @select="selectInstance"
                    @delete="removeInstance"
                />
            </div>
            <div class="bm-admin__pane">
                <div class="bm-rail-tabs">
                    <button
                        v-for="tab in tabs"
                        :key="tab.id"
                        type="button"
                        class="bm-rail-tab"
                        :class="{ 'is-active': activeTab === tab.id }"
                        @click="activeTab = tab.id"
                    >{{ tab.label }}</button>
                </div>
                <div class="bm-rail-pane">
                    <!-- Selected element controls -->
                    <div v-if="activeTab === 'element'" class="bm-element-panel">
                        <template v-if="selectedInstance">
                            <h3 class="bm-admin__title">{{ selectedInstance.element_type }}</h3>
                            <!-- Containers are styled via the layout panel below, not a variant. -->
                            <label
                                v-if="!isContainerElement(selectedInstance.element_type)"
                                class="bm-element-panel__row"
                            >
                                <span>Variant</span>
                                <VariantPicker
                                    :value="selectedInstance.variant"
                                    :variants="variantsForType(selectedInstance.element_type)"
                                    @input="(v) => setVariant(selectedInstance.instance_id, v)"
                                />
                            </label>
                            <ContainerStylePanel
                                v-if="isContainerElement(selectedInstance.element_type)"
                                :value="selectedInstance.style_props || {}"
                                :tokens="tokens"
                                @input="(props) => setStyleProps(selectedInstance.instance_id, props)"
                            />
                            <div class="bm-element-panel__actions">
                                <button type="button" class="bm-instance__btn bm-instance__btn--danger" @click="removeSelected">✕ Remove</button>
                            </div>
                        </template>
                        <p v-else class="bm-rail-empty">Click an element in the canvas to edit it.</p>
                    </div>

                    <StructureTree
                        v-else-if="activeTab === 'structure'"
                        v-model="instances"
                        :selected-id="selectedInstanceId"
                        @select="selectInstance"
                        @delete="removeInstance"
                    />
                    <BlockSettings
                        v-else-if="activeTab === 'settings'"
                        :value="settings"
                        @input="updateSettings"
                    />
                    <FieldsPanel
                        v-else-if="activeTab === 'fields'"
                        :instances="instances"
                        :element-manifests="elements"
                        :panel="fieldsPanel"
                        @input="updateFieldsPanel"
                    />
                </div>
            </div>
        </div>
    </div>
</template>

<script>
import ElementPicker from './ElementPicker.vue';
import BlockPreviewCanvas from './BlockPreviewCanvas.vue';
import VariantPicker from './VariantPicker.vue';
import StructureTree from './StructureTree.vue';
import BlockSettings from './BlockSettings.vue';
import FieldsPanel from './FieldsPanel.vue';
import ContainerStylePanel from './ContainerStylePanel.vue';
import {
    findInstance as treeFind,
    removeInstance as treeRemove,
    updateInstance as treeUpdate,
} from '../../helpers/instance-tree.js';

const ENDPOINT = '/api/block-manager';

export default {
    name: 'BlockManagerMain',
    components: { ElementPicker, BlockPreviewCanvas, VariantPicker, StructureTree, BlockSettings, FieldsPanel, ContainerStylePanel },
    props: {
        blockId: { type: Number, default: null },
        mode: { type: String, default: 'composer' },
    },
    data() {
        return {
            elements: [],
            loadingElements: true,
            tokens: [],
            instances: [],
            selectedInstanceId: null,
            name: '',
            settings: { slug: '', description: '', icon: '' },
            fieldsPanel: { renames: {}, order: [], required: {}, custom: [], repeaters: [] },
            currentId: this.blockId,
            saving: false,
            shipping: false,
            lastMessage: '',
            activeTab: 'structure',
            tabs: [
                { id: 'element',   label: 'Element'   },
                { id: 'structure', label: 'Structure' },
                { id: 'settings',  label: 'Settings'  },
                { id: 'fields',    label: 'Fields'    },
            ],
        };
    },
    computed: {
        manifestByType() {
            const out = {};
            for (const m of this.elements) out[m.type] = m;
            return out;
        },
        selectedInstance() {
            // Depth-first search so selecting an element nested at any depth
            // still populates the right rail.
            if (!this.selectedInstanceId) return null;
            return treeFind(this.instances, this.selectedInstanceId);
        },
    },
    async mounted() {
        await Promise.all([this.loadElements(), this.loadTokens()]);
        if (this.currentId) {
            await this.loadBlock(this.currentId);
        }
    },
    methods: {
        async loadTokens() {
            try {
                const res = await fetch(`${ENDPOINT}/tokens`);
                const json = await res.json();
                this.tokens = json.data || [];
            } catch (err) {
                // Non-fatal: the container panel still works with raw values.
                this.tokens = [];
            }
        },
        async loadElements() {
            this.loadingElements = true;
            try {
                const res = await fetch(`${ENDPOINT}/elements`);
                const json = await res.json();
                this.elements = json.data || [];
            } catch (err) {
                this.lastMessage = `Failed to load elements: ${err.message}`;
            } finally {
                this.loadingElements = false;
            }
        },
        async loadBlock(id) {
            try {
                const res = await fetch(`${ENDPOINT}/${id}`);
                if (!res.ok) throw new Error(`status ${res.status}`);
                const { data } = await res.json();
                this.name = data.name || '';
                this.settings = {
                    slug: data.slug || '',
                    description: data.description || '',
                    icon: data.icon || '',
                };
                const structure = data.structure_json || {};
                this.instances = structure.elements || [];
                this.fieldsPanel = {
                    renames: {},
                    order: [],
                    required: {},
                    custom: [],
                    repeaters: [],
                    ...(structure.fields_panel || {}),
                };
            } catch (err) {
                this.lastMessage = `Failed to load block: ${err.message}`;
            }
        },
        isContainerElement(type) {
            const manifest = this.manifestByType[type];
            return !!(manifest && manifest.accepts_children);
        },
        addInstance(element) {
            // Click-to-add path. Drag drops are handled by vue-draggable-plus
            // mutating `instances` directly via v-model; the canvas emits
            // `select` for the just-dropped row to match this UX.
            const id = `el-${Date.now()}-${Math.floor(Math.random() * 1000)}`;
            const instance = {
                instance_id: id,
                element_type: element.type,
                variant: element.default_variant,
                field_name: element.type,
            };
            if (element.accepts_children) {
                instance.children = [];
                instance.style_props = { base: { default: {} } };
            }
            this.instances.push(instance);
            this.selectedInstanceId = id;
            this.activeTab = 'element';
        },
        selectInstance(instanceId) {
            this.selectedInstanceId = instanceId;
            this.activeTab = 'element';
        },
        variantsForType(type) {
            const manifest = this.manifestByType[type];
            return manifest ? (manifest.variants || []) : [];
        },
        removeSelected() {
            if (this.selectedInstance) {
                this.removeInstance(this.selectedInstance.instance_id);
            }
        },
        removeInstance(instanceId) {
            // Removes the node at whatever depth it lives.
            this.instances = treeRemove(this.instances, instanceId);
            if (this.selectedInstanceId === instanceId) {
                this.selectedInstanceId = null;
            }
        },
        setVariant(instanceId, variant) {
            this.instances = treeUpdate(this.instances, instanceId, { variant });
        },
        setStyleProps(instanceId, styleProps) {
            this.instances = treeUpdate(this.instances, instanceId, { style_props: styleProps });
        },
        updateSettings(next) {
            this.settings = next;
        },
        updateFieldsPanel(next) {
            this.fieldsPanel = next;
        },
        async save() {
            this.saving = true;
            this.lastMessage = '';
            const payload = {
                name: this.name,
                description: this.settings.description || null,
                icon: this.settings.icon || null,
                structure_json: {
                    elements: this.instances,
                    fields_panel: this.fieldsPanel,
                },
            };
            if (this.settings.slug) payload.slug = this.settings.slug;

            const isUpdate = !!this.currentId;
            const url = isUpdate ? `${ENDPOINT}/${this.currentId}` : ENDPOINT;
            const method = isUpdate ? 'PUT' : 'POST';
            try {
                const res = await fetch(url, {
                    method,
                    headers: {
                        'Content-Type': 'application/json',
                        'Accept': 'application/json',
                        'X-Requested-With': 'XMLHttpRequest',
                    },
                    body: JSON.stringify(payload),
                    credentials: 'same-origin',
                });
                if (!res.ok) {
                    const body = await res.text();
                    throw new Error(`${res.status} ${body.slice(0, 120)}`);
                }
                const { data } = await res.json();
                if (!isUpdate && data && data.id) {
                    this.currentId = data.id;
                    window.history.replaceState({}, '', `/admin/block-manager/${data.id}`);
                }
                if (data && data.slug) this.settings.slug = data.slug;
                this.lastMessage = 'Saved.';
            } catch (err) {
                this.lastMessage = `Save failed: ${err.message}`;
            } finally {
                this.saving = false;
            }
        },
        async ship() {
            if (!this.currentId) return;
            this.shipping = true;
            this.lastMessage = '';
            try {
                const res = await fetch(`${ENDPOINT}/${this.currentId}/ship`, {
                    method: 'POST',
                    headers: {
                        'Accept': 'application/json',
                        'X-Requested-With': 'XMLHttpRequest',
                    },
                    credentials: 'same-origin',
                });
                if (!res.ok) throw new Error(`status ${res.status}`);
                const { data } = await res.json();
                this.lastMessage = `Shipped: BlockRegistry id ${data.block_registry_id}.`;
            } catch (err) {
                this.lastMessage = `Ship failed: ${err.message}`;
            } finally {
                this.shipping = false;
            }
        },
    },
};
</script>
