/**
 * CacheManager - 데이터 캐싱 및 로컬 스토리지 관리
 * API 응답, 문서 데이터, 사용자 설정 등을 효율적으로 캐싱합니다.
 */
class CacheManager {
    constructor() {
        console.log('💾 CacheManager 초기화 시작');
        
        // 캐시 설정
        this.config = {
            // 캐시 만료 시간 (밀리초)
            ttl: {
                document: 30 * 60 * 1000,      // 문서: 30분
                highlights: 10 * 60 * 1000,    // 하이라이트: 10분
                notes: 10 * 60 * 1000,         // 메모: 10분
                bookmarks: 15 * 60 * 1000,     // 북마크: 15분
                links: 15 * 60 * 1000,         // 링크: 15분
                navigation: 60 * 60 * 1000,    // 네비게이션: 1시간
                userSettings: 24 * 60 * 60 * 1000  // 사용자 설정: 24시간
            },
            // 캐시 키 접두사
            prefix: 'docviewer_',
            // 최대 캐시 크기 (항목 수)
            maxItems: 100,
            // 로컬 스토리지 사용 여부
            useLocalStorage: true
        };
        
        // 메모리 캐시 (빠른 접근용)
        this.memoryCache = new Map();
        
        // 캐시 통계
        this.stats = {
            hits: 0,
            misses: 0,
            sets: 0,
            evictions: 0
        };
        
        // 초기화 시 오래된 캐시 정리
        this.cleanupExpiredCache();
        
        console.log('✅ CacheManager 초기화 완료');
    }

    /**
     * 캐시에서 데이터 가져오기
     */
    get(key, category = 'default') {
        const fullKey = this.getFullKey(key, category);
        
        // 1. 메모리 캐시에서 먼저 확인
        if (this.memoryCache.has(fullKey)) {
            const cached = this.memoryCache.get(fullKey);
            if (this.isValid(cached)) {
                this.stats.hits++;
                console.log(`💾 메모리 캐시 HIT: ${fullKey}`);
                return cached.data;
            } else {
                // 만료된 캐시 제거
                this.memoryCache.delete(fullKey);
            }
        }
        
        // 2. 로컬 스토리지에서 확인
        if (this.config.useLocalStorage) {
            try {
                const stored = localStorage.getItem(fullKey);
                if (stored) {
                    const cached = JSON.parse(stored);
                    if (this.isValid(cached)) {
                        // 메모리 캐시에도 저장
                        this.memoryCache.set(fullKey, cached);
                        this.stats.hits++;
                        console.log(`💾 로컬 스토리지 캐시 HIT: ${fullKey}`);
                        return cached.data;
                    } else {
                        // 만료된 캐시 제거
                        localStorage.removeItem(fullKey);
                    }
                }
            } catch (error) {
                console.warn('로컬 스토리지 읽기 오류:', error);
            }
        }
        
        this.stats.misses++;
        console.log(`💾 캐시 MISS: ${fullKey}`);
        return null;
    }

    /**
     * 캐시에 데이터 저장
     */
    set(key, data, category = 'default', customTtl = null) {
        const fullKey = this.getFullKey(key, category);
        const ttl = customTtl || this.config.ttl[category] || this.config.ttl.default || 10 * 60 * 1000;
        
        const cached = {
            data: data,
            timestamp: Date.now(),
            ttl: ttl,
            category: category,
            size: this.estimateSize(data)
        };
        
        // 메모리 캐시에 저장
        this.memoryCache.set(fullKey, cached);
        
        // 로컬 스토리지에 저장
        if (this.config.useLocalStorage) {
            try {
                localStorage.setItem(fullKey, JSON.stringify(cached));
            } catch (error) {
                console.warn('로컬 스토리지 저장 오류 (용량 부족?):', error);
                // 용량 부족 시 오래된 캐시 정리 후 재시도
                this.cleanupOldCache();
                try {
                    localStorage.setItem(fullKey, JSON.stringify(cached));
                } catch (retryError) {
                    console.error('로컬 스토리지 저장 재시도 실패:', retryError);
                }
            }
        }
        
        this.stats.sets++;
        console.log(`💾 캐시 저장: ${fullKey} (TTL: ${ttl}ms)`);
        
        // 캐시 크기 제한 확인
        this.enforceMaxItems();
    }

    /**
     * 특정 키 또는 카테고리의 캐시 삭제
     */
    delete(key, category = 'default') {
        const fullKey = this.getFullKey(key, category);
        
        // 메모리 캐시에서 삭제
        this.memoryCache.delete(fullKey);
        
        // 로컬 스토리지에서 삭제
        if (this.config.useLocalStorage) {
            localStorage.removeItem(fullKey);
        }
        
        console.log(`💾 캐시 삭제: ${fullKey}`);
    }

    /**
     * 카테고리별 캐시 전체 삭제
     */
    deleteCategory(category) {
        const prefix = this.getFullKey('', category);
        
        // 메모리 캐시에서 삭제
        for (const key of this.memoryCache.keys()) {
            if (key.startsWith(prefix)) {
                this.memoryCache.delete(key);
            }
        }
        
        // 로컬 스토리지에서 삭제
        if (this.config.useLocalStorage) {
            for (let i = localStorage.length - 1; i >= 0; i--) {
                const key = localStorage.key(i);
                if (key && key.startsWith(prefix)) {
                    localStorage.removeItem(key);
                }
            }
        }
        
        console.log(`💾 카테고리 캐시 삭제: ${category}`);
    }

    /**
     * 모든 캐시 삭제
     */
    clear() {
        // 메모리 캐시 삭제
        this.memoryCache.clear();
        
        // 로컬 스토리지에서 관련 캐시만 삭제
        if (this.config.useLocalStorage) {
            for (let i = localStorage.length - 1; i >= 0; i--) {
                const key = localStorage.key(i);
                if (key && key.startsWith(this.config.prefix)) {
                    localStorage.removeItem(key);
                }
            }
        }
        
        // 통계 초기화
        this.stats = { hits: 0, misses: 0, sets: 0, evictions: 0 };
        
        console.log('💾 모든 캐시 삭제 완료');
    }

    /**
     * 캐시 유효성 검사
     */
    isValid(cached) {
        if (!cached || !cached.timestamp || !cached.ttl) {
            return false;
        }
        
        const age = Date.now() - cached.timestamp;
        return age < cached.ttl;
    }

    /**
     * 만료된 캐시 정리
     */
    cleanupExpiredCache() {
        console.log('🧹 만료된 캐시 정리 시작');
        
        let cleanedCount = 0;
        
        // 메모리 캐시 정리
        for (const [key, cached] of this.memoryCache.entries()) {
            if (!this.isValid(cached)) {
                this.memoryCache.delete(key);
                cleanedCount++;
            }
        }
        
        // 로컬 스토리지 정리
        if (this.config.useLocalStorage) {
            for (let i = localStorage.length - 1; i >= 0; i--) {
                const key = localStorage.key(i);
                if (key && key.startsWith(this.config.prefix)) {
                    try {
                        const stored = localStorage.getItem(key);
                        if (stored) {
                            const cached = JSON.parse(stored);
                            if (!this.isValid(cached)) {
                                localStorage.removeItem(key);
                                cleanedCount++;
                            }
                        }
                    } catch (error) {
                        // 파싱 오류 시 해당 캐시 삭제
                        localStorage.removeItem(key);
                        cleanedCount++;
                    }
                }
            }
        }
        
        console.log(`🧹 만료된 캐시 ${cleanedCount}개 정리 완료`);
    }

    /**
     * 오래된 캐시 정리 (용량 부족 시)
     */
    cleanupOldCache() {
        console.log('🧹 오래된 캐시 정리 시작');
        
        const items = [];
        
        // 로컬 스토리지의 모든 캐시 항목 수집
        for (let i = 0; i < localStorage.length; i++) {
            const key = localStorage.key(i);
            if (key && key.startsWith(this.config.prefix)) {
                try {
                    const stored = localStorage.getItem(key);
                    if (stored) {
                        const cached = JSON.parse(stored);
                        items.push({ key, cached });
                    }
                } catch (error) {
                    // 파싱 오류 시 해당 캐시 삭제
                    localStorage.removeItem(key);
                }
            }
        }
        
        // 타임스탬프 기준으로 정렬 (오래된 것부터)
        items.sort((a, b) => a.cached.timestamp - b.cached.timestamp);
        
        // 오래된 항목의 절반 삭제
        const deleteCount = Math.floor(items.length / 2);
        for (let i = 0; i < deleteCount; i++) {
            localStorage.removeItem(items[i].key);
            this.memoryCache.delete(items[i].key);
        }
        
        console.log(`🧹 오래된 캐시 ${deleteCount}개 정리 완료`);
    }

    /**
     * 최대 항목 수 제한 적용
     */
    enforceMaxItems() {
        if (this.memoryCache.size > this.config.maxItems) {
            const excess = this.memoryCache.size - this.config.maxItems;
            const keys = Array.from(this.memoryCache.keys());
            
            // 오래된 항목부터 삭제
            for (let i = 0; i < excess; i++) {
                this.memoryCache.delete(keys[i]);
                this.stats.evictions++;
            }
            
            console.log(`💾 캐시 크기 제한으로 ${excess}개 항목 제거`);
        }
    }

    /**
     * 전체 키 생성
     */
    getFullKey(key, category) {
        return `${this.config.prefix}${category}_${key}`;
    }

    /**
     * 데이터 크기 추정
     */
    estimateSize(data) {
        try {
            return JSON.stringify(data).length;
        } catch {
            return 0;
        }
    }

    /**
     * 캐시 통계 조회
     */
    getStats() {
        const hitRate = this.stats.hits + this.stats.misses > 0 
            ? (this.stats.hits / (this.stats.hits + this.stats.misses) * 100).toFixed(2)
            : 0;
        
        return {
            ...this.stats,
            hitRate: `${hitRate}%`,
            memoryItems: this.memoryCache.size,
            localStorageItems: this.getLocalStorageItemCount()
        };
    }

    /**
     * 로컬 스토리지 항목 수 조회
     */
    getLocalStorageItemCount() {
        let count = 0;
        for (let i = 0; i < localStorage.length; i++) {
            const key = localStorage.key(i);
            if (key && key.startsWith(this.config.prefix)) {
                count++;
            }
        }
        return count;
    }

    /**
     * 캐시 상태 리포트
     */
    getReport() {
        const stats = this.getStats();
        const memoryUsage = Array.from(this.memoryCache.values())
            .reduce((total, cached) => total + (cached.size || 0), 0);
        
        return {
            stats,
            memoryUsage: `${(memoryUsage / 1024).toFixed(2)} KB`,
            categories: this.getCategoryStats(),
            config: this.config
        };
    }

    /**
     * 카테고리별 통계
     */
    getCategoryStats() {
        const categories = {};
        
        for (const [key, cached] of this.memoryCache.entries()) {
            const category = cached.category || 'default';
            if (!categories[category]) {
                categories[category] = { count: 0, size: 0 };
            }
            categories[category].count++;
            categories[category].size += cached.size || 0;
        }
        
        return categories;
    }
}

// 전역 캐시 매니저 인스턴스
window.cacheManager = new CacheManager();

// 전역으로 내보내기
window.CacheManager = CacheManager;
