(function() {
    function init() {
        const containers = document.querySelectorAll('.hdyc-calc-container');
        if (containers.length === 0) return;

        containers.forEach(container => {
            const type = container.dataset.hdycType;
            const factor = parseFloat(container.dataset.hdycFactor) || 1;
            const offset = parseFloat(container.dataset.hdycOffset) || 0;
            const in1 = container.querySelector('#input-1');
            const in2 = container.querySelector('#input-2');
            const in3 = container.querySelector('#input-3');

            if (!in1 || !in2) return;

            function solve(source) {
                let v1 = parseFloat(in1.value);
                let v2 = parseFloat(in2.value);
                let v3 = in3 ? parseFloat(in3.value) : NaN;

                if (type === 'standard') {
                    if (source === 1) {
                        if (!isNaN(v1)) in2.value = parseFloat((v1 * factor + offset).toFixed(6));
                        else in2.value = '';
                    } else {
                        if (!isNaN(v2)) in1.value = parseFloat(((v2 - offset) / factor).toFixed(6));
                        else in1.value = '';
                    }
                } else if (type === 'inverse') {
                    // Logic: v1 * v2 = factor (constant)
                    if (source === 1) {
                        if (!isNaN(v1) && v1 !== 0) in2.value = parseFloat((factor / v1).toFixed(6));
                        else in2.value = '';
                    } else {
                        if (!isNaN(v2) && v2 !== 0) in1.value = parseFloat((factor / v2).toFixed(6));
                        else in1.value = '';
                    }
                } else if (type === '3col') {
                    // Standard 3-col: v3 = v1 / v2 (e.g. Watts = Amps * Volts -> in3 = in1 / in2? No, usually Watts is in3)
                    // Let's look at legacy scripts. 
                    // grams-to-moles: in3 (moles) = in1 (mass) / in2 (molar mass)
                    // watts-to-amps: in3 (amps) = in1 (watts) / in2 (volts)
                    if (source === 1 || source === 2) {
                        if (!isNaN(v1) && !isNaN(v2) && v2 !== 0) in3.value = parseFloat((v1 / v2).toFixed(6));
                        else in3.value = '';
                    } else {
                        if (!isNaN(v3) && !isNaN(v2)) in1.value = parseFloat((v3 * v2).toFixed(6));
                        else in1.value = '';
                    }
                } else if (type === '3col-mul') {
                    // v3 = v1 * v2 (e.g. Lux to Lumens: Lumens(3) = Lux(1) * Area(2))
                    if (source === 1 || source === 2) {
                        if (!isNaN(v1) && !isNaN(v2)) in3.value = parseFloat((v1 * v2).toFixed(6));
                        else in3.value = '';
                    } else {
                        if (!isNaN(v3) && !isNaN(v2) && v2 !== 0) in1.value = parseFloat((v3 / v2).toFixed(6));
                        else in1.value = '';
                    }
                } else if (type === 'dms-dd') {
                  // DD to DMS (in1=DD, in2=DMS text)
                  if (source === 1) {
                    if (!isNaN(v1)) {
                      let d = Math.floor(v1); let md = (v1 - d) * 60; let m = Math.floor(md); let sec = ((md - m) * 60).toFixed(2);
                      in2.value = `${d}° ${m}' ${sec}"`;
                    } else in2.value = '';
                  } else {
                    let str = in2.value;
                    let match = str.match(/(?:([0-9.-]+)\s*°)?\s*(?:([0-9.-]+)\s*')?\s*(?:([0-9.-]+)\s*")?/);
                    if (match) {
                      let d = parseFloat(match[1]) || 0; let m = parseFloat(match[2]) || 0; let sec = parseFloat(match[3]) || 0;
                      if (str.trim().length > 0) in1.value = parseFloat((d + m/60 + sec/3600).toFixed(6));
                      else in1.value = '';
                    } else in1.value = '';
                  }
                } else if (type === 'dd-dms') {
                   // DMS to DD inverse?
                   // Actually the legacy code for "dms-to-dd" has input-1 as DMS and input-2 as DD.
                   // I'll handle based on the ID mapping in the container.
                } else if (type === 'dec-frac') {
                  function gcd(a, b) { return b ? gcd(b, a % b) : a; }
                  if (source === 1) {
                    if (!isNaN(v1)) {
                        let len = v1.toString().split('.')[1] ? v1.toString().split('.')[1].length : 0;
                        let den = Math.pow(10, len); let num = v1 * den; let div = gcd(num, den);
                        in2.value = `${num/div}/${den/div}`;
                    } else in2.value = '';
                  } else {
                    let parts = in2.value.split('/');
                    if (parts.length === 2 && !isNaN(parts[0]) && !isNaN(parts[1]) && parts[1] != 0) in1.value = parseFloat((parts[0]/parts[1]).toFixed(6));
                    else { let f = parseFloat(parts[0]); if (!isNaN(f)) in1.value = f; else in1.value = ''; }
                  }
                } else if (type === 'db-int') {
                    if (source === 1) { if (!isNaN(v1)) in2.value = parseFloat((1e-12 * Math.pow(10, v1/10)).toExponential(6)); else in2.value = ''; }
                    else { if (!isNaN(v2) && v2 > 0) in1.value = parseFloat((10 * Math.log10(v2 / 1e-12)).toFixed(6)); else in1.value = ''; }
                } else if (type === 'db-spl') {
                    if (source === 1) { if (!isNaN(v1)) in2.value = parseFloat((20 * Math.pow(10, v1/20)).toFixed(6)); else in2.value = ''; }
                    else { if (!isNaN(v2) && v2 > 0) in1.value = parseFloat((20 * Math.log10(v2 / 20)).toFixed(6)); else in1.value = ''; }
                } else if (type === 'db-v') {
                    if (source === 1) { if (!isNaN(v1)) in2.value = parseFloat((1 * Math.pow(10, v1/20)).toFixed(6)); else in2.value = ''; }
                    else { if (!isNaN(v2) && v2 > 0) in1.value = parseFloat((20 * Math.log10(v2 / 1)).toFixed(6)); else in1.value = ''; }
                } else if (type === 'db-w') {
                    if (source === 1) { if (!isNaN(v1)) in2.value = parseFloat((1 * Math.pow(10, v1/10)).toFixed(6)); else in2.value = ''; }
                    else { if (!isNaN(v2) && v2 > 0) in1.value = parseFloat((10 * Math.log10(v2 / 1)).toFixed(6)); else in1.value = ''; }
                } else if (type === 'base') {
                    const fromBase = parseInt(container.dataset.hdycFrom) || 10;
                    const toBase = parseInt(container.dataset.hdycTo) || 2;
                    if (source === 1) {
                        try {
                            const val = in1.value.trim();
                            if (val === '') { in2.value = ''; return; }
                            const dec = parseInt(val, fromBase);
                            if (!isNaN(dec)) in2.value = dec.toString(toBase).toUpperCase();
                            else in2.value = 'Invalid';
                        } catch(e) { in2.value = 'Error'; }
                    } else {
                        try {
                            const val = in2.value.trim();
                            if (val === '') { in1.value = ''; return; }
                            const dec = parseInt(val, toBase);
                            if (!isNaN(dec)) in1.value = dec.toString(fromBase).toUpperCase();
                            else in1.value = 'Invalid';
                        } catch(e) { in1.value = 'Error'; }
                    }
                } else if (type === 'text-bin') {
                    if (source === 1) {
                        in2.value = in1.value.split('').map(char => char.charCodeAt(0).toString(2).padStart(8, '0')).join(' ');
                    } else {
                        try {
                           in1.value = in2.value.split(' ').map(bin => String.fromCharCode(parseInt(bin, 2))).join('');
                        } catch(e) { in1.value = 'Error'; }
                    }
                } else if (type === 'bin-text') {
                    if (source === 1) {
                        try {
                           in2.value = in1.value.split(' ').map(bin => String.fromCharCode(parseInt(bin, 2))).join('');
                        } catch(e) { in2.value = 'Error'; }
                    } else {
                        in1.value = in2.value.split('').map(char => char.charCodeAt(0).toString(2).padStart(8, '0')).join(' ');
                    }
                }
            }

            in1.addEventListener('input', () => solve(1));
            in2.addEventListener('input', () => solve(2));
            if (in3) in3.addEventListener('input', () => solve(3));

            const uParams = new URLSearchParams(window.location.search);
            if (uParams.has('v1')) { in1.value = uParams.get('v1'); solve(1); }
            else if (uParams.has('v2')) { in2.value = uParams.get('v2'); solve(2); }
            else if (uParams.has('v3') && in3) { in3.value = uParams.get('v3'); solve(3); }
        });
    }

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