<template>
    <div class="bm-designer__layout">
        <!-- Landing experience: no draft loaded yet. -->
        <section v-if="!draftId" class="bm-designer__landing">
            <ElementVariantPicker />
        </section>

        <!-- Editor experience: draft loaded. -->
        <template v-else>
            <aside class="bm-designer__rail bm-designer__rail--left">
                <h2 class="bm-admin__title">Variant</h2>
                <div v-if="draft" class="bm-designer__draft-meta">
                    <div><strong>Type:</strong> {{ draft.element_type }}</div>
                    <div><strong>Slug:</strong> {{ draft.variant_slug }}</div>
                    <div><strong>Label:</strong> {{ draft.label || '—' }}</div>
                    <div v-if="draft.last_published_at">
                        <strong>Published:</strong>
                        <span>{{ draft.last_published_at }}</span>
                    </div>
                </div>

                <h3 class="bm-designer__rail-heading">State</h3>
                <StateTabBar :value="state" @input="(v) => (state = v)" />

                <h3 class="bm-designer__rail-heading">Breakpoint</h3>
                <BreakpointSwitcher :value="breakpoint" @input="(v) => (breakpoint = v)" />

                <div v-if="conflict.has_conflict" class="bm-designer__banner bm-designer__banner--warning">
                    <strong>Local edit detected.</strong>
                    <div class="bm-designer__banner-body">{{ conflict.reason }}</div>
                </div>
            </aside>

            <section class="bm-designer__canvas">
                <PreviewCanvas
                    :draft-id="draftId"
                    :properties-json="propertiesPayload"
                    :state="state"
                    :breakpoint="breakpoint"
                />
            </section>

            <aside class="bm-designer__rail bm-designer__rail--right">
                <div class="bm-admin__toolbar">
                    <button
                        type="button"
                        class="bm-button-primary"
                        :disabled="!draftId || saving"
                        @click="save"
                    >{{ saving ? 'Saving…' : 'Save' }}</button>
                    <button
                        type="button"
                        class="bm-button-primary bm-button-primary--ghost"
                        :disabled="!draftId || publishing"
                        @click="publish"
                    >{{ publishing ? 'Publishing…' : 'Publish' }}</button>
                    <RawValueBadge :properties-json="propertiesPayload" />
                </div>
                <div v-if="lastMessage" class="bm-designer__msg">{{ lastMessage }}</div>

                <div class="bm-designer__cell-hint">
                    Editing: <strong>{{ state }}</strong> @ <strong>{{ breakpoint }}</strong>
                </div>

                <div v-if="!ready" class="bm-designer__placeholder">Loading schema…</div>

                <template v-else>
                    <PropertyPanel
                        v-for="panel in schema"
                        :key="panel.id"
                        :panel="panel"
                        :values="valuesFor(panel.id)"
                        :tokens="tokens"
                        @input="(propName, value) => updateProp(panel.id, propName, value)"
                    />
                </template>
            </aside>
        </template>
    </div>
</template>

<script>
import PropertyPanel from './PropertyPanel.vue';
import PreviewCanvas from './PreviewCanvas.vue';
import ElementVariantPicker from './ElementVariantPicker.vue';
import StateTabBar from './StateTabBar.vue';
import BreakpointSwitcher from './BreakpointSwitcher.vue';
import RawValueBadge from './RawValueBadge.vue';

const VARIANTS_ENDPOINT = '/api/block-manager/variants';
const TOKENS_ENDPOINT   = '/api/block-manager/tokens';
const SCHEMA_ENDPOINT   = '/api/block-manager/property-schema';

export default {
    name: 'DesignerRoot',
    components: {
        PropertyPanel,
        PreviewCanvas,
        ElementVariantPicker,
        StateTabBar,
        BreakpointSwitcher,
        RawValueBadge,
    },
    props: {
        draftId: { type: Number, default: null },
    },
    data() {
        return {
            schema: [],
            tokens: [],
            draft:  null,
            // Working state of properties_json.base.{state}.{breakpoint}.{panel}.{property}
            base: { default: { desktop: {} } },
            state: 'default',
            breakpoint: 'desktop',
            ready: false,
            saving: false,
            publishing: false,
            lastMessage: '',
            conflict: { has_conflict: false, reason: null },
        };
    },
    computed: {
        propertiesPayload() {
            return { base: this.base };
        },
    },
    async mounted() {
        if (!this.draftId) return;
        await Promise.all([this.loadSchema(), this.loadTokens()]);
        await this.loadDraft(this.draftId);
        await this.refreshConflict();
        this.ready = true;
    },
    methods: {
        async loadSchema() {
            try {
                const r = await fetch(SCHEMA_ENDPOINT);
                const j = await r.json();
                this.schema = j.data || [];
            } catch (err) {
                this.lastMessage = `Schema load failed: ${err.message}`;
            }
        },
        async loadTokens() {
            try {
                const r = await fetch(TOKENS_ENDPOINT);
                const j = await r.json();
                this.tokens = j.data || [];
            } catch (err) {
                this.lastMessage = `Token load failed: ${err.message}`;
            }
        },
        async loadDraft(id) {
            try {
                const r = await fetch(`${VARIANTS_ENDPOINT}/${id}`);
                if (!r.ok) throw new Error(`status ${r.status}`);
                const { data } = await r.json();
                this.draft = data;
                const tree = (data.properties_json && data.properties_json.base) || {};
                this.base = this.normaliseBase(tree);
            } catch (err) {
                this.lastMessage = `Draft load failed: ${err.message}`;
            }
        },
        async refreshConflict() {
            if (!this.draftId) return;
            try {
                const r = await fetch(`${VARIANTS_ENDPOINT}/${this.draftId}/conflict`);
                if (!r.ok) return;
                const { data } = await r.json();
                this.conflict = data || { has_conflict: false, reason: null };
            } catch (_err) {
                // best-effort; banner just stays hidden
            }
        },
        /** Ensures every (state × breakpoint) cell exists so $set isn't needed in updateProp. */
        normaliseBase(rawBase) {
            const states = ['default', 'hover', 'focus', 'active', 'disabled'];
            const breakpoints = ['desktop', 'tablet', 'mobile'];
            const out = {};
            states.forEach((s) => {
                out[s] = {};
                breakpoints.forEach((b) => {
                    out[s][b] = (rawBase[s] && rawBase[s][b]) || {};
                });
            });
            return out;
        },
        valuesFor(panelId) {
            const cell = this.base[this.state] && this.base[this.state][this.breakpoint];
            return (cell && cell[panelId]) || {};
        },
        updateProp(panelId, propName, value) {
            const cell = { ...(this.base[this.state][this.breakpoint] || {}) };
            const panel = { ...(cell[panelId] || {}) };
            if (value === null || value === undefined) {
                delete panel[propName];
            } else {
                panel[propName] = value;
            }
            cell[panelId] = panel;
            this.$set(this.base[this.state], this.breakpoint, cell);
        },
        async save() {
            if (!this.draftId) return;
            this.saving = true;
            this.lastMessage = '';
            try {
                const r = await fetch(`${VARIANTS_ENDPOINT}/${this.draftId}`, {
                    method:  'PUT',
                    headers: {
                        'Content-Type':     'application/json',
                        'Accept':           'application/json',
                        'X-Requested-With': 'XMLHttpRequest',
                    },
                    body: JSON.stringify({ properties_json: { base: this.base } }),
                    credentials: 'same-origin',
                });
                if (!r.ok) throw new Error(`status ${r.status}`);
                this.lastMessage = 'Saved.';
            } catch (err) {
                this.lastMessage = `Save failed: ${err.message}`;
            } finally {
                this.saving = false;
            }
        },
        async publish() {
            if (!this.draftId) return;
            this.publishing = true;
            this.lastMessage = '';
            try {
                const r = await fetch(`${VARIANTS_ENDPOINT}/${this.draftId}/publish`, {
                    method:  'POST',
                    headers: {
                        'Accept':           'application/json',
                        'X-Requested-With': 'XMLHttpRequest',
                    },
                    credentials: 'same-origin',
                });
                if (!r.ok) throw new Error(`status ${r.status}`);
                const { data } = await r.json();
                this.lastMessage = `Published. Twig: ${data.twig_path}`;
                await this.refreshConflict();
            } catch (err) {
                this.lastMessage = `Publish failed: ${err.message}`;
            } finally {
                this.publishing = false;
            }
        },
    },
};
</script>
