/**
 * Редактор габаритов (ITU Fig. 38).
 * Корма — L, правый борт — W (доли A/L и C/W фиксируются на время жеста); точка GPS — перетаскивание.
 * Для роста L/W координаты могут выходить за контур корпуса (опорный масштаб wPxRef/hPxRef с pointerdown).
 */
(function () {
    'use strict';

    var NS = 'http://www.w3.org/2000/svg';

    var MIN_LEN = 20;
    var MIN_BEAM = 6;
    var MAX_AB = 511;
    var MAX_CD = 63;
    var MAX_L = MAX_AB + MAX_AB;
    var MAX_W = MAX_CD + MAX_CD;

    /** Макс. размер корпуса в пикселях (пропорции сохраняются) */
    var MAX_DRAW_W = 175;
    var MAX_DRAW_H = 210;
    /** Минимум по меньшей стороне корпуса в px — иначе ручки и клампы «схлопываются» */
    var MIN_HULL_PX = 48;

    var PAD_L = 12;
    var PAD_T = 48;
    var PAD_R = 78;
    var PAD_B = 42;

    var svg, inner, hull, marker, handles;
    var gridH, gridV, lblBow, lblStern, dimBeam, dimLength;
    var drag = null;

    /** Текущая геометрия (обновляется в refresh) */
    var layout = {
        wPx: 100,
        hPx: 160,
        dispL: MIN_LEN,
        dispW: MIN_BEAM,
    };

    function clamp(n, lo, hi) {
        return Math.max(lo, Math.min(hi, n));
    }

    function el(name, attrs) {
        var e = document.createElementNS(NS, name);
        if (attrs) {
            Object.keys(attrs).forEach(function (k) {
                e.setAttribute(k, attrs[k]);
            });
        }
        return e;
    }

    function readDims() {
        var A = parseInt(document.getElementById('tp-to-bow').value, 10) || 0;
        var B = parseInt(document.getElementById('tp-to-stern').value, 10) || 0;
        var C = parseInt(document.getElementById('tp-to-port').value, 10) || 0;
        var D = parseInt(document.getElementById('tp-to-starboard').value, 10) || 0;
        A = clamp(A, 0, MAX_AB);
        B = clamp(B, 0, MAX_AB);
        C = clamp(C, 0, MAX_CD);
        D = clamp(D, 0, MAX_CD);
        return { A: A, B: B, C: C, D: D, L: A + B, W: C + D };
    }

    function writeDims(A, B, C, D) {
        A = clamp(Math.round(A), 0, MAX_AB);
        B = clamp(Math.round(B), 0, MAX_AB);
        C = clamp(Math.round(C), 0, MAX_CD);
        D = clamp(Math.round(D), 0, MAX_CD);
        document.getElementById('tp-to-bow').value = A;
        document.getElementById('tp-to-stern').value = B;
        document.getElementById('tp-to-port').value = C;
        document.getElementById('tp-to-starboard').value = D;
    }

    function displayLW(d) {
        var L = d.L > 0 ? d.L : MIN_LEN;
        var W = d.W > 0 ? d.W : MIN_BEAM;
        return { L: L, W: W, template: d.L === 0 && d.W === 0 };
    }

    function hullPath(w, h) {
        var bow = Math.min(20, h * 0.11);
        var tipX = w / 2;
        return (
            'M ' + tipX + ',0 L ' + w + ',' + bow + ' L ' + w + ',' + h + ' L 0,' + h + ' L 0,' + bow + ' Z'
        );
    }

    function computeLayout(d, disp) {
        var scale = Math.min(MAX_DRAW_W / disp.W, MAX_DRAW_H / disp.L);
        if (!isFinite(scale) || scale <= 0) scale = 1;
        var wPx0 = disp.W * scale;
        var hPx0 = disp.L * scale;
        var bump = 1;
        if (wPx0 < MIN_HULL_PX) bump = Math.max(bump, MIN_HULL_PX / Math.max(wPx0, 1e-6));
        if (hPx0 < MIN_HULL_PX) bump = Math.max(bump, MIN_HULL_PX / Math.max(hPx0, 1e-6));
        scale *= bump;
        var wPx = disp.W * scale;
        var hPx = disp.L * scale;
        layout.wPx = wPx;
        layout.hPx = hPx;
        layout.dispL = disp.L;
        layout.dispW = disp.W;
        layout.scale = scale;
        return { sx: scale, sy: scale, wPx: wPx, hPx: hPx };
    }

    function scales(d, disp, geo) {
        var wPx = geo.wPx;
        var hPx = geo.hPx;
        var padX = Math.max(1, Math.min(8, wPx * 0.1));
        var padY = Math.max(1, Math.min(8, hPx * 0.1));
        var aVis = d.L > 0 ? d.A : disp.L / 2;
        var cVis = d.W > 0 ? d.C : disp.W / 2;
        var mx = clamp(cVis * geo.sx, padX, wPx - padX);
        var my = clamp(aVis * geo.sy, padY, hPx - padY);
        return { mx: mx, my: my };
    }

    function ensureNonZeroDims() {
        var d = readDims();
        if (d.L === 0 && d.W === 0) {
            writeDims(MIN_LEN / 2, MIN_LEN / 2, MIN_BEAM / 2, MIN_BEAM / 2);
        }
    }

    function clearG(g) {
        while (g.firstChild) g.removeChild(g.firstChild);
    }

    function rebuildBeamDimension(g, wPx, hPx, Wm) {
        clearG(g);
        var bow = Math.min(20, hPx * 0.11);
        var off = 24;
        var y = -off;
        var yPast = y - 1.5;
        g.appendChild(
            el('line', { class: 'ship-dim-ext', x1: 0, y1: bow, x2: 0, y2: yPast })
        );
        g.appendChild(
            el('line', { class: 'ship-dim-ext', x1: wPx, y1: bow, x2: wPx, y2: yPast })
        );
        g.appendChild(
            el('line', {
                class: 'ship-dim-main',
                x1: 0,
                y1: y,
                x2: wPx,
                y2: y,
                'marker-start': 'url(#ship-dim-arrow)',
                'marker-end': 'url(#ship-dim-arrow)',
            })
        );
        var t = el('text', {
            class: 'ship-dim-txt',
            x: wPx / 2,
            y: y - 8,
            'text-anchor': 'middle',
        });
        t.textContent = 'W = ' + Wm + ' м';
        g.appendChild(t);
    }

    function rebuildLengthDimension(g, wPx, hPx, Lm) {
        clearG(g);
        var bow = Math.min(20, hPx * 0.11);
        var off = 22;
        var x = wPx + off;
        var xPast = x + 1.5;
        g.appendChild(
            el('line', { class: 'ship-dim-ext', x1: wPx, y1: bow, x2: x, y2: bow })
        );
        g.appendChild(
            el('line', { class: 'ship-dim-ext', x1: x, y1: bow, x2: x, y2: 0 })
        );
        g.appendChild(
            el('line', { class: 'ship-dim-ext', x1: wPx, y1: hPx, x2: xPast, y2: hPx })
        );
        g.appendChild(
            el('line', {
                class: 'ship-dim-main',
                x1: x,
                y1: 0,
                x2: x,
                y2: hPx,
                'marker-start': 'url(#ship-dim-arrow)',
                'marker-end': 'url(#ship-dim-arrow)',
            })
        );
        var t = el('text', {
            class: 'ship-dim-txt',
            x: x + 14,
            y: hPx / 2,
            'text-anchor': 'middle',
            transform: 'rotate(-90 ' + (x + 14) + ' ' + hPx / 2 + ')',
        });
        t.textContent = 'L = ' + Lm + ' м';
        g.appendChild(t);
    }

    function positionHandles(wPx, hPx) {
        if (!handles) return;
        var stern = handles.querySelector('[data-ship-edge="stern"]');
        var sb = handles.querySelector('[data-ship-edge="starboard"]');
        if (stern) stern.setAttribute('transform', 'translate(' + wPx / 2 + ',' + hPx + ')');
        if (sb) sb.setAttribute('transform', 'translate(' + wPx + ',' + hPx / 2 + ')');
    }

    function refreshFromInputs() {
        if (!svg || !inner || !hull || !marker) return;
        var d = readDims();
        var disp = displayLW(d);
        var geo = computeLayout(d, disp);
        var sc = scales(d, disp, geo);
        var wPx = geo.wPx;
        var hPx = geo.hPx;

        inner.setAttribute('transform', 'translate(' + PAD_L + ',' + PAD_T + ')');

        var vbW = PAD_L + wPx + PAD_R;
        var vbH = PAD_T + hPx + PAD_B;
        svg.setAttribute('viewBox', '0 0 ' + vbW + ' ' + vbH);

        rebuildBeamDimension(dimBeam, wPx, hPx, disp.W);
        rebuildLengthDimension(dimLength, wPx, hPx, disp.L);

        hull.setAttribute('d', hullPath(wPx, hPx));

        if (gridH && gridV) {
            gridH.setAttribute('x1', 0);
            gridH.setAttribute('y1', sc.my);
            gridH.setAttribute('x2', wPx);
            gridH.setAttribute('y2', sc.my);
            gridV.setAttribute('x1', sc.mx);
            gridV.setAttribute('y1', 0);
            gridV.setAttribute('x2', sc.mx);
            gridV.setAttribute('y2', hPx);
        }

        if (lblBow) {
            lblBow.setAttribute('x', wPx / 2);
            lblBow.setAttribute('y', -38);
        }
        if (lblStern) {
            lblStern.setAttribute('x', wPx / 2);
            lblStern.setAttribute('y', hPx + 22);
        }

        marker.setAttribute('transform', 'translate(' + sc.mx + ',' + sc.my + ')');
        marker.setAttribute('class', 'ship-gps-group' + (disp.template ? ' ship-gps-group--template' : ''));

        positionHandles(wPx, hPx);
    }

    function svgPointFromClient(clientX, clientY) {
        var pt = svg.createSVGPoint();
        pt.x = clientX;
        pt.y = clientY;
        var ctm = inner.getScreenCTM();
        if (!ctm) return null;
        var p = pt.matrixTransform(ctm.inverse());
        return { x: p.x, y: p.y };
    }

    function splitLength(u, Ls) {
        u = clamp(u, 0, 1);
        var A = Math.round(u * Ls);
        A = clamp(A, 0, MAX_AB);
        var B = Ls - A;
        if (B > MAX_AB) {
            B = MAX_AB;
            A = clamp(Ls - B, 0, MAX_AB);
        }
        if (B < 0) {
            B = 0;
            A = clamp(Ls, 0, MAX_AB);
        }
        return { A: A, B: B };
    }

    function splitBeam(v, Ws) {
        v = clamp(v, 0, 1);
        var C = Math.round(v * Ws);
        C = clamp(C, 0, MAX_CD);
        var D = Ws - C;
        if (D > MAX_CD) {
            D = MAX_CD;
            C = clamp(Ws - D, 0, MAX_CD);
        }
        if (D < 0) {
            D = 0;
            C = clamp(Ws, 0, MAX_CD);
        }
        return { C: C, D: D };
    }

    /** Новая длина L; сохраняем долю носа A/L ≈ rA. */
    function abFromLength(Ln, rA) {
        Ln = clamp(Math.round(Ln), 1, MAX_L);
        var r = clamp(isFinite(rA) ? rA : 0.5, 0, 1);
        var A = Math.round(r * Ln);
        A = clamp(A, 0, MAX_AB);
        var B = Ln - A;
        if (B > MAX_AB) {
            B = MAX_AB;
            A = clamp(Ln - B, 0, MAX_AB);
        }
        if (B < 0) {
            B = 0;
            A = clamp(Ln, 0, MAX_AB);
        }
        return { A: A, B: B };
    }

    /** Новая ширина W; сохраняем долю порта C/W ≈ rC. */
    function cdFromWidth(Wn, rC) {
        Wn = clamp(Math.round(Wn), 1, MAX_W);
        var r = clamp(isFinite(rC) ? rC : 0.5, 0, 1);
        var C = Math.round(r * Wn);
        C = clamp(C, 0, MAX_CD);
        var D = Wn - C;
        if (D > MAX_CD) {
            D = MAX_CD;
            C = clamp(Wn - D, 0, MAX_CD);
        }
        if (D < 0) {
            D = 0;
            C = clamp(Wn, 0, MAX_CD);
        }
        return { C: C, D: D };
    }

    function startDrag(ev, kind, captureEl) {
        ev.preventDefault();
        captureEl.setPointerCapture(ev.pointerId);
        document.body.classList.add('ship-editor-dragging');
        document.addEventListener('pointermove', onDocumentPointerMove);
        document.addEventListener('pointerup', onDocumentPointerEnd);
        document.addEventListener('pointercancel', onDocumentPointerEnd);
        return { kind: kind, pid: ev.pointerId, el: captureEl };
    }

    function stopDragListeners() {
        document.removeEventListener('pointermove', onDocumentPointerMove);
        document.removeEventListener('pointerup', onDocumentPointerEnd);
        document.removeEventListener('pointercancel', onDocumentPointerEnd);
    }

    function onInnerPointerDown(ev) {
        if (!inner) return;
        var edgeG = ev.target.closest ? ev.target.closest('[data-ship-edge]') : null;
        if (edgeG) {
            ensureNonZeroDims();
            var d0 = readDims();
            var disp0 = displayLW(d0);
            var geo0 = computeLayout(d0, disp0);
            var kind = edgeG.getAttribute('data-ship-edge');
            drag = startDrag(ev, kind, edgeG);
            drag.L0 = d0.L;
            drag.W0 = d0.W;
            drag.rA = d0.L > 0 ? d0.A / d0.L : 0.5;
            drag.rC = d0.W > 0 ? d0.C / d0.W : 0.5;
            drag.wPxRef = geo0.wPx;
            drag.hPxRef = geo0.hPx;
            return;
        }
        if (marker && marker.contains(ev.target)) {
            ensureNonZeroDims();
            var dg = readDims();
            var Ls = dg.L > 0 ? Math.min(dg.L, MAX_L) : MIN_LEN;
            var Ws = dg.W > 0 ? Math.min(dg.W, MAX_W) : MIN_BEAM;
            Ls = clamp(Ls, 1, MAX_L);
            Ws = clamp(Ws, 1, MAX_W);
            drag = startDrag(ev, 'gps', marker);
            drag.Ls = Ls;
            drag.Ws = Ws;
        }
    }

    function onDocumentPointerMove(ev) {
        if (!drag || ev.pointerId !== drag.pid) return;
        var p = svgPointFromClient(ev.clientX, ev.clientY);
        if (!p) return;

        var d = readDims();
        var disp = displayLW(d);
        var geo = computeLayout(d, disp);
        var wPx = geo.wPx;
        var hPx = geo.hPx;

        if (drag.kind === 'gps') {
            var u = p.y / hPx;
            var v = p.x / wPx;
            var ab = splitLength(u, drag.Ls);
            var cd = splitBeam(v, drag.Ws);
            writeDims(ab.A, ab.B, cd.C, cd.D);
            refreshFromInputs();
            return;
        }

        var wRef = drag.wPxRef;
        var hRef = drag.hPxRef;
        if (drag.kind === 'stern' && wRef > 0 && hRef > 0) {
            var yMin = (hRef * 1) / Math.max(drag.L0, 1);
            var yMax = (hRef * MAX_L) / Math.max(drag.L0, 1);
            var yS = clamp(p.y, yMin, yMax);
            var L1 = Math.round((drag.L0 * yS) / hRef);
            L1 = clamp(L1, 1, MAX_L);
            var abS = abFromLength(L1, drag.rA);
            writeDims(abS.A, abS.B, d.C, d.D);
        } else if (drag.kind === 'starboard' && wRef > 0 && hRef > 0) {
            var xMin = (wRef * 1) / Math.max(drag.W0, 1);
            var xMax = (wRef * MAX_W) / Math.max(drag.W0, 1);
            var xSb = clamp(p.x, xMin, xMax);
            var W1s = Math.round((drag.W0 * xSb) / wRef);
            W1s = clamp(W1s, 1, MAX_W);
            var cd2 = cdFromWidth(W1s, drag.rC);
            writeDims(d.A, d.B, cd2.C, cd2.D);
        }

        refreshFromInputs();
    }

    function onDocumentPointerEnd(ev) {
        if (!drag || ev.pointerId !== drag.pid) return;
        stopDragListeners();
        try {
            drag.el.releasePointerCapture(ev.pointerId);
        } catch (e) { /* ignore */ }
        drag = null;
        document.body.classList.remove('ship-editor-dragging');
    }

    function bindInputs() {
        ['tp-to-bow', 'tp-to-stern', 'tp-to-port', 'tp-to-starboard'].forEach(function (id) {
            var eln = document.getElementById(id);
            if (eln) {
                eln.addEventListener('input', refreshFromInputs);
                eln.addEventListener('change', refreshFromInputs);
            }
        });
    }

    function boot() {
        svg = document.getElementById('ship-editor-svg');
        inner = document.getElementById('ship-editor-inner');
        hull = document.getElementById('ship-hull');
        marker = document.getElementById('ship-gps-marker');
        handles = document.getElementById('ship-edge-handles');
        gridH = document.getElementById('ship-grid-h');
        gridV = document.getElementById('ship-grid-v');
        lblBow = document.getElementById('ship-lbl-bow');
        lblStern = document.getElementById('ship-lbl-stern');
        dimBeam = document.getElementById('ship-dim-beam');
        dimLength = document.getElementById('ship-dim-length');
        if (!svg || !inner || !hull || !marker) return;

        inner.addEventListener('pointerdown', onInnerPointerDown);
        bindInputs();
        refreshFromInputs();
    }

    window.shipDimsEditorRefresh = refreshFromInputs;

    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', boot);
    } else {
        boot();
    }
})();
