import { canvasClear } from '../diagram/canvas-clear.js';
import { fileSaveSvg } from '../diagram/dgrm-png.js';
import { deserialize, serialize } from '../diagram/dgrm-serialization.js';
import { generateKey, srvSave } from '../diagram/dgrm-srv.js';
import { fileOpen, fileSave } from '../infrastructure/file.js';
import { tipShow, uiDisable } from './ui.js';

export class Menu extends HTMLElement {
	connectedCallback() {
		const shadow = this.attachShadow({ mode: 'closed' });
		shadow.innerHTML = `
			<style>
			.menu {
				top: 15px;
				left: 15px;
				cursor: pointer;
			}
			#options {
				padding: 15px;
				box-shadow: 0px 0px 58px 2px rgb(34 60 80 / 20%);
				background-color: rgba(255,255,255, .9);

    position: absolute !important;
				top: 0px;
				left: 0px;
                width: 200px;

				z-index: 1;
			}

			#options div, #options a { 
				color: rgb(13, 110, 253); 
				cursor: pointer; margin: 10px 0;
				display: flex;
				align-items: center;
				line-height: 25px;
				text-decoration: none;
			}
			#options div svg, #options a svg { margin-right: 10px; }
			</style>
			<svg id="menu" class="menu" viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M3 4h18v2H3V4zm0 7h18v2H3v-2zm0 7h18v2H3v-2z" fill="rgb(52,71,103)"/></svg>
			<div id="options" style="visibility: hidden;">
			 	<div id="menu2" style="margin: 0 0 15px;"><svg viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M3 4h18v2H3V4zm0 7h18v2H3v-2zm0 7h18v2H3v-2z" fill="rgb(52,71,103)"/></svg></div>
				<div id="new"><svg viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M9 2.003V2h10.998C20.55 2 21 2.455 21 2.992v18.016a.993.993 0 0 1-.993.992H3.993A1 1 0 0 1 3 20.993V8l6-5.997zM5.83 8H9V4.83L5.83 8zM11 4v5a1 1 0 0 1-1 1H5v10h14V4h-8z" fill="rgb(52,71,103)"/></svg>New diagram</div>
				<div id="open"><svg viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M3 21a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h7.414l2 2H20a1 1 0 0 1 1 1v3h-2V7h-7.414l-2-2H4v11.998L5.5 11h17l-2.31 9.243a1 1 0 0 1-.97.757H3zm16.938-8H7.062l-1.5 6h12.876l1.5-6z" fill="rgb(52,71,103)"/></svg>Open diagram image</div>
				<div id="save"><svg viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M3 19h18v2H3v-2zm10-5.828L19.071 7.1l1.414 1.414L12 17 3.515 8.515 4.929 7.1 11 13.17V2h2v11.172z" fill="rgb(52,71,103)"/></svg>Save diagram image</div>
				<div id="link" style="display: none;"><svg viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M13.06 8.11l1.415 1.415a7 7 0 0 1 0 9.9l-.354.353a7 7 0 0 1-9.9-9.9l1.415 1.415a5 5 0 1 0 7.071 7.071l.354-.354a5 5 0 0 0 0-7.07l-1.415-1.415 1.415-1.414zm6.718 6.011l-1.414-1.414a5 5 0 1 0-7.071-7.071l-.354.354a5 5 0 0 0 0 7.07l1.415 1.415-1.415 1.414-1.414-1.414a7 7 0 0 1 0-9.9l.354-.353a7 7 0 0 1 9.9 9.9z" fill="rgb(52,71,103)"/></svg>Copy link to diagram</div>
				<a style="display: none;" href="/donate.html" target="_blank" style="margin-bottom: 0;">
					<svg viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0H24V24H0z"/><path d="M12.001 4.529c2.349-2.109 5.979-2.039 8.242.228 2.262 2.268 2.34 5.88.236 8.236l-8.48 8.492-8.478-8.492c-2.104-2.356-2.025-5.974.236-8.236 2.265-2.264 5.888-2.34 8.244-.228zm6.826 1.641c-1.5-1.502-3.92-1.563-5.49-.153l-1.335 1.198-1.336-1.197c-1.575-1.412-3.99-1.35-5.494.154-1.49 1.49-1.565 3.875-.192 5.451L12 18.654l7.02-7.03c1.374-1.577 1.299-3.959-.193-5.454z" fill="rgb(255,66,77)"/></svg>Donate
				</a>
		 	</div>`;

		const options = shadow.getElementById('options');
		function toggle() { options.style.visibility = options.style.visibility === 'visible' ? 'hidden' : 'visible'; }

		/** @param {string} id, @param {()=>void} handler */
		function click(id, handler) {
			shadow.getElementById(id).onclick = _ => {
				uiDisable(true);
				handler();
				toggle();
				uiDisable(false);
			};
		}

		shadow.getElementById('menu').onclick = toggle;
		shadow.getElementById('menu2').onclick = toggle;

		click('new', () => { canvasClear(this._canvas); });

click('save', () => {
    const serialized = serialize(this._canvas);
    if (serialized.s.length === 0) { alertEmpty(); return; }

    fileSaveSvg(this._canvas, serialized, blob => {
        fileSave(blob, 'dgrm.svg');
    });
});

click('open', () =>
    fileOpen('.svg', async svgFile => await loadData(this._canvas, svgFile))
);

		click('link', async () => {
			const serialized = serialize(this._canvas);
			if (serialized.s.length === 0) { alertEmpty(); return; }

			const key = generateKey();
			const url = new URL(window.location.href);
			url.searchParams.set('k', key);
			// use clipboard before server call - to fix 'Document is not focused'
			await navigator.clipboard.writeText(url.toString());
			await srvSave(key, serialized);

			alert('Link to diagram copied to clipboard');
		});
	}

	/** @param {CanvasElement} canvas */
	init(canvas) {
		/** @private */ this._canvas = canvas;

		// file drag to window
		document.body.addEventListener('dragover', evt => { evt.preventDefault(); });
		document.body.addEventListener('drop', async evt => {
			evt.preventDefault();

			if (evt.dataTransfer?.items?.length !== 1 ||
				evt.dataTransfer.items[0].kind !== 'file' ||
				evt.dataTransfer.items[0].type !== 'image/png') {
				alertCantOpen(); return;
			}

			await loadData(this._canvas, evt.dataTransfer.items[0].getAsFile());
		});
	}
};
customElements.define('ap-menu', Menu);




/** @param {CanvasElement} canvas, @param {File|Blob} svgFile */
import { CanvasSmbl } from '../infrastructure/canvas-smbl.js';

function parseTranslateFromString(str) {
    if (!str) return { x: 0, y: 0 };
    const m = /translate\(\s*([-\d.]+)(?:px)?\s*(?:,|\s)\s*([-\d.]+)(?:px)?\s*\)/.exec(str);
    if (m) return { x: parseFloat(m[1]), y: parseFloat(m[2]) };
    const mm = /matrix\(\s*([-\d.e]+)[,\s]+([-\d.e]+)[,\s]+([-\d.e]+)[,\s]+([-\d.e]+)[,\s]+([-\d.e]+)[,\s]+([-\d.e]+)\s*\)/.exec(str);
    if (mm && mm.length >= 7) return { x: parseFloat(mm[5]), y: parseFloat(mm[6]) };
    return { x: 0, y: 0 };
}

function getEffectiveTranslate(el) {
    // priority: style attribute "transform: translate(...)" -> attribute transform -> HTMLElement.style.transform
    if (!el || !el.getAttribute) return { x: 0, y: 0 };
    const styleAttr = el.getAttribute('style');
    if (styleAttr) {
        const m = /transform\s*:\s*([^;]+)/.exec(styleAttr);
        if (m) {
            const p = parseTranslateFromString(m[1]);
            if (Number.isFinite(p.x) || Number.isFinite(p.y)) return p;
        }
    }
    const trAttr = el.getAttribute('transform');
    if (trAttr) {
        const p = parseTranslateFromString(trAttr);
        if (Number.isFinite(p.x) || Number.isFinite(p.y)) return p;
    }
    if (el instanceof HTMLElement && el.style && el.style.transform) {
        const p = parseTranslateFromString(el.style.transform);
        if (Number.isFinite(p.x) || Number.isFinite(p.y)) return p;
    }
    return { x: 0, y: 0 };
}

function extractCoordsFromPathD(d) {
    if (!d) return { start: { x: 0, y: 0 }, end: { x: 0, y: 0 } };
    const nums = (d.match(/-?\d+(\.\d+)?/g) || []).map(Number);
    if (nums.length >= 4) {
        return { start: { x: nums[0], y: nums[1] }, end: { x: nums[nums.length - 2], y: nums[nums.length - 1] } };
    }
    return { start: { x: 0, y: 0 }, end: { x: 0, y: 0 } };
}

function detectMainTag(el) {
    if (!el || !el.querySelector) return null;
    const main = el.querySelector('[data-key="main"]');
    if (main) return main.tagName?.toLowerCase() || null;
    // fallback: check for presence of common tags
    if (el.querySelector('circle')) return 'circle';
    if (el.querySelector('rect')) return 'rect';
    if (el.querySelector('path')) return 'path';
    return null;
}

export async function loadData(canvas, svgFile) {
    try {
        const text = await svgFile.text();

        const parser = new DOMParser();
        const svgDoc = parser.parseFromString(text, 'image/svg+xml');
        const svgElement = svgDoc.documentElement;

        const srcCanvasContainer = svgElement.querySelector('#canvas') || svgElement;
        const canvasContainerOffset = getEffectiveTranslate(srcCanvasContainer);

        const sourceElements = Array.from(srcCanvasContainer.children || []);

        const shapeMap = canvas[CanvasSmbl] && canvas[CanvasSmbl].shapeMap;
        if (!shapeMap) {
            console.error('canvas[CanvasSmbl].shapeMap not found');
            return;
        }

        const mapKeys = Object.keys(shapeMap);

        // Найдём ключ для стрелок (проверкой create с s/e данными)
        let arrowKey = null;
        for (const k of mapKeys) {
            try {
                const testData = {
                    s: { data: { dir: 'right', position: { x: 0, y: 0 } } },
                    e: { data: { dir: 'right', position: { x: 10, y: 0 } } }
                };
                const proto = shapeMap[k].create(testData);
                // если create вернул элемент и в нём есть path или g[data-key="start"]
                if (proto && (proto.querySelector && (proto.querySelector('path') || proto.querySelector('[data-key="start"]')))) {
                    arrowKey = k;
                    proto.remove && proto.remove();
                    break;
                }
                proto.remove && proto.remove();
            } catch (err) {
                // ignore
            }
        }
        // fallback обычно '0'
        if (arrowKey == null) arrowKey = mapKeys.find(mk => String(mk) === '0') || null;

        // Сопоставление kind(tag) -> key: создаём один proto на ключ и смотрим main tag
        const keyByTag = {};
        for (const k of mapKeys) {
            try {
                const proto = shapeMap[k].create({ type: k, position: { x: 0, y: 0 }, title: 'T' });
                const tag = detectMainTag(proto);
                if (tag) {
                    if (!keyByTag[tag]) keyByTag[tag] = k;
                }
                proto.remove && proto.remove();
            } catch (e) {
                // ignore
            }
        }

        const createdShapes = [];

        // 1) создаём фигуры (non-path)
        for (const node of sourceElements) {
            if (!(node instanceof Element)) continue;
            const looksLikePath = node.classList.contains('shpath') || !!node.querySelector('path.path') || !!node.querySelector('path[data-key="path"]');
            if (looksLikePath) continue;

            const groupPos = getEffectiveTranslate(node); // visible transform of group
            const absPos = { x: (groupPos.x || 0) + (canvasContainerOffset.x || 0), y: (groupPos.y || 0) + (canvasContainerOffset.y || 0) };

            const tag = detectMainTag(node) || 'unknown';
            const key = keyByTag[tag] || null;

            if (!key) {
                // fallback: просто клонируем — визуал будет, но интерактивность может отсутствовать
                try {
                    const clone = node.cloneNode(true);
                    canvas.append(clone);
                } catch (e) {
                    console.error('clone failed', e);
                }
                continue;
            }

            const title = node.querySelector('text')?.textContent || 'Title';
            const shapeData = { type: key, position: { x: absPos.x, y: absPos.y }, title };

            try {
                const shapeEl = shapeMap[key].create(shapeData);
                // apply visible transform (absolute)
                shapeEl.setAttribute && shapeEl.setAttribute('transform', `translate(${absPos.x},${absPos.y})`);
                canvas.append(shapeEl);
                shapeEl.dispatchEvent && shapeEl.dispatchEvent(new PointerEvent('pointerdown', { bubbles: true }));

                // collect connectors absolute positions from source node
                const connectors = {};
                const connNodes = Array.from(node.querySelectorAll('circle[data-connect]') || []);
                connNodes.forEach(cn => {
                    const connName = cn.getAttribute('data-connect') || cn.getAttribute('data-key') || 'conn';
                    const connTr = getEffectiveTranslate(cn);
                    // connector absolute = canvasContainerOffset + groupPos + connTr
                    const cpos = {
                        x: (canvasContainerOffset.x || 0) + (groupPos.x || 0) + (connTr.x || 0),
                        y: (canvasContainerOffset.y || 0) + (groupPos.y || 0) + (connTr.y || 0)
                    };
                    connectors[connName] = cpos;
                });

                createdShapes.push({ key, el: shapeEl, tag, absPos, connectors });
            } catch (e) {
                console.error('create shape failed', e);
            }
        }

        // 2) создаём стрелки точно как в _shapeCreate: формируем s/e с data.position и вызываем create
for (const node of sourceElements) {
    if (!(node instanceof Element)) continue;
    const looksLikePath = node.classList.contains('shpath') || !!node.querySelector('path.path') || !!node.querySelector('path[data-key="path"]');
    if (!looksLikePath) continue;

    let sPos = { x: 0, y: 0 }, ePos = { x: 0, y: 0 };

    const startG = node.querySelector('[data-key="start"]');
    const endG = node.querySelector('[data-key="end"]');

    if (startG) {
        const p = getEffectiveTranslate(startG);
        sPos.x = (p.x || 0) + (canvasContainerOffset.x || 0);
        sPos.y = (p.y || 0) + (canvasContainerOffset.y || 0);
    }
    if (endG) {
        const p = getEffectiveTranslate(endG);
        ePos.x = (p.x || 0) + (canvasContainerOffset.x || 0);
        ePos.y = (p.y || 0) + (canvasContainerOffset.y || 0);
    }

    if ((sPos.x === 0 && sPos.y === 0) || (ePos.x === 0 && ePos.y === 0)) {
        const pathEl = node.querySelector('path[data-key="path"]') || node.querySelector('path');
        if (pathEl) {
            const coords = extractCoordsFromPathD(pathEl.getAttribute('d'));
            sPos.x = coords.start?.x || sPos.x;
            sPos.y = coords.start?.y || sPos.y;
            ePos.x = coords.end?.x || ePos.x;
            ePos.y = coords.end?.y || ePos.y;
        }
    }

    // Найти реальные shape и connector для s/e
    const findConnector = (pos) => {
        let best = null;
        let minDist = Infinity;
        for (const sh of createdShapes) {
            for (const key in sh.connectors) {
                const c = sh.connectors[key];
                const dx = c.x - pos.x;
                const dy = c.y - pos.y;
                const dist = dx*dx + dy*dy;
                if (dist < minDist) {
                    minDist = dist;
                    best = { shapeEl: sh.el, connectorKey: key };
                }
            }
        }
        return best;
    }

    const sShape = findConnector(sPos);
    const eShape = findConnector(ePos);

    const shapeData = {
        s: sShape ? { shape: sShape, data: { dir:'right', position: {...sPos} } } : { data: { dir:'right', position: {...sPos} } },
        e: eShape ? { shape: eShape, data: { dir:'right', position: {...ePos} } } : { data: { dir:'right', position: {...ePos} } }
    };

    const shapeEl = arrowKey != null ? shapeMap[arrowKey].create(shapeData) : node.cloneNode(true);
    canvas.append(shapeEl);
    shapeEl.dispatchEvent && shapeEl.dispatchEvent(new PointerEvent('pointerdown', { bubbles: true }));
}


        console.log('loadData finished. shapes created:', createdShapes.length);
    } catch (e) {
        console.error('Ошибка при загрузке SVG', e);
    }
}




const alertCantOpen = () => alert('File cannot be read. Use the exact image file you got from the application.');
const alertEmpty = () => alert('Diagram is empty');

/** @typedef { {x:number, y:number} } Point */
/** @typedef { import('../infrastructure/canvas-smbl.js').CanvasElement } CanvasElement */
