/**
 * 推薦技師相片：選圖 → 剪裁（拖曳／縮放）→ 馬賽克塗抹 → 輸出 JPEG。
 * fateInitMasseurPhotoEditor({ cropAspect: 'square'|'portrait', ... })
 */
(function (global) {
    'use strict';

    function parseAspect(name) {
        if (name === 'square') {
            return { w: 1, h: 1, exportMax: 512 };
        }
        return { w: 3, h: 4, exportMax: 600 };
    }

    function initMasseurPhotoEditor(opts) {
        var fileInput = document.getElementById(opts.fileId);
        var panel = document.getElementById(opts.panelId);
        var cropStage = opts.cropStageId ? document.getElementById(opts.cropStageId) : null;
        var editStage = opts.editStageId ? document.getElementById(opts.editStageId) : null;
        var cropCanvas = opts.cropCanvasId ? document.getElementById(opts.cropCanvasId) : null;
        var canvas = document.getElementById(opts.canvasId);
        var hidden = document.getElementById(opts.hiddenId);
        var cropZoomInput = opts.cropZoomId ? document.getElementById(opts.cropZoomId) : null;
        var btnCropApply = opts.cropApplyId ? document.getElementById(opts.cropApplyId) : null;
        var brushInput = opts.brushId ? document.getElementById(opts.brushId) : null;
        var btnApply = opts.applyId ? document.getElementById(opts.applyId) : null;
        var btnReset = opts.resetId ? document.getElementById(opts.resetId) : null;
        var btnRecrop = opts.recropId ? document.getElementById(opts.recropId) : null;
        var btnCancel = opts.cancelId ? document.getElementById(opts.cancelId) : null;
        var btnCancelEdit = opts.cancelEditId ? document.getElementById(opts.cancelEditId) : null;
        var preview = opts.previewId ? document.getElementById(opts.previewId) : null;
        var previewWrap = opts.previewWrapId ? document.getElementById(opts.previewWrapId) : null;
        var hint = opts.hintId ? document.getElementById(opts.hintId) : null;

        if (!fileInput || !panel || !canvas || !hidden) {
            return null;
        }

        var aspect = parseAspect(opts.cropAspect || 'portrait');
        var cropEnabled = !!(cropStage && editStage && cropCanvas && btnCropApply);
        var VIEW_W = 280;
        var VIEW_H = Math.round(VIEW_W * aspect.h / aspect.w);
        var MIN_ZOOM = 1;
        var MAX_ZOOM = 3;
        var MAX_EDIT_W = 600;
        var MAX_EDIT_H = 760;

        var ctx = canvas.getContext('2d', { willReadFrequently: true });
        var cropCtx = cropEnabled ? cropCanvas.getContext('2d') : null;
        var sourceImage = null;
        var baseImage = null;
        var objectUrl = null;
        var painting = false;
        var mode = 'idle';

        var cropState = {
            zoom: 1,
            panX: 0,
            panY: 0,
            dragging: false,
            lastX: 0,
            lastY: 0,
        };

        var applyMsg = opts.applyMessage || '相片已套用，送出表單即可。';
        var cropHint = opts.cropHint || '拖曳調整位置、滑桿縮放，完成後按「完成剪裁」。';
        var pickHint = opts.pickHint || '在臉部來回塗抹即可打上馬賽克遮蔽五官；完成後按「套用相片」。';

        if (cropEnabled) {
            cropCanvas.width = VIEW_W;
            cropCanvas.height = VIEW_H;
        }

        function setHint(text) {
            if (hint) {
                hint.textContent = text || '';
            }
        }

        function clearObjectUrl() {
            if (objectUrl) {
                URL.revokeObjectURL(objectUrl);
                objectUrl = null;
            }
        }

        function showStage(name) {
            if (!cropEnabled) {
                panel.hidden = name === 'idle';
                return;
            }
            panel.hidden = name === 'idle';
            cropStage.hidden = name !== 'crop';
            editStage.hidden = name !== 'edit';
            mode = name;
        }

        function resetCropState() {
            cropState.zoom = 1;
            cropState.panX = 0;
            cropState.panY = 0;
            cropState.dragging = false;
            if (cropZoomInput) {
                cropZoomInput.value = '1';
                cropZoomInput.min = String(MIN_ZOOM);
                cropZoomInput.max = String(MAX_ZOOM);
                cropZoomInput.step = '0.02';
            }
        }

        function hideCustomPreview() {
            if (preview) {
                preview.removeAttribute('src');
            }
            if (previewWrap) {
                previewWrap.hidden = true;
            } else if (preview) {
                preview.hidden = true;
            }
        }

        function showCustomPreview(dataUrl) {
            if (!preview || !dataUrl) {
                return;
            }
            preview.src = dataUrl;
            if (previewWrap) {
                previewWrap.hidden = false;
            } else {
                preview.hidden = false;
            }
        }

        function reset() {
            clearObjectUrl();
            sourceImage = null;
            baseImage = null;
            hidden.value = '';
            resetCropState();
            showStage('idle');
            hideCustomPreview();
            setHint('');
        }

        function cropBaseScale() {
            if (!sourceImage) {
                return 1;
            }
            return Math.max(VIEW_W / sourceImage.width, VIEW_H / sourceImage.height);
        }

        function clampCropPan() {
            if (!sourceImage) {
                return;
            }
            var s = cropBaseScale() * cropState.zoom;
            var dw = sourceImage.width * s;
            var dh = sourceImage.height * s;
            var maxX = Math.max(0, (dw - VIEW_W) / 2);
            var maxY = Math.max(0, (dh - VIEW_H) / 2);
            cropState.panX = Math.max(-maxX, Math.min(maxX, cropState.panX));
            cropState.panY = Math.max(-maxY, Math.min(maxY, cropState.panY));
        }

        function drawCrop() {
            if (!cropEnabled || !cropCtx || !sourceImage) {
                return;
            }
            cropCtx.clearRect(0, 0, VIEW_W, VIEW_H);
            var s = cropBaseScale() * cropState.zoom;
            var dw = sourceImage.width * s;
            var dh = sourceImage.height * s;
            var x = (VIEW_W - dw) / 2 + cropState.panX;
            var y = (VIEW_H - dh) / 2 + cropState.panY;
            cropCtx.fillStyle = '#13161d';
            cropCtx.fillRect(0, 0, VIEW_W, VIEW_H);
            cropCtx.drawImage(sourceImage, x, y, dw, dh);

            if (aspect.w === aspect.h) {
                cropCtx.save();
                cropCtx.fillStyle = 'rgba(0,0,0,0.45)';
                cropCtx.beginPath();
                cropCtx.rect(0, 0, VIEW_W, VIEW_H);
                cropCtx.arc(VIEW_W / 2, VIEW_H / 2, VIEW_W / 2, 0, Math.PI * 2);
                cropCtx.fill('evenodd');
                cropCtx.strokeStyle = 'rgba(255,255,255,0.85)';
                cropCtx.lineWidth = 2;
                cropCtx.beginPath();
                cropCtx.arc(VIEW_W / 2, VIEW_H / 2, VIEW_W / 2 - 1, 0, Math.PI * 2);
                cropCtx.stroke();
                cropCtx.restore();
            } else {
                cropCtx.strokeStyle = 'rgba(255,255,255,0.85)';
                cropCtx.lineWidth = 2;
                cropCtx.strokeRect(1, 1, VIEW_W - 2, VIEW_H - 2);
            }
        }

        function exportCropDataUrl() {
            if (!sourceImage) {
                return '';
            }
            var exportW = aspect.w === aspect.h ? aspect.exportMax : Math.round(aspect.exportMax * aspect.w / aspect.h);
            var exportH = aspect.w === aspect.h ? aspect.exportMax : aspect.exportMax;
            var out = document.createElement('canvas');
            out.width = exportW;
            out.height = exportH;
            var octx = out.getContext('2d');
            if (!octx) {
                return '';
            }
            var ratio = exportW / VIEW_W;
            var s = cropBaseScale() * cropState.zoom * ratio;
            var dw = sourceImage.width * s;
            var dh = sourceImage.height * s;
            var x = (exportW - dw) / 2 + cropState.panX * ratio;
            var y = (exportH - dh) / 2 + cropState.panY * ratio;
            octx.fillStyle = '#13161d';
            octx.fillRect(0, 0, exportW, exportH);
            octx.drawImage(sourceImage, x, y, dw, dh);
            try {
                return out.toDataURL('image/jpeg', 0.88);
            } catch (e) {
                return '';
            }
        }

        function dataUrlToImage(dataUrl, onLoad, onError) {
            var img = new Image();
            img.onload = function () {
                onLoad(img);
            };
            img.onerror = function () {
                if (onError) {
                    onError();
                }
            };
            img.src = dataUrl;
        }

        function drawBase(img) {
            var scale = Math.min(1, MAX_EDIT_W / img.width, MAX_EDIT_H / img.height);
            canvas.width = Math.max(1, Math.round(img.width * scale));
            canvas.height = Math.max(1, Math.round(img.height * scale));
            ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
        }

        function beginWithSource(img, hintText) {
            sourceImage = img;
            baseImage = null;
            hidden.value = '';
            hideCustomPreview();
            if (cropEnabled) {
                resetCropState();
                drawCrop();
                showStage('crop');
                setHint(hintText || cropHint);
            } else {
                baseImage = img;
                drawBase(img);
                showStage('edit');
                setHint(hintText || pickHint);
            }
        }

        function enterEditStage(croppedImg) {
            baseImage = croppedImg;
            drawBase(croppedImg);
            showStage('edit');
            setHint(pickHint);
        }

        function finishCrop() {
            var data = exportCropDataUrl();
            if (!data) {
                window.alert('無法產生剪裁圖，請再試一次。');
                return;
            }
            dataUrlToImage(data, enterEditStage, function () {
                window.alert('無法載入剪裁結果，請再試一次。');
            });
        }

        function loadFromUrl(url, hintText) {
            var src = (url || '').trim();
            if (!src) {
                return false;
            }
            clearObjectUrl();
            fileInput.value = '';
            hidden.value = '';
            var img = new Image();
            img.onload = function () {
                beginWithSource(img, hintText || (cropEnabled ? cropHint : pickHint));
            };
            img.onerror = function () {
                window.alert('無法載入圖片，請重新選擇檔案上傳。');
            };
            img.src = src + (src.indexOf('?') >= 0 ? '&' : '?') + '_=' + Date.now();
            return true;
        }

        function brushSize() {
            var v = brushInput ? parseInt(brushInput.value, 10) : 36;
            return isNaN(v) ? 36 : Math.max(10, Math.min(120, v));
        }

        function mosaicAt(cx, cy, size) {
            var half = Math.round(size / 2);
            var x0 = Math.max(0, Math.round(cx - half));
            var y0 = Math.max(0, Math.round(cy - half));
            var x1 = Math.min(canvas.width, Math.round(cx + half));
            var y1 = Math.min(canvas.height, Math.round(cy + half));
            var w = x1 - x0;
            var h = y1 - y0;
            if (w <= 0 || h <= 0) {
                return;
            }
            var block = Math.max(6, Math.round(size / 5));
            var imgData;
            try {
                imgData = ctx.getImageData(x0, y0, w, h);
            } catch (e) {
                return;
            }
            var data = imgData.data;
            for (var by = 0; by < h; by += block) {
                for (var bx = 0; bx < w; bx += block) {
                    var r = 0, g = 0, b = 0, cnt = 0;
                    var maxY = Math.min(by + block, h);
                    var maxX = Math.min(bx + block, w);
                    for (var y = by; y < maxY; y++) {
                        for (var x = bx; x < maxX; x++) {
                            var i = (y * w + x) * 4;
                            r += data[i];
                            g += data[i + 1];
                            b += data[i + 2];
                            cnt++;
                        }
                    }
                    if (cnt === 0) {
                        continue;
                    }
                    r = Math.round(r / cnt);
                    g = Math.round(g / cnt);
                    b = Math.round(b / cnt);
                    for (var y2 = by; y2 < maxY; y2++) {
                        for (var x2 = bx; x2 < maxX; x2++) {
                            var j = (y2 * w + x2) * 4;
                            data[j] = r;
                            data[j + 1] = g;
                            data[j + 2] = b;
                        }
                    }
                }
            }
            ctx.putImageData(imgData, x0, y0);
        }

        function toCanvasCoords(clientX, clientY) {
            var rect = canvas.getBoundingClientRect();
            var sx = canvas.width / rect.width;
            var sy = canvas.height / rect.height;
            return { x: (clientX - rect.left) * sx, y: (clientY - rect.top) * sy };
        }

        function paintAt(clientX, clientY) {
            var p = toCanvasCoords(clientX, clientY);
            mosaicAt(p.x, p.y, brushSize());
        }

        function cropPointerDown(clientX, clientY) {
            cropState.dragging = true;
            cropState.lastX = clientX;
            cropState.lastY = clientY;
        }

        function cropPointerMove(clientX, clientY) {
            if (!cropState.dragging) {
                return;
            }
            cropState.panX += clientX - cropState.lastX;
            cropState.panY += clientY - cropState.lastY;
            cropState.lastX = clientX;
            cropState.lastY = clientY;
            clampCropPan();
            drawCrop();
        }

        function cropPointerUp() {
            cropState.dragging = false;
        }

        fileInput.addEventListener('change', function () {
            var file = fileInput.files && fileInput.files[0];
            if (!file) {
                return;
            }
            if (!/^image\/(jpeg|png|webp)$/i.test(file.type)) {
                window.alert('請選擇 JPEG、PNG 或 WebP 圖片。');
                fileInput.value = '';
                return;
            }
            if (file.size > 8 * 1024 * 1024) {
                window.alert('檔案過大，請小於 8MB。');
                fileInput.value = '';
                return;
            }
            clearObjectUrl();
            objectUrl = URL.createObjectURL(file);
            var img = new Image();
            img.onload = function () {
                beginWithSource(img, cropHint);
            };
            img.onerror = function () {
                clearObjectUrl();
                window.alert('無法讀取圖片。');
            };
            img.src = objectUrl;
        });

        if (cropZoomInput) {
            cropZoomInput.addEventListener('input', function () {
                cropState.zoom = parseFloat(cropZoomInput.value, 10) || 1;
                clampCropPan();
                drawCrop();
            });
        }

        if (btnCropApply) {
            btnCropApply.addEventListener('click', finishCrop);
        }

        if (btnRecrop) {
            btnRecrop.addEventListener('click', function () {
                if (!sourceImage) {
                    return;
                }
                resetCropState();
                drawCrop();
                showStage('crop');
                setHint(cropHint);
            });
        }

        if (brushInput) {
            brushInput.addEventListener('input', function () {
                setHint('筆刷大小：' + brushSize() + ' px');
            });
        }

        if (cropEnabled && cropCanvas) {
            cropCanvas.addEventListener('mousedown', function (e) {
                if (mode !== 'crop') {
                    return;
                }
                e.preventDefault();
                cropPointerDown(e.clientX, e.clientY);
            });
            window.addEventListener('mousemove', function (e) {
                if (mode === 'crop') {
                    cropPointerMove(e.clientX, e.clientY);
                }
            });
            window.addEventListener('mouseup', cropPointerUp);
            cropCanvas.addEventListener('touchstart', function (e) {
                if (mode !== 'crop' || e.touches.length !== 1) {
                    return;
                }
                e.preventDefault();
                cropPointerDown(e.touches[0].clientX, e.touches[0].clientY);
            }, { passive: false });
            cropCanvas.addEventListener('touchmove', function (e) {
                if (mode !== 'crop' || e.touches.length !== 1) {
                    return;
                }
                e.preventDefault();
                cropPointerMove(e.touches[0].clientX, e.touches[0].clientY);
            }, { passive: false });
            cropCanvas.addEventListener('touchend', cropPointerUp);
        }

        canvas.addEventListener('mousedown', function (e) {
            if (mode !== 'edit') {
                return;
            }
            e.preventDefault();
            painting = true;
            paintAt(e.clientX, e.clientY);
        });
        window.addEventListener('mousemove', function (e) {
            if (painting && mode === 'edit') {
                paintAt(e.clientX, e.clientY);
            }
        });
        window.addEventListener('mouseup', function () {
            painting = false;
        });
        canvas.addEventListener('touchstart', function (e) {
            if (mode !== 'edit' || e.touches.length !== 1) {
                return;
            }
            e.preventDefault();
            painting = true;
            paintAt(e.touches[0].clientX, e.touches[0].clientY);
        }, { passive: false });
        canvas.addEventListener('touchmove', function (e) {
            if (mode !== 'edit' || !painting || e.touches.length !== 1) {
                return;
            }
            e.preventDefault();
            paintAt(e.touches[0].clientX, e.touches[0].clientY);
        }, { passive: false });
        canvas.addEventListener('touchend', function () {
            painting = false;
        });

        if (btnReset) {
            btnReset.addEventListener('click', function () {
                if (baseImage) {
                    drawBase(baseImage);
                    setHint('已還原剪裁後原圖。');
                }
            });
        }

        if (btnApply) {
            btnApply.addEventListener('click', function () {
                if (!baseImage) {
                    return;
                }
                var data = '';
                try {
                    data = canvas.toDataURL('image/jpeg', 0.82);
                } catch (e) {
                    data = '';
                }
                if (!data) {
                    window.alert('無法產生相片，請再試一次。');
                    return;
                }
                hidden.value = data;
                showCustomPreview(data);
                showStage('idle');
                panel.hidden = true;
                setHint(applyMsg);
            });
        }

        if (btnCancel) {
            btnCancel.addEventListener('click', function () {
                fileInput.value = '';
                reset();
            });
        }

        if (btnCancelEdit) {
            btnCancelEdit.addEventListener('click', function () {
                fileInput.value = '';
                reset();
            });
        }

        if (opts.editExistingId) {
            var btnEditExisting = document.getElementById(opts.editExistingId);
            if (btnEditExisting) {
                btnEditExisting.addEventListener('click', function () {
                    var url = btnEditExisting.getAttribute('data-src') || opts.existingUrl || '';
                    if (!loadFromUrl(url, cropEnabled ? cropHint : '已載入目前預設，可繼續塗抹；完成後按「套用相片」。')) {
                        window.alert('目前沒有可編輯的預設圖，請先選擇新圖片上傳。');
                    }
                });
            }
        }

        return {
            loadFromUrl: loadFromUrl,
            reset: reset,
            getDataUrl: function () {
                return hidden.value || '';
            },
            setExistingUrl: function (url) {
                if (opts.editExistingId) {
                    var btn = document.getElementById(opts.editExistingId);
                    if (btn) {
                        if (url) {
                            btn.setAttribute('data-src', url);
                            btn.hidden = false;
                        } else {
                            btn.removeAttribute('data-src');
                            btn.hidden = true;
                        }
                    }
                }
            },
        };
    }

    global.fateInitMasseurPhotoEditor = initMasseurPhotoEditor;

    function initMasseurGenderDefaultPreview(opts) {
        var genderSelect = document.getElementById(opts.genderId);
        var defaultWrap = document.getElementById(opts.wrapId);
        var defaultImg = document.getElementById(opts.defaultImgId);
        var defaultFallback = document.getElementById(opts.defaultFallbackId);
        var customPreview = document.getElementById(opts.customPreviewId);
        var customPreviewWrap = opts.customPreviewWrapId ? document.getElementById(opts.customPreviewWrapId) : null;
        var hidden = document.getElementById(opts.hiddenId);
        var fileInput = opts.fileId ? document.getElementById(opts.fileId) : null;
        var panel = opts.panelId ? document.getElementById(opts.panelId) : null;
        var hint = opts.hintId ? document.getElementById(opts.hintId) : null;
        var defaults = opts.defaults || {};
        var symbols = opts.symbols || { female: '♀', male: '♂', other: '☻' };
        var baseHint = '未上傳則依性別使用站方預設頭像。';

        if (!genderSelect || !defaultWrap) {
            return;
        }

        function resolveDefaultUrl(gender) {
            if (defaults[gender]) {
                return defaults[gender];
            }
            if (gender === 'other') {
                return defaults.female || defaults.male || '';
            }
            return '';
        }

        function hasCustomPhoto() {
            if (hidden && hidden.value) {
                return true;
            }
            if (customPreviewWrap) {
                return !customPreviewWrap.hidden;
            }
            return !!(customPreview && customPreview.getAttribute('src'));
        }

        function isEditingPhoto() {
            return !!(panel && !panel.hidden);
        }

        function updateDefaultPreview() {
            if (hasCustomPhoto() || isEditingPhoto()) {
                defaultWrap.hidden = true;
                return;
            }
            defaultWrap.hidden = false;
            var g = genderSelect.value || 'female';
            var url = resolveDefaultUrl(g);
            if (defaultImg && url) {
                defaultImg.src = url + (url.indexOf('?') >= 0 ? '&' : '?') + '_=' + Date.now();
                defaultImg.hidden = false;
                if (defaultFallback) {
                    defaultFallback.hidden = true;
                }
            } else {
                if (defaultImg) {
                    defaultImg.hidden = true;
                    defaultImg.removeAttribute('src');
                }
                if (defaultFallback) {
                    defaultFallback.textContent = symbols[g] || symbols.other || '☻';
                    defaultFallback.hidden = false;
                }
            }
            if (hint && !hint.textContent) {
                hint.textContent = baseHint;
            }
        }

        genderSelect.addEventListener('change', updateDefaultPreview);

        if (fileInput) {
            fileInput.addEventListener('change', function () {
                if (fileInput.files && fileInput.files[0]) {
                    defaultWrap.hidden = true;
                } else {
                    updateDefaultPreview();
                }
            });
        }

        ['masseur-photo-apply', 'masseur-photo-cancel', 'masseur-photo-cancel-edit'].forEach(function (id) {
            var btn = document.getElementById(id);
            if (btn) {
                btn.addEventListener('click', function () {
                    window.setTimeout(updateDefaultPreview, 0);
                });
            }
        });

        updateDefaultPreview();
    }

    global.fateInitMasseurGenderDefaultPreview = initMasseurGenderDefaultPreview;

    if (document.getElementById('masseur-photo')) {
        initMasseurPhotoEditor({
            fileId: 'masseur-photo',
            panelId: 'masseur-photo-panel',
            cropStageId: 'masseur-photo-crop-stage',
            editStageId: 'masseur-photo-edit-stage',
            cropCanvasId: 'masseur-photo-crop-canvas',
            cropZoomId: 'masseur-photo-crop-zoom',
            cropApplyId: 'masseur-photo-crop-apply',
            canvasId: 'masseur-photo-canvas',
            hiddenId: 'masseur_photo_data',
            brushId: 'masseur-photo-brush',
            recropId: 'masseur-photo-recrop',
            applyId: 'masseur-photo-apply',
            resetId: 'masseur-photo-reset',
            cancelId: 'masseur-photo-cancel',
            cancelEditId: 'masseur-photo-cancel-edit',
            previewId: 'masseur-photo-preview',
            previewWrapId: 'masseur-photo-preview-wrap',
            hintId: 'masseur-photo-hint',
            cropAspect: 'portrait',
            applyMessage: '相片已套用，送出表單即可建檔。',
        });
    }
})(typeof window !== 'undefined' ? window : this);
