/**
 * 테이블 정렬 유틸리티
 *
 * 다양한 테이블에서 재사용 가능한 정렬/그룹화 기능 제공
 *
 * @example
 * // 기본 사용
 * const sorter = new TableSorter({
 *     data: issuesData,
 *     containerId: 'issue-list',
 *     renderFn: renderIssues,
 *     sortOptions: [
 *         { value: 'start_date', label: '시작일순', type: 'date' },
 *         { value: 'status', label: '상태순', type: 'priority', priority: {...} },
 *         { value: 'client', label: '고객사별', type: 'group' },
 *     ]
 * });
 * sorter.init();
 */

class TableSorter {
    constructor(options) {
        this.data = options.data || [];
        this.containerId = options.containerId;
        this.renderFn = options.renderFn;
        this.sortOptions = options.sortOptions || [];
        this.defaultSort = options.defaultSort || null;
        this.onSort = options.onSort || null;
        this.controlsContainerId = options.controlsContainerId || null;

        this.currentSort = this.defaultSort;
        this.currentDirection = 'asc';
    }

    /**
     * 초기화 - 정렬 컨트롤 UI 생성
     */
    init() {
        if (this.controlsContainerId) {
            this.renderControls();
        }
        return this;
    }

    /**
     * 데이터 업데이트
     */
    setData(data) {
        this.data = data;
        return this;
    }

    /**
     * 정렬 컨트롤 UI 렌더링
     */
    renderControls() {
        const container = document.getElementById(this.controlsContainerId);
        if (!container) return;

        const html = `
            <div class="flex items-center gap-2">
                <span class="text-xs text-gray-500">정렬:</span>
                <select id="${this.containerId}-sort"
                        class="text-xs px-2 py-1 border border-gray-300 rounded-lg bg-white focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
                    <option value="">기본</option>
                    ${this.sortOptions.map(opt =>
                        `<option value="${opt.value}" ${this.currentSort === opt.value ? 'selected' : ''}>${opt.label}</option>`
                    ).join('')}
                </select>
                <button id="${this.containerId}-sort-dir"
                        class="p-1 text-gray-400 hover:text-gray-600 rounded hover:bg-gray-100 transition"
                        title="정렬 방향 변경">
                    <svg class="w-4 h-4 transition-transform ${this.currentDirection === 'desc' ? 'rotate-180' : ''}"
                         fill="none" stroke="currentColor" viewBox="0 0 24 24">
                        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 15l7-7 7 7"/>
                    </svg>
                </button>
            </div>
        `;
        container.innerHTML = html;

        // 이벤트 바인딩
        const select = document.getElementById(`${this.containerId}-sort`);
        const dirBtn = document.getElementById(`${this.containerId}-sort-dir`);

        select?.addEventListener('change', (e) => {
            this.currentSort = e.target.value || null;
            this.apply();
        });

        dirBtn?.addEventListener('click', () => {
            this.currentDirection = this.currentDirection === 'asc' ? 'desc' : 'asc';
            dirBtn.querySelector('svg').classList.toggle('rotate-180');
            this.apply();
        });
    }

    /**
     * 정렬 적용 및 렌더링
     */
    apply() {
        const sortedData = this.sort(this.data);

        if (this.onSort) {
            this.onSort(sortedData, this.currentSort, this.currentDirection);
        } else if (this.renderFn) {
            const container = document.getElementById(this.containerId);
            if (container) {
                this.renderFn(container, sortedData);
            }
        }

        return sortedData;
    }

    /**
     * 데이터 정렬
     */
    sort(data) {
        if (!this.currentSort || !data || data.length === 0) {
            return data;
        }

        const option = this.sortOptions.find(o => o.value === this.currentSort);
        if (!option) return data;

        const sorted = [...data].sort((a, b) => {
            let result = 0;

            switch (option.type) {
                case 'date':
                    result = this.compareDates(a[option.value], b[option.value]);
                    break;
                case 'number':
                    result = this.compareNumbers(a[option.value], b[option.value]);
                    break;
                case 'priority':
                    result = this.comparePriority(a[option.value], b[option.value], option.priority);
                    break;
                case 'group':
                case 'string':
                default:
                    result = this.compareStrings(a[option.value], b[option.value]);
                    break;
            }

            // 2차 정렬 (옵션)
            if (result === 0 && option.secondary) {
                const secOption = this.sortOptions.find(o => o.value === option.secondary);
                if (secOption) {
                    result = this.compareByType(a, b, secOption);
                }
            }

            return this.currentDirection === 'desc' ? -result : result;
        });

        return sorted;
    }

    /**
     * 타입별 비교
     */
    compareByType(a, b, option) {
        switch (option.type) {
            case 'date':
                return this.compareDates(a[option.value], b[option.value]);
            case 'number':
                return this.compareNumbers(a[option.value], b[option.value]);
            case 'priority':
                return this.comparePriority(a[option.value], b[option.value], option.priority);
            default:
                return this.compareStrings(a[option.value], b[option.value]);
        }
    }

    /**
     * 날짜 비교 (null은 맨 뒤)
     */
    compareDates(a, b) {
        if (!a && !b) return 0;
        if (!a) return 1;
        if (!b) return -1;
        return new Date(a) - new Date(b);
    }

    /**
     * 숫자 비교 (null은 맨 뒤)
     */
    compareNumbers(a, b) {
        if (a == null && b == null) return 0;
        if (a == null) return 1;
        if (b == null) return -1;
        return Number(a) - Number(b);
    }

    /**
     * 문자열 비교 (null/빈값은 맨 뒤)
     */
    compareStrings(a, b) {
        const strA = (a || '').toString().toLowerCase();
        const strB = (b || '').toString().toLowerCase();

        if (!strA && !strB) return 0;
        if (!strA) return 1;
        if (!strB) return -1;

        return strA.localeCompare(strB, 'ko');
    }

    /**
     * 우선순위 비교
     */
    comparePriority(a, b, priorityMap) {
        const prioA = priorityMap[a] ?? 99;
        const prioB = priorityMap[b] ?? 99;
        return prioA - prioB;
    }

    /**
     * 현재 정렬 상태 반환
     */
    getState() {
        return {
            sort: this.currentSort,
            direction: this.currentDirection
        };
    }

    /**
     * 정렬 상태 설정
     */
    setState(sort, direction = 'asc') {
        this.currentSort = sort;
        this.currentDirection = direction;
        return this;
    }
}

/**
 * 그룹화 유틸리티
 * 데이터를 특정 필드로 그룹화하여 반환
 */
class TableGrouper {
    /**
     * 데이터 그룹화
     * @param {Array} data - 원본 데이터
     * @param {string} groupBy - 그룹화 기준 필드
     * @param {Object} options - 옵션
     * @returns {Object} 그룹화된 데이터 { groupKey: [items] }
     */
    static group(data, groupBy, options = {}) {
        const emptyLabel = options.emptyLabel || '(미지정)';
        const sortGroups = options.sortGroups !== false;

        const groups = {};

        data.forEach(item => {
            const key = item[groupBy] || emptyLabel;
            if (!groups[key]) {
                groups[key] = [];
            }
            groups[key].push(item);
        });

        if (sortGroups) {
            const sortedKeys = Object.keys(groups).sort((a, b) => {
                if (a === emptyLabel) return 1;
                if (b === emptyLabel) return -1;
                return a.localeCompare(b, 'ko');
            });

            const sortedGroups = {};
            sortedKeys.forEach(key => {
                sortedGroups[key] = groups[key];
            });
            return sortedGroups;
        }

        return groups;
    }

    /**
     * 그룹 내 아이템 정렬
     * @param {Object} groups - 그룹화된 데이터
     * @param {Function} sortFn - 정렬 함수
     * @returns {Object} 정렬된 그룹 데이터
     */
    static sortWithinGroups(groups, sortFn) {
        const result = {};
        Object.keys(groups).forEach(key => {
            result[key] = [...groups[key]].sort(sortFn);
        });
        return result;
    }
}

/**
 * 간단한 정렬 함수 (TableSorter 없이 사용)
 */
const SortUtils = {
    /**
     * 다중 기준 정렬
     * @param {Array} data - 정렬할 데이터
     * @param {Array} criteria - 정렬 기준 배열 [{ field, direction, type, priority }]
     */
    multiSort(data, criteria) {
        return [...data].sort((a, b) => {
            for (const criterion of criteria) {
                const { field, direction = 'asc', type = 'string', priority } = criterion;
                let result = 0;

                switch (type) {
                    case 'date':
                        result = this.compareDates(a[field], b[field]);
                        break;
                    case 'number':
                        result = this.compareNumbers(a[field], b[field]);
                        break;
                    case 'priority':
                        result = this.comparePriority(a[field], b[field], priority);
                        break;
                    default:
                        result = this.compareStrings(a[field], b[field]);
                }

                if (result !== 0) {
                    return direction === 'desc' ? -result : result;
                }
            }
            return 0;
        });
    },

    compareDates(a, b) {
        if (!a && !b) return 0;
        if (!a) return 1;
        if (!b) return -1;
        return new Date(a) - new Date(b);
    },

    compareNumbers(a, b) {
        if (a == null && b == null) return 0;
        if (a == null) return 1;
        if (b == null) return -1;
        return Number(a) - Number(b);
    },

    compareStrings(a, b) {
        const strA = (a || '').toString().toLowerCase();
        const strB = (b || '').toString().toLowerCase();
        if (!strA && !strB) return 0;
        if (!strA) return 1;
        if (!strB) return -1;
        return strA.localeCompare(strB, 'ko');
    },

    comparePriority(a, b, priorityMap) {
        const prioA = priorityMap[a] ?? 99;
        const prioB = priorityMap[b] ?? 99;
        return prioA - prioB;
    }
};

// 전역 등록
window.TableSorter = TableSorter;
window.TableGrouper = TableGrouper;
window.SortUtils = SortUtils;
