/* =========================================================================
 * XIT Common JavaScript Library
 * 중요도 순서: 1.환경설정 → 3.Ajax통신 → 4.공통유틸 → 5.UI컴포넌트
 * ========================================================================= */

/* =============================================================================
 * 1. ENVIRONMENT CONFIGURATION (최우선 - 시스템 기본 설정)
 * ============================================================================= */

/* 컨택스트 패스 설정 로드 */
// 기본값 설정 (설정 로드 실패 시 사용)
var contextPath = '';

// 현재 스크립트 경로에서 컨택스트 패스 추출 (임시 방법)
(function() {
    var scripts = document.getElementsByTagName('script');
    var currentScript = scripts[scripts.length - 1];
    var src = currentScript.src;

    if (src) {
        // 스크립트 경로에서 컨택스트 패스 추출 (예: http://localhost:8080/context/resources/xit/xit-common.js)
        var match = src.match(/^https?:\/\/[^\/]+([^\/]*?)\/resources\//);
        if (match && match[1]) {
            contextPath = match[1];
        }
    }
})();

// 서버에서 정확한 컨택스트 패스 로드 (위의 추출된 값으로 URL 구성)
(function() {
    var script = document.createElement('script');
    script.src = (contextPath || '') + '/common/config/context-path.do';
    script.async = false; // 동기적으로 로드하여 설정값이 먼저 로드되도록 함
    script.onerror = function() {
        // 컨택스트 패스 로드 실패 시 기본값 유지
        console.warn('컨택스트 패스 설정 로드에 실패했습니다. 추출된 값("' + contextPath + '")을 사용합니다.');
    };
    document.head.appendChild(script);
})();

/* 로그인 URL 설정 로드 */
// 기본값 설정 (설정 로드 실패 시 사용)
var loginUrl = '/login/login.do';

// 서버에서 설정값 로드 (컨택스트 패스 적용)
(function() {
    var script = document.createElement('script');
    script.src = (contextPath || '') + '/common/config/login-url.do';
    script.async = false; // 동기적으로 로드하여 설정값이 먼저 로드되도록 함
    document.head.appendChild(script);
})();

/* =============================================================================
 * 3. AJAX COMMUNICATION (Ajax 통신 관리)
 * ============================================================================= */

/* jQuery Ajax 설정 */
$.ajaxSetup({
	type:"POST",
	dataType : "JSON",
	cache: false
});

/* Ajax Error 설정 */
$(document).ajaxError( function( event, jqxhr, settings, exception ){
    if( jqxhr.responseJSON ){
        // 세션 만료인 경우 처리
        if(jqxhr.responseJSON.errorCode === "SESSION_EXPIRED") {
            handleSessionExpired()
        } else if(jqxhr.responseJSON.errorCode === "MessageException") {
            alert(jqxhr.responseJSON.message);
        } else if(jqxhr.responseJSON.errorCode === "MESSAGE_EXCEPTION") {
            alert(jqxhr.responseJSON.message);
        } else if(jqxhr.responseJSON.errorCode === "MESSAGE") {
                    alert(jqxhr.responseJSON.message);
        } else {
            alert("에러가 발생했습니다.\n\nERROR CODE : "+jqxhr.responseJSON.errorCode+"\nMESSAGE : "+jqxhr.responseJSON.message);
        }
    }
});

function handleSessionExpired() {
    alert("세션이 종료되었습니다. 로그인 페이지로 이동합니다.");

    try {
        // 최상위 부모창 찾기
        var topWindow = window;
        while (topWindow.opener && !topWindow.opener.closed) {
            topWindow = topWindow.opener;
        }

        // 최상위 부모는 로그인 페이지로 이동
        if (topWindow && !topWindow.closed) {
            topWindow.location.href = loginUrl;
        }

        // 🔹 열린 순서대로 닫기: 최상위부터 내려오면서 닫음
        var stack = [];
        var current = window;

        // opener 체인을 최상위까지 쭉 담기
        while (current.opener && !current.opener.closed) {
            stack.unshift(current.opener); // 부모를 앞쪽에 넣음
            current = current.opener;
        }

        // stack = [A, B, ...] 순서대로 들어있음
        stack.forEach(function(win) {
            try {
                if (win && !win.closed) {
                    win.close();
                }
            } catch (e) {
                console.warn("창 닫기 실패:", e);
            }
        });

        // 마지막에 현재 창 닫기
        setTimeout(function() {
            try {
                window.close();
            } catch (e) {
                console.warn("현재 창 닫기 실패:", e);
            }
        }, 100);

    } catch (e) {
        console.error("세션 만료 처리 중 오류:", e);
        location.href = loginUrl; // fallback
    }
}

/* Ajax Progress Block UI 설정 */
// Ajax 활성 요청 카운터 (동시 Ajax 요청 처리를 위함)
var activeAjaxCount = 0;

// Progress Block UI 초기화
$(document).ready(function() {
    // Progress Block UI 생성
    createProgressBlockUI();
    console.debug('[Ajax Block UI] 초기화 완료');

    // activeAjaxCount 리셋 (페이지 로드 시)
    activeAjaxCount = 0;
    console.debug('[Ajax Block UI] Ajax 카운터 초기화:', activeAjaxCount);
});

// Ajax 시작 시 Progress Block UI 표시
$(document).ajaxSend(function(event, jqXHR, ajaxOptions) {
    console.debug('[Ajax Block UI] Ajax 시작:', ajaxOptions.url);

    // Block UI 제외 대상 URL 체크
    if (ajaxOptions.url && ajaxOptions.url.indexOf('/system/user/duplicateCheck.ajax') !== -1) {
        console.log('[Ajax Block UI] 제외 대상 URL, Block UI 표시 안함');
        return;
    }

    activeAjaxCount++;
    console.debug('[Ajax Block UI] 활성 Ajax 카운트 증가:', activeAjaxCount);

    // 첫 번째 Ajax 요청일 때만 Progress Block UI 표시
    if (activeAjaxCount === 1) {
        // Block UI 요소 존재 확인
        if ($('#ajax-progress-overlay').length === 0) {
            console.warn('[Ajax Block UI] Block UI 요소가 존재하지 않음, 생성 시도');
            createProgressBlockUI();
        }

        var $overlay = $('#ajax-progress-overlay');
        if ($overlay.length > 0) {
            $overlay.css('display', 'flex').hide().fadeIn(200);
            console.debug('[Ajax Block UI] Block UI 표시 완료');
        } else {
            console.error('[Ajax Block UI] Block UI 요소를 찾을 수 없음');
        }
    }
});

// Ajax 완료 시 Progress Block UI 제거 (성공/실패 모든 경우)
$(document).ajaxComplete(function(event, jqXHR, ajaxOptions) {
    console.debug('[Ajax Block UI] Ajax 완료:', ajaxOptions.url);

    // Block UI 제외 대상 URL 체크 (ajaxSend와 동일한 조건으로 수정)
    if (ajaxOptions.url && ajaxOptions.url.indexOf('/system/user/duplicateCheck.ajax') !== -1) {
        console.debug('[Ajax Block UI] 제외 대상 URL, 카운트 감소 안함');
        return;
    }

    activeAjaxCount--;
    console.debug('[Ajax Block UI] 활성 Ajax 카운트 감소:', activeAjaxCount);

    // 모든 Ajax 요청이 완료되었을 때만 Progress Block UI 숨김
    if (activeAjaxCount <= 0) {
        activeAjaxCount = 0; // 음수 방지
        var $overlay = $('#ajax-progress-overlay');
        if ($overlay.length > 0) {
            $overlay.fadeOut(200);
            console.debug('[Ajax Block UI] Block UI 숨김 완료');
        } else {
            console.warn('[Ajax Block UI] Block UI 요소를 찾을 수 없어 숨길 수 없음');
        }
    }
});

// Progress Block UI 생성 함수
function createProgressBlockUI() {
    if ($('#ajax-progress-overlay').length === 0) {
        var progressHtml =
            '<div id="ajax-progress-overlay" class="ajax-progress-overlay" style="' +
                'position: fixed; top: 0; left: 0; width: 100%; height: 100%; ' +
                'background-color: rgba(0, 0, 0, 0.3); z-index: 9999; ' +
                'display: none; justify-content: center; align-items: center;">' +
                '<div class="ajax-progress-content" style="' +
                    'background-color: #ffffff; border-radius: 8px; padding: 30px; ' +
                    'box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); text-align: center; min-width: 200px;">' +
                    '<div class="ajax-progress-spinner" style="' +
                        'width: 40px; height: 40px; border: 4px solid #f3f3f3; ' +
                        'border-top: 4px solid #007bff; border-radius: 50%; ' +
                        'animation: spin 1s linear infinite; margin: 0 auto 15px;"></div>' +
                    '<p class="ajax-progress-text" style="' +
                        'color: #495057; font-size: 14px; font-weight: 500; margin: 0; ' +
                        'text-align: center;">처리 중입니다...</p>' +
                '</div>' +
            '</div>';
        $('body').append(progressHtml);

        // CSS 애니메이션이 없는 경우를 대비한 인라인 스타일 추가
        var style = document.createElement('style');
        style.textContent = '@keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }';
        document.head.appendChild(style);

        console.log('[Ajax Block UI] Block UI 요소 생성 완료');
    }
}

/* =============================================================================
 * 4. COMMON UTILITIES (공통 유틸리티 함수들)
 * ============================================================================= */

/* 4.1 VALIDATION UTILITIES (검증 관련 함수들) */

/**
 * HTML 엔티티를 원래 문자로 변환하는 함수
 * JavaScript XSS 공격 패턴도 감지하여 처리
 * 문자열 및 JSON 객체 모두 처리 가능
 * @param {string|object|array} input - escape 처리된 문자열 또는 JSON 객체
 * @return {string|object|array} unescape 처리된 문자열 또는 JSON 객체
 */
function unescapeHtml(input) {
    // 입력값이 없는 경우 그대로 반환
    if (input === null || input === undefined) return input;

    // 입력값이 문자열인 경우 기존 로직으로 처리
    if (typeof input === 'string') {
        // HTML 엔티티를 원래 문자로 변환
        var unescaped = input.replace(/&amp;/g, '&')
            .replace(/&lt;/g, '<')
            .replace(/&gt;/g, '>')
            .replace(/&quot;/g, '"')
            .replace(/&#x27;/g, "'")
            .replace(/&#x2F;/g, '/')
            .replace(/&#40;/g, '(')
            .replace(/&#41;/g, ')');

        // 문자열 연결을 통한 우회 방지를 위한 정규화
        // j&#x61;vascript: 같은 패턴을 javascript:로 변환
        unescaped = unescaped.replace(/j\s*(?:&[^;]+;|\\[0-9A-Fa-f]+)\s*a\s*(?:&[^;]+;|\\[0-9A-Fa-f]+)\s*v\s*(?:&[^;]+;|\\[0-9A-Fa-f]+)\s*a\s*(?:&[^;]+;|\\[0-9A-Fa-f]+)\s*s\s*(?:&[^;]+;|\\[0-9A-Fa-f]+)\s*c\s*(?:&[^;]+;|\\[0-9A-Fa-f]+)\s*r\s*(?:&[^;]+;|\\[0-9A-Fa-f]+)\s*i\s*(?:&[^;]+;|\\[0-9A-Fa-f]+)\s*p\s*(?:&[^;]+;|\\[0-9A-Fa-f]+)\s*t\s*(?:&[^;]+;|\\[0-9A-Fa-f]+)\s*:/gi, 'javascript:');

        // JavaScript XSS 공격 패턴 감지 및 처리
        var xssPatterns = [
            // 위험한 프로토콜
            { pattern: /javascript\s*:/i, replacement: 'blocked:' },
            { pattern: /vbscript\s*:/i, replacement: 'blocked:' },
            { pattern: /data\s*:[^,]*?base64/i, replacement: 'blocked:' },
            { pattern: /livescript\s*:/i, replacement: 'blocked:' },
            { pattern: /mocha\s*:/i, replacement: 'blocked:' },

            // 스크립트 태그
            { pattern: /<script\b[^>]*>(.*?)<\/script>/gi, replacement: '' },

            // 이벤트 핸들러 속성
            { pattern: /\s+on\w+\s*=\s*["']?[^"']*["']?/gi, replacement: '' },

            // 위험한 함수 호출
            { pattern: /eval\s*\(/gi, replacement: 'blocked(' },
            { pattern: /setTimeout\s*\(/gi, replacement: 'blocked(' },
            { pattern: /setInterval\s*\(/gi, replacement: 'blocked(' },
            { pattern: /Function\s*\(/gi, replacement: 'blocked(' },
            { pattern: /constructor\s*\(/gi, replacement: 'blocked(' },
            { pattern: /import\s*\(/gi, replacement: 'blocked(' },
            { pattern: /execScript\s*\(/gi, replacement: 'blocked(' },
            { pattern: /document\s*\.\s*write\s*\(/gi, replacement: 'blocked.write(' },
            { pattern: /document\s*\.\s*writeln\s*\(/gi, replacement: 'blocked.writeln(' },

            // 위험한 CSS 표현식
            { pattern: /expression\s*\(/gi, replacement: 'blocked(' },
            { pattern: /url\s*\(\s*["']?\s*javascript:/gi, replacement: 'url(blocked:' },

            // 인라인 스타일 속성에서의 XSS
            { pattern: /style\s*=\s*["']?[^"']*(?:expression|javascript|behavior|url\s*\(\s*['"]?\s*javascript:)[^"']*/gi, replacement: 'style="blocked"' },

            // 위험한 HTML 태그
            { pattern: /<iframe\b[^>]*>(.*?)<\/iframe>/gi, replacement: '' },
            { pattern: /<object\b[^>]*>(.*?)<\/object>/gi, replacement: '' },
            { pattern: /<embed\b[^>]*>(.*?)<\/embed>/gi, replacement: '' },
            { pattern: /<base\b[^>]*>/gi, replacement: '' },
            { pattern: /<form\b[^>]*>(.*?)<\/form>/gi, replacement: '' },
            { pattern: /<svg\b[^>]*>(.*?)<\/svg>/gi, replacement: '' },
            { pattern: /<math\b[^>]*>(.*?)<\/math>/gi, replacement: '' },
            { pattern: /<link\b[^>]*>/gi, replacement: '' },
            { pattern: /<meta\b[^>]*>/gi, replacement: '' },

            // 주석 내 코드 실행 방지
            { pattern: /<!--[^>]*-->/g, replacement: '' },

            // 기타 위험한 패턴
            { pattern: /document\s*\.\s*cookie/gi, replacement: 'blocked.cookie' },
            { pattern: /document\s*\.\s*domain/gi, replacement: 'blocked.domain' },
            { pattern: /document\s*\.\s*location/gi, replacement: 'blocked.location' },
            { pattern: /window\s*\.\s*location/gi, replacement: 'blocked.location' },
            { pattern: /location\s*\.\s*href/gi, replacement: 'blocked.href' },
            { pattern: /location\s*\.\s*replace/gi, replacement: 'blocked.replace' },
            { pattern: /location\s*\.\s*assign/gi, replacement: 'blocked.assign' },
            { pattern: /window\s*\.\s*open\s*\(/gi, replacement: 'blocked.open(' },
            { pattern: /window\s*\.\s*execScript\s*\(/gi, replacement: 'blocked.execScript(' }
        ];

        // 모든 XSS 패턴에 대해 검사 및 처리
        for (var i = 0; i < xssPatterns.length; i++) {
            unescaped = unescaped.replace(xssPatterns[i].pattern, xssPatterns[i].replacement);
        }

        // 추가적인 보안 검사 - 여러 번 패턴 적용 (중첩된 공격 방지)
        if (/javascript|eval|expression|on\w+=|<script|<iframe|<object|<embed|<svg|<form/i.test(unescaped)) {
            // 위험한 패턴이 여전히 존재하면 한 번 더 패턴 적용
            for (var i = 0; i < xssPatterns.length; i++) {
                unescaped = unescaped.replace(xssPatterns[i].pattern, xssPatterns[i].replacement);
            }
        }

        return unescaped;
    }
    // 입력값이 배열인 경우 각 요소를 재귀적으로 처리
    else if (Array.isArray(input)) {
        // 배열의 각 요소에 대해 재귀적으로 unescapeHtml 함수 적용
        return input.map(function(item) {
            return unescapeHtml(item);
        });
    }
    // 입력값이 객체인 경우 각 속성을 재귀적으로 처리
    else if (typeof input === 'object') {
        // 객체의 복사본 생성
        var result = {};

        // 객체의 각 속성에 대해 재귀적으로 unescapeHtml 함수 적용
        for (var key in input) {
            if (input.hasOwnProperty(key)) {
                result[key] = unescapeHtml(input[key]);
            }
        }

        return result;
    }
    // 기타 타입(숫자, 불리언 등)은 그대로 반환
    else {
        return input;
    }
}

/* 4.2 COLOR UTILITIES (색상 관련 함수들) */

/**
 * selectbox option에 data-color가 있을 때 자동으로 색상을 적용하는 함수
 * @param {string|jQuery} selector - selectbox 선택자 또는 jQuery 객체
 */
function applySelectboxColors(selector) {
    var $select = typeof selector === 'string' ? $(selector) : selector;

    $select.find('option[data-color]').each(function() {
        var $option = $(this);
        var color = $option.data('color');

        if (color && color.trim() !== '') {
            // 색상을 투명하게 만들기
            var transparentColor = makeColorTransparent(color, 0.15);

            $option.css({
                'background-color': transparentColor,
                'color': 'black',
                'padding': '8px',
                'margin': '2px 0',
                'border-radius': '4px'
            });
        }
    });
}

/**
 * 색상을 투명하게 만드는 함수
 * @param {string} color - 원본 색상
 * @param {number} opacity - 투명도 (0~1)
 * @returns {string} 투명한 색상
 */
function makeColorTransparent(color, opacity) {
    // rgba 형식인 경우
    if (color.startsWith('rgba')) {
        return color.replace(/[\d.]+\)$/, opacity + ')');
    }
    // rgb 형식인 경우
    else if (color.startsWith('rgb')) {
        return color.replace('rgb', 'rgba').replace(')', ', ' + opacity + ')');
    }
    // hex 형식인 경우
    else if (color.startsWith('#')) {
        var r = parseInt(color.substr(1,2), 16);
        var g = parseInt(color.substr(3,2), 16);
        var b = parseInt(color.substr(5,2), 16);
        return 'rgba(' + r + ', ' + g + ', ' + b + ', ' + opacity + ')';
    }
    // 기타 형식은 그대로 반환
    return color;
}

/* =============================================================================
 * 5. UI COMPONENTS (UI 컴포넌트들)
 * ============================================================================= */

/* 5.1 MODAL UTILITIES (모달 관련 함수들) */

$(document).ready(function () {
    $('.pop-x-btn, .modalclose').click(function() {
        var tmp = $(this).parents().parents().parents()
        if (tmp.attr('class') == 'modalz act') {
            tmp.removeClass('act');
        } else {
            //tmp.removeClass('act');
        }
    });
});

/**
 * 모달 닫기 이벤트를 설정하는 함수
 * 모달 닫기 버튼 클릭 및 모달 외부 클릭 시 모달을 닫는 이벤트를 설정합니다.
 * @param {string} modalId - 모달 요소의 ID (기본값: 'modal')
 * @param {string} closeBtnSelector - 닫기 버튼의 선택자 (기본값: '.pop-x-btn, .modalclose')
 */
function initModalClose(modalId) {
    // 기본값 설정
    modalId = modalId || 'modal';

    // '#' 접두사가 없는 경우 추가
    if (!modalId.startsWith('#')) {
        modalId = '#' + modalId;
    }

    // 모달 외부 클릭 시 닫기 (dim 영역 클릭 시)
    $(modalId + ' .dim').on('click', function() {
        $(modalId).removeClass('act');
    });

    // ESC 키 입력 시 모달 닫기
    $(document).on('keydown', function(e) {
        if (e.keyCode === 27 && $(modalId).hasClass('act')) { // ESC key
            $(modalId).removeClass('act');
        }
    });
}

/* 5.2 SELECTBOX INITIALIZATION (selectbox 자동 색상 적용) */

/**
 * 페이지 로드 시 모든 selectbox에 자동 색상 적용
 */
$(document).ready(function() {
    // 기존 selectbox에 색상 적용
    applySelectboxColors('select');

    // 동적으로 추가되는 selectbox를 위한 MutationObserver 설정
    var observer = new MutationObserver(function(mutations) {
        mutations.forEach(function(mutation) {
            if (mutation.type === 'childList') {
                mutation.addedNodes.forEach(function(node) {
                    if (node.nodeType === 1) { // Element node
                        // 새로 추가된 selectbox 찾기
                        var $newSelects = $(node).find('select[data-auto-color="true"]');
                        if ($newSelects.length > 0) {
                            applySelectboxColors($newSelects);
                        }

                        // 새로 추가된 option이 있는 selectbox 찾기
                        var $selectsWithNewOptions = $(node).find('select option[data-color]').parent();
                        if ($selectsWithNewOptions.length > 0) {
                            applySelectboxColors($selectsWithNewOptions);
                        }
                    }
                });
            }
        });
    });

    // body 요소의 변경사항 감지
    observer.observe(document.body, {
        childList: true,
        subtree: true
    });
});