/**
 * Media Tag Manager
 * Handles tagging system for photos and videos
 * Supports individual and bulk tagging operations
 */

class MediaTagManager {
    constructor(dataManager) {
        this.dataManager = dataManager;
        this.tags = this.loadTags();
        this.mediaTags = this.loadMediaTags();
        
        console.log('🏷️ MediaTagManager initialized');
    }

    /**
     * Get default tag structure
     */
    getDefaultTagData() {
        return {
            version: '1.0',
            tags: [], // Array of tag objects { id, name, color, createdAt, usageCount }
            mediaTags: {}, // Map of mediaId -> array of tag IDs
            lastUpdated: Date.now()
        };
    }

    /**
     * Load tags from storage
     */
    loadTags() {
        try {
            const data = this.dataManager.get('mediaTags');
            if (data && data.tags) {
                return data.tags;
            }
            return [];
        } catch (error) {
            console.error('Error loading tags:', error);
            return [];
        }
    }

    /**
     * Load media-tag associations from storage
     */
    loadMediaTags() {
        try {
            const data = this.dataManager.get('mediaTags');
            if (data && data.mediaTags) {
                return data.mediaTags;
            }
            return {};
        } catch (error) {
            console.error('Error loading media tags:', error);
            return {};
        }
    }

    /**
     * Save tags to storage
     */
    saveTags() {
        const data = {
            version: '1.0',
            tags: this.tags,
            mediaTags: this.mediaTags,
            lastUpdated: Date.now()
        };
        this.dataManager.set('mediaTags', data);
        console.log('🏷️ Tags saved to storage');
    }

    /**
     * Create a new tag
     * @param {string} name - Tag name
     * @param {string} color - Optional hex color for tag
     * @returns {Object} Created tag object
     */
    createTag(name, color = null) {
        // Sanitize tag name
        const sanitizedName = name.trim().toLowerCase();
        
        if (!sanitizedName) {
            throw new Error('Tag name cannot be empty');
        }

        // Check if tag already exists
        const existing = this.tags.find(tag => tag.name === sanitizedName);
        if (existing) {
            return existing;
        }

        // Generate random color if not provided
        const tagColor = color || this.generateRandomColor();

        // Create new tag
        const tag = {
            id: `tag_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
            name: sanitizedName,
            color: tagColor,
            createdAt: Date.now(),
            usageCount: 0
        };

        this.tags.push(tag);
        this.saveTags();

        console.log(`🏷️ Created new tag: ${name}`);
        return tag;
    }

    /**
     * Delete a tag
     * @param {string} tagId - Tag ID to delete
     * @returns {boolean} Success status
     */
    deleteTag(tagId) {
        const index = this.tags.findIndex(tag => tag.id === tagId);
        if (index === -1) {
            return false;
        }

        // Remove tag from all media
        Object.keys(this.mediaTags).forEach(mediaId => {
            this.mediaTags[mediaId] = this.mediaTags[mediaId].filter(id => id !== tagId);
            if (this.mediaTags[mediaId].length === 0) {
                delete this.mediaTags[mediaId];
            }
        });

        // Remove tag
        this.tags.splice(index, 1);
        this.saveTags();

        console.log(`🏷️ Deleted tag: ${tagId}`);
        return true;
    }

    /**
     * Rename a tag
     * @param {string} tagId - Tag ID to rename
     * @param {string} newName - New tag name
     * @returns {boolean} Success status
     */
    renameTag(tagId, newName) {
        const tag = this.tags.find(t => t.id === tagId);
        if (!tag) {
            return false;
        }

        const sanitizedName = newName.trim().toLowerCase();
        if (!sanitizedName) {
            throw new Error('Tag name cannot be empty');
        }

        // Check if new name already exists (excluding current tag)
        const duplicate = this.tags.find(t => t.name === sanitizedName && t.id !== tagId);
        if (duplicate) {
            throw new Error('A tag with this name already exists');
        }

        tag.name = sanitizedName;
        this.saveTags();

        console.log(`🏷️ Renamed tag ${tagId} to: ${newName}`);
        return true;
    }

    /**
     * Add tag(s) to media item
     * @param {string} mediaId - Media item ID (photo or video path/id)
     * @param {string|Array} tagNames - Single tag name or array of tag names
     * @returns {Array} Array of tag objects that were added
     */
    addTagsToMedia(mediaId, tagNames) {
        if (!mediaId) {
            throw new Error('Media ID is required');
        }

        // Ensure tagNames is an array
        const names = Array.isArray(tagNames) ? tagNames : [tagNames];
        
        // Initialize media tags array if it doesn't exist
        if (!this.mediaTags[mediaId]) {
            this.mediaTags[mediaId] = [];
        }

        const addedTags = [];

        names.forEach(name => {
            // Create tag if it doesn't exist
            const tag = this.createTag(name);

            // Add tag to media if not already present
            if (!this.mediaTags[mediaId].includes(tag.id)) {
                this.mediaTags[mediaId].push(tag.id);
                tag.usageCount++;
                addedTags.push(tag);
            }
        });

        this.saveTags();
        console.log(`🏷️ Added ${addedTags.length} tags to media: ${mediaId}`);
        return addedTags;
    }

    /**
     * Remove tag from media item
     * @param {string} mediaId - Media item ID
     * @param {string} tagId - Tag ID to remove
     * @returns {boolean} Success status
     */
    removeTagFromMedia(mediaId, tagId) {
        if (!this.mediaTags[mediaId]) {
            return false;
        }

        const index = this.mediaTags[mediaId].indexOf(tagId);
        if (index === -1) {
            return false;
        }

        this.mediaTags[mediaId].splice(index, 1);

        // Decrease usage count
        const tag = this.tags.find(t => t.id === tagId);
        if (tag && tag.usageCount > 0) {
            tag.usageCount--;
        }

        // Clean up empty arrays
        if (this.mediaTags[mediaId].length === 0) {
            delete this.mediaTags[mediaId];
        }

        this.saveTags();
        console.log(`🏷️ Removed tag ${tagId} from media: ${mediaId}`);
        return true;
    }

    /**
     * Bulk tag multiple media items
     * @param {Array} mediaIds - Array of media IDs
     * @param {string|Array} tagNames - Tag name(s) to add
     * @returns {Object} Results object with success count
     */
    bulkAddTags(mediaIds, tagNames) {
        if (!Array.isArray(mediaIds) || mediaIds.length === 0) {
            throw new Error('Media IDs array is required');
        }

        let successCount = 0;
        const results = [];

        mediaIds.forEach(mediaId => {
            try {
                const addedTags = this.addTagsToMedia(mediaId, tagNames);
                results.push({ mediaId, success: true, addedTags });
                successCount++;
            } catch (error) {
                results.push({ mediaId, success: false, error: error.message });
            }
        });

        console.log(`🏷️ Bulk tagged ${successCount}/${mediaIds.length} media items`);
        return {
            successCount,
            totalCount: mediaIds.length,
            results
        };
    }

    /**
     * Bulk remove tag from multiple media items
     * @param {Array} mediaIds - Array of media IDs
     * @param {string} tagId - Tag ID to remove
     * @returns {Object} Results object with success count
     */
    bulkRemoveTag(mediaIds, tagId) {
        if (!Array.isArray(mediaIds) || mediaIds.length === 0) {
            throw new Error('Media IDs array is required');
        }

        let successCount = 0;

        mediaIds.forEach(mediaId => {
            if (this.removeTagFromMedia(mediaId, tagId)) {
                successCount++;
            }
        });

        console.log(`🏷️ Bulk removed tag from ${successCount}/${mediaIds.length} media items`);
        return {
            successCount,
            totalCount: mediaIds.length
        };
    }

    /**
     * Get all tags for a media item
     * @param {string} mediaId - Media item ID
     * @returns {Array} Array of tag objects
     */
    getTagsForMedia(mediaId) {
        if (!this.mediaTags[mediaId]) {
            return [];
        }

        return this.mediaTags[mediaId]
            .map(tagId => this.tags.find(tag => tag.id === tagId))
            .filter(tag => tag !== undefined);
    }

    /**
     * Get all media items with a specific tag
     * @param {string} tagId - Tag ID
     * @returns {Array} Array of media IDs
     */
    getMediaWithTag(tagId) {
        const mediaIds = [];

        Object.keys(this.mediaTags).forEach(mediaId => {
            if (this.mediaTags[mediaId].includes(tagId)) {
                mediaIds.push(mediaId);
            }
        });

        return mediaIds;
    }

    /**
     * Get media items that match ALL specified tags (AND logic)
     * @param {Array} tagIds - Array of tag IDs
     * @returns {Array} Array of media IDs
     */
    getMediaWithAllTags(tagIds) {
        if (!Array.isArray(tagIds) || tagIds.length === 0) {
            return [];
        }

        const mediaIds = [];

        Object.keys(this.mediaTags).forEach(mediaId => {
            const mediaTags = this.mediaTags[mediaId];
            const hasAllTags = tagIds.every(tagId => mediaTags.includes(tagId));
            if (hasAllTags) {
                mediaIds.push(mediaId);
            }
        });

        return mediaIds;
    }

    /**
     * Get media items that match ANY specified tags (OR logic)
     * @param {Array} tagIds - Array of tag IDs
     * @returns {Array} Array of media IDs
     */
    getMediaWithAnyTags(tagIds) {
        if (!Array.isArray(tagIds) || tagIds.length === 0) {
            return [];
        }

        const mediaIds = new Set();

        Object.keys(this.mediaTags).forEach(mediaId => {
            const mediaTags = this.mediaTags[mediaId];
            const hasAnyTag = tagIds.some(tagId => mediaTags.includes(tagId));
            if (hasAnyTag) {
                mediaIds.add(mediaId);
            }
        });

        return Array.from(mediaIds);
    }

    /**
     * Search tags by name
     * @param {string} query - Search query
     * @returns {Array} Array of matching tags
     */
    searchTags(query) {
        const lowerQuery = query.toLowerCase().trim();
        if (!lowerQuery) {
            return this.getAllTags();
        }

        return this.tags.filter(tag => tag.name.includes(lowerQuery));
    }

    /**
     * Get all tags
     * @returns {Array} Array of all tag objects
     */
    getAllTags() {
        return [...this.tags];
    }

    /**
     * Get all media IDs that have at least one tag
     * @returns {Array} Array of media IDs
     */
    getAllMediaWithTags() {
        return Object.keys(this.mediaTags).filter(mediaId => {
            const tags = this.mediaTags[mediaId];
            return tags && tags.length > 0;
        });
    }

    /**
     * Get tag statistics
     * @returns {Object} Statistics object
     */
    getStatistics() {
        const totalTags = this.tags.length;
        const totalTaggedMedia = Object.keys(this.mediaTags).length;
        const mostUsedTags = [...this.tags]
            .sort((a, b) => b.usageCount - a.usageCount)
            .slice(0, 10);

        return {
            totalTags,
            totalTaggedMedia,
            mostUsedTags,
            averageTagsPerMedia: totalTaggedMedia > 0 
                ? Object.values(this.mediaTags).reduce((sum, tags) => sum + tags.length, 0) / totalTaggedMedia 
                : 0
        };
    }

    /**
     * Generate random color for tag
     * @returns {string} Hex color code
     */
    generateRandomColor() {
        const colors = [
            '#FF6B6B', '#4ECDC4', '#45B7D1', '#FFA07A', '#98D8C8',
            '#F7DC6F', '#BB8FCE', '#85C1E2', '#F8B88B', '#FAD7A0',
            '#AED6F1', '#A9DFBF', '#F9E79F', '#EDBB99', '#D7BDE2',
            '#A3E4D7', '#F5B7B1', '#D5F4E6', '#FADBD8', '#E8DAEF'
        ];
        return colors[Math.floor(Math.random() * colors.length)];
    }

    /**
     * Export tags data
     * @returns {Object} Exportable tags data
     */
    exportTags() {
        return {
            version: '1.0',
            tags: this.tags,
            mediaTags: this.mediaTags,
            exportedAt: Date.now()
        };
    }

    /**
     * Import tags data
     * @param {Object} data - Tags data to import
     * @param {boolean} merge - Whether to merge with existing tags or replace
     * @returns {Object} Import results
     */
    importTags(data, merge = true) {
        if (!data || !data.tags) {
            throw new Error('Invalid import data');
        }

        let importedTags = 0;
        let importedAssociations = 0;

        if (merge) {
            // Merge tags
            data.tags.forEach(importTag => {
                const existing = this.tags.find(t => t.name === importTag.name);
                if (!existing) {
                    this.tags.push(importTag);
                    importedTags++;
                }
            });

            // Merge media associations
            Object.keys(data.mediaTags).forEach(mediaId => {
                if (!this.mediaTags[mediaId]) {
                    this.mediaTags[mediaId] = [];
                }
                
                data.mediaTags[mediaId].forEach(tagId => {
                    if (!this.mediaTags[mediaId].includes(tagId)) {
                        this.mediaTags[mediaId].push(tagId);
                        importedAssociations++;
                    }
                });
            });
        } else {
            // Replace all data
            this.tags = data.tags;
            this.mediaTags = data.mediaTags;
            importedTags = data.tags.length;
            importedAssociations = Object.keys(data.mediaTags).length;
        }

        this.saveTags();

        console.log(`🏷️ Imported ${importedTags} tags and ${importedAssociations} associations`);
        return {
            importedTags,
            importedAssociations,
            merge
        };
    }

    /**
     * Clear all tags and associations
     * @param {boolean} confirm - Confirmation flag
     */
    clearAllTags(confirm = false) {
        if (!confirm) {
            throw new Error('Confirmation required to clear all tags');
        }

        this.tags = [];
        this.mediaTags = {};
        this.saveTags();

        console.log('🏷️ All tags cleared');
    }

    /**
     * Get tag by ID
     * @param {string} tagId - Tag ID
     * @returns {Object|null} Tag object or null
     */
    getTagById(tagId) {
        return this.tags.find(tag => tag.id === tagId) || null;
    }

    /**
     * Get tag by name
     * @param {string} name - Tag name
     * @returns {Object|null} Tag object or null
     */
    getTagByName(name) {
        const sanitizedName = name.trim().toLowerCase();
        return this.tags.find(tag => tag.name === sanitizedName) || null;
    }

    /**
     * Update tag color
     * @param {string} tagId - Tag ID
     * @param {string} color - New hex color
     * @returns {boolean} Success status
     */
    updateTagColor(tagId, color) {
        const tag = this.tags.find(t => t.id === tagId);
        if (!tag) {
            return false;
        }

        tag.color = color;
        this.saveTags();

        console.log(`🏷️ Updated tag color for ${tagId}`);
        return true;
    }
}

// Make available globally
if (typeof window !== 'undefined') {
    window.MediaTagManager = MediaTagManager;
}
