/**
 * Cast Conductor Proprietary License v5
 * SPDX-License-Identifier: LicenseRef-CastConductor-Proprietary-v5
 * 
 * Copyright (c) 2025 CastConductor.com. All Rights Reserved.
 * 
 * This file is part of Cast Conductor ("Software"). The Software and its source
 * code constitute proprietary, confidential, and trade secret information of
 * CastConductor.com ("Company"). Any access or use is governed strictly by the
 * Cast Conductor Proprietary License v5 ("License"). By installing, copying,
 * accessing, compiling, or otherwise using the Software you agree to be bound by
 * all terms of the License. If you do not agree, you must cease use immediately.
 * 
 * Key Terms (Summary – see full License for binding terms):
 *  1. No Redistribution: You may not publish, distribute, sublicense, rent,
 *     lease, transfer, sell, or otherwise make the Software (or any derivative)
 *     available to any third party without prior written consent of Company.
 *  2. No Modification: Modification, reverse engineering, decompilation, or
 *     disassembly is prohibited except to the limited extent expressly permitted
 *     by applicable law that cannot be contractually waived.
 *  3. Confidentiality: Treat all source code and related artifacts as Company
 *     Confidential Information. Maintain at least the same degree of care as for
 *     your own confidential materials, and not less than reasonable care.
 *  4. No Patent License: No express or implied patent rights are granted. Future
 *     patents (if any) are fully reserved.
 *  5. No Trademark License: Company names, marks, and logos may not be used
 *     without prior written permission.
 *  6. Limited Internal Use: Use is limited solely to internal evaluation and
 *     operation of licensed Cast Conductor deployments. Commercial hosting or
 *     resale as a service requires a separate written agreement.
 *  7. Telemetry & License Validation: The Software may periodically transmit a
 *     hashed installation identifier, domain (or site ID), plugin/app version,
 *     and a truncated (non-reversible) fragment of the license key solely to
 *     validate activation status and enforce licensing. This minimal "phone home"
 *     check contains no personal or content data. If optional telemetry is later
 *     introduced it will be limited to aggregate operational metrics (no PII),
 *     fully documented, and optionally disableable per published instructions.
 *  8. Third-Party Components: The Software may include open source components
 *     covered by their own licenses. See THIRD-PARTY-NOTICES.md. Those licenses
 *     govern their respective components; this License governs all remaining code.
 *  9. Export Compliance: You are responsible for compliance with all applicable
 *     export control and sanctions laws.
 * 10. Warranty Disclaimer: THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF
 *     ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO MERCHANTABILITY,
 *     FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND NON-INFRINGEMENT.
 * 11. Limitation of Liability: IN NO EVENT WILL COMPANY OR AUTHORS BE LIABLE FOR
 *     ANY INDIRECT, SPECIAL, INCIDENTAL, CONSEQUENTIAL, EXEMPLARY, OR PUNITIVE
 *     DAMAGES, OR LOST PROFITS, EVEN IF ADVISED OF THE POSSIBILITY.
 * 12. Acceptance: Use of the Software constitutes acceptance of the License.
 * 13. Enforcement: Unauthorized reproduction or distribution may result in civil
 *     and criminal penalties and will be prosecuted to the maximum extent allowed
 *     by law.
 * 
 * Authoritative EULA: EULA-v5.1.md (repository root – private) and https://castconductor.com/eula
 * Precedence: If this summary conflicts with the EULA, the EULA governs.
 * Revision: Current EULA revision v5.1 (subject to update; check EULA for current enterprise thresholds).
 * 
 * Full License text available from: licensing@castconductor.com
 * Security reports: security@castconductor.com
 * Commercial inquiries: licensing@castconductor.com
 * 
 * END OF HEADER
 * 
 * Layout bindings extraction (Phase 2.7 Step 4)
 */
import { applyPresetGeometry, fixedToPercent, percentToFixed } from '../modules/geometry-conversion.js';
// Use 1280×720 preset geometry for Content Block Canvas (not 1920×1080 from geometry-conversion.js)
import { PRESET_GEOMETRY } from '../modules/util-preset-geometry.js';

export function setupLayoutControls(editor) {
	const controls = [
		'canvas-width','canvas-height','canvas-position-x','canvas-position-y',
		'canvas-width-pct','canvas-height-pct','canvas-position-x-pct','canvas-position-y-pct',
		'canvas-padding-top','canvas-padding-right','canvas-padding-bottom','canvas-padding-left',
		'canvas-fit-mode'
	];
	controls.forEach(id => {
		const el = document.getElementById(id);
		if (!el) return;
		let _rafPending = false;
		const handler = () => {
			if (id.endsWith('-pct')) {
				_updateResponsiveFromPercentInputs(editor);
			} else {
				editor.updateLayoutConfig();
				// Intended container now confined to Block Template tab; handled separately.
			}
			// Real-time geometry mutation & HUD update batched via rAF
			if (!_rafPending) {
				_rafPending = true;
				requestAnimationFrame(()=>{
					_rafPending = false;
					try { editor.updateBlockEditorRectFromConfig && editor.updateBlockEditorRectFromConfig(); } catch(_) {}
					_refreshLayoutPills(editor);
					try { editor.logGeometryDiagnostics && editor.logGeometryDiagnostics('layout-input'); } catch(_) {}
				});
			}
			editor.triggerPreview(); // still trigger preview pipeline
			editor.markUnsaved();
		};
		el.addEventListener('input', handler);
		el.addEventListener('change', handler);
	});
	// If layout matches default and intended container changed from default, auto-apply preset once
	setTimeout(()=>{
		try {
			if (!editor.currentConfig) return;
			const l = editor.currentConfig.layout;
			const ic = l?.intendedContainer || l?.intended_container;
			if (ic && !editor._initialIntendedApplied) {
				applyPreset(editor, ic);
				editor._initialIntendedApplied = true;
				const pc = editor.previewContainer || document.getElementById('canvas-preview-container');
				if (pc) pc.classList.add('ccve-preset-flash-initial');
				setTimeout(()=> pc && pc.classList.remove('ccve-preset-flash-initial'), 1200);
				editor.triggerPreview();
			}
		} catch(_) {}
	}, 300);
	// Geometry mode toggle
	const modeSel = document.getElementById('ccve-geometry-mode');
	if (modeSel) {
		modeSel.addEventListener('change', () => {
			const newMode = modeSel.value === 'responsive' ? 'responsive' : 'fixed';
			if (newMode === editor._geometryMode) return;
			const oldMode = editor._geometryMode;
			editor._geometryMode = newMode;
			_switchGeometryMode(editor, newMode, oldMode);
			editor.triggerPreview();
			editor.markUnsaved();
			_refreshLayoutPills(editor);
			_syncResponsiveInputsVisibility(editor);
			_populateAdvancedGeometryInputs(editor);
		});
	}
	// Advanced toggle
	const adv = document.getElementById('ccve-advanced-geometry');
	const showBtn = document.getElementById('ccve-toggle-advanced-geometry');
	const hideBtn = document.getElementById('ccve-hide-advanced-geometry');
	if (showBtn && adv) showBtn.addEventListener('click', () => { adv.style.display='block'; showBtn.style.display='none'; });
	if (hideBtn && adv && showBtn) hideBtn.addEventListener('click', () => { adv.style.display='none'; showBtn.style.display='inline-block'; });
	_refreshLayoutPills(editor);

	// Dedicated intended container handler (scoped to Block Template tab only)
	const intendedSel = document.getElementById('canvas-intended-container');
	if (intendedSel) {
		const intendedHandler = () => {
			// Ensure current layout object up to date before applying preset
			try { editor.updateLayoutConfig && editor.updateLayoutConfig(); } catch(_) {}
			const key = editor.getControlValue('canvas-intended-container');
			console.log('[IntendedContainer] Dropdown changed to:', key);
			applyPreset(editor, key);
			// Force immediate geometry refresh & flash wrap for feedback
			try {
				const wrap = editor.previewContainer?.querySelector('.cc-block-editor-wrap');
				if (wrap) {
					wrap.classList.add('ccve-geom-flash');
					setTimeout(()=> wrap.classList.remove('ccve-geom-flash'), 500);
				}
			} catch(_) {}
			try {
				const pc = editor.previewContainer || document.getElementById('canvas-preview-container');
				if (pc) {
					pc.classList.add('ccve-preset-flash');
					clearTimeout(editor._presetFlashTimer);
					editor._presetFlashTimer = setTimeout(()=> pc.classList.remove('ccve-preset-flash'), 600);
				}
			} catch(_) {}
			try { editor.updateBlockEditorRectFromConfig && editor.updateBlockEditorRectFromConfig(); } catch(_) {}
			// Update container boundary visual to reflect new preset
			try { editor._ensureContainerBoundary && editor._ensureContainerBoundary(); } catch(_) {}
			// Re-render layers with new container offset
			try { editor._renderUnifiedLayers && editor._renderUnifiedLayers(); } catch(_) {}
			requestAnimationFrame(()=>{ 
				try { editor.updateBlockEditorRectFromConfig && editor.updateBlockEditorRectFromConfig(); } catch(_) {} 
				try { editor._ensureContainerBoundary && editor._ensureContainerBoundary(); } catch(_) {}
			});
			try { editor.logGeometryDiagnostics && editor.logGeometryDiagnostics('intended-container-change'); } catch(_) {}
			editor.triggerPreview();
			editor.markUnsaved();
		};
		intendedSel.addEventListener('change', intendedHandler);
		intendedSel.addEventListener('input', intendedHandler);
	}
}

export function applyPreset(editor, key) {
	if (!key) return;
	if (!editor.currentConfig) editor.currentConfig = editor.getDefaultConfig();
	const layout = editor.currentConfig.layout || (editor.currentConfig.layout = {});
	if (!layout.position) layout.position = { x: layout.x_position||0, y: layout.y_position||0 };
	console.log('[applyPreset] Applying preset:', key, 'Available presets:', Object.keys(PRESET_GEOMETRY));
	console.log('[applyPreset] Before layout:', JSON.stringify({ w: layout.width, h: layout.height, x: layout.position?.x, y: layout.position?.y }));
	const { changed, before } = applyPresetGeometry(layout, key, PRESET_GEOMETRY);
	console.log('[applyPreset] After applyPresetGeometry - changed:', changed, 'layout:', JSON.stringify({ w: layout.width, h: layout.height, x: layout.position?.x, y: layout.position?.y }));
	// Check if the geometry element exists - if not, we must render even if values haven't changed
	// This handles new/empty blocks where server preview failed and no wrap element exists yet
	const wrapExists = !!editor.previewContainer?.querySelector('.cc-block-editor-wrap');
	if (!changed && wrapExists) {
		console.log('[applyPreset] No change detected and wrap exists, returning early');
		return;
	}
	if (!changed && !wrapExists) {
		console.log('[applyPreset] No change but wrap missing - forcing geometry render for new block');
	}
	try { console.debug('[CCVE] appliedContainerPreset', key, { before, after: layout }); } catch(_){ }
	editor.setControlValue('canvas-width', layout.width);
	editor.setControlValue('canvas-height', layout.height);
	editor.setControlValue('canvas-position-x', layout.position.x);
	editor.setControlValue('canvas-position-y', layout.position.y);
	console.log('[applyPreset] Set control values - w:', layout.width, 'h:', layout.height, 'x:', layout.position.x, 'y:', layout.position.y);
	// Immediately sync internal layout config so geometry updater uses new numbers
	try { editor.updateLayoutConfig && editor.updateLayoutConfig(); } catch(_) {}
	// Reset baseline guides flag so they recalculate for new container bounds
	editor._baselineGuidesAdded = false;
	editor._guidesHorizontal = []; editor._guidesVertical = [];
	// Force bypass of diff hash on next preview (intended container considered structurally significant)
	try { editor._lastPreviewHash = null; } catch(_) {}
	_refreshLayoutPills(editor);
	clearTimeout(editor._pendingPresetSync);
	editor._pendingPresetSync = setTimeout(()=>{
		editor._resetOverlayElement && editor._resetOverlayElement();
		try { editor.getPreviewScale(); } catch(_) {}
		try { editor.updateBlockEditorRectFromConfig && editor.updateBlockEditorRectFromConfig(); } catch(_) {}
		requestAnimationFrame(()=>{ try { editor.updateBlockEditorRectFromConfig && editor.updateBlockEditorRectFromConfig(); } catch(_) {} });
		// Re-render layers to update container boundary
		try { editor._renderUnifiedLayers && editor._renderUnifiedLayers(); } catch(_) {}
	},16);
}

function _updateResponsiveFromPercentInputs(editor) {
	if (!editor.currentConfig || !editor.currentConfig.layout) return;
	const l = editor.currentConfig.layout;
	if (!l.responsive) l.responsive = { x_pct:0,y_pct:0,w_pct:0,h_pct:0,anchor:'tl' };
	const gx = parseFloat(document.getElementById('canvas-position-x-pct')?.value || l.responsive.x_pct || 0);
	const gy = parseFloat(document.getElementById('canvas-position-y-pct')?.value || l.responsive.y_pct || 0);
	const gw = parseFloat(document.getElementById('canvas-width-pct')?.value || l.responsive.w_pct || 0);
	const gh = parseFloat(document.getElementById('canvas-height-pct')?.value || l.responsive.h_pct || 0);
	l.responsive.x_pct = Math.max(0, Math.min(100, gx));
	l.responsive.y_pct = Math.max(0, Math.min(100, gy));
	l.responsive.w_pct = Math.max(0, Math.min(100, gw));
	l.responsive.h_pct = Math.max(0, Math.min(100, gh));
	const fixed = percentToFixed(l.responsive);
	l.x_position = fixed.x; l.y_position = fixed.y; l.width = fixed.w; l.height = fixed.h;
}

function _switchGeometryMode(editor, newMode, oldMode) {
	if (!editor.currentConfig || !editor.currentConfig.layout) return;
	const l = editor.currentConfig.layout;
	if (newMode === 'responsive') {
		if (!l.responsive) l.responsive = fixedToPercent({ x: l.x_position, y: l.y_position, w: l.width, h: l.height });
	} else {
		if (l.responsive) {
			const fr = percentToFixed(l.responsive);
			l.x_position = fr.x; l.y_position = fr.y; l.width = fr.w; l.height = fr.h;
		}
	}
}

function _refreshLayoutPills(editor) {
	if (!editor.currentConfig || !editor.currentConfig.layout) return;
	const l = editor.currentConfig.layout;
	const active = editor._geometryMode === 'responsive' && l.responsive ? percentToFixed(l.responsive) : { x: l.x_position ?? l.x, y: l.y_position ?? l.y, w: l.width, h:l.height };
	const set = (id,val) => { const el = document.getElementById(id); if (el) { const strong = el.querySelector('strong'); if (strong) strong.textContent = (val != null && !isNaN(val)) ? Math.round(val) : '—'; } };
	set('ccve-pill-left', active.x);
	set('ccve-pill-top', active.y);
	set('ccve-pill-width', active.w);
	set('ccve-pill-height', active.h);
	_populateAdvancedGeometryInputs(editor);
}

function _syncResponsiveInputsVisibility(editor) {
	const show = editor._geometryMode === 'responsive';
	document.querySelectorAll('.ccve-responsive-only').forEach(el => { el.style.display = show ? 'block' : 'none'; });
}

function _populateAdvancedGeometryInputs(editor) {
	if (!editor.currentConfig || !editor.currentConfig.layout) return;
	const l = editor.currentConfig.layout;
	if (l.responsive) {
		_setIfExists('canvas-width-pct', l.responsive.w_pct);
		_setIfExists('canvas-height-pct', l.responsive.h_pct);
		_setIfExists('canvas-position-x-pct', l.responsive.x_pct);
		_setIfExists('canvas-position-y-pct', l.responsive.y_pct);
	}
	_setIfExists('canvas-width', l.width);
	_setIfExists('canvas-height', l.height);
	_setIfExists('canvas-position-x', l.x_position ?? l.position?.x);
	_setIfExists('canvas-position-y', l.y_position ?? l.position?.y);
}

function _setIfExists(id,val) { const el = document.getElementById(id); if (el && val != null && !isNaN(val)) el.value = Math.round(val); }

// Re-export selected helpers for potential external usage
export const layoutBindingsInternals = { _refreshLayoutPills, _syncResponsiveInputsVisibility, _populateAdvancedGeometryInputs, _updateResponsiveFromPercentInputs, _switchGeometryMode };
