/**
 * AniWorld - Series Manager Module
 *
 * Manages series data, filtering, sorting, and rendering.
 *
 * Dependencies: constants.js, api-client.js, ui-utils.js
 */

var AniWorld = window.AniWorld || {};

AniWorld.SeriesManager = (function() {
    'use strict';

    const API = AniWorld.Constants.API;

    // State
    let seriesData = [];
    let filteredSeriesData = [];
    let filterMode = 'all'; // 'all' | 'missing_episodes' | 'no_episodes'
    let sortAlphabetical = false;

    /**
     * Initialize the series manager
     */
    function init() {
        bindEvents();
        updateFilterButtonUI();
    }

    /**
     * Bind UI events for filtering and sorting
     */
    function bindEvents() {
        const filterBtn = document.getElementById('show-missing-only');
        if (filterBtn) {
            filterBtn.addEventListener('click', toggleFilterMode);
        }

        const sortBtn = document.getElementById('sort-alphabetical');
        if (sortBtn) {
            sortBtn.addEventListener('click', toggleAlphabeticalSort);
        }
    }

    /**
     * Load series from API
     * @returns {Promise<Array>} Array of series data
     */
    async function loadSeries() {
        try {
            AniWorld.UI.showLoading();

            const url = filterMode && filterMode !== 'all'
                ? `${API.ANIME_LIST}?filter=${encodeURIComponent(filterMode)}`
                : API.ANIME_LIST;
            const response = await AniWorld.ApiClient.get(url);

            if (!response) {
                return [];
            }

            const data = await response.json();

            // Check if response has the expected format
            if (Array.isArray(data)) {
                // API returns array of AnimeSummary objects
                seriesData = data.map(function(anime) {
                    // Count total missing episodes from the episode dictionary
                    const episodeDict = anime.missing_episodes || {};
                    const totalMissing = Object.values(episodeDict).reduce(
                        function(sum, episodes) {
                            return sum + (Array.isArray(episodes) ? episodes.length : 0);
                        },
                        0
                    );

                    return {
                        key: anime.key,
                        name: anime.name,
                        site: anime.site,
                        folder: anime.folder,
                        episodeDict: episodeDict,
                        missing_episodes: totalMissing,
                        has_missing: anime.has_missing || totalMissing > 0,
                        has_nfo: anime.has_nfo || false,
                        nfo_created_at: anime.nfo_created_at || null,
                        nfo_updated_at: anime.nfo_updated_at || null,
                        tmdb_id: anime.tmdb_id || null,
                        tvdb_id: anime.tvdb_id || null,
                        loading_status: anime.loading_status || 'completed',
                        episodes_loaded: anime.episodes_loaded !== false,
                        nfo_loaded: anime.nfo_loaded !== false,
                        logo_loaded: anime.logo_loaded !== false,
                        images_loaded: anime.images_loaded !== false
                    };
                });
            } else if (data.status === 'success') {
                // Legacy format support
                seriesData = data.series;
            } else {
                AniWorld.UI.showToast('Error loading series: ' + (data.message || 'Unknown error'), 'error');
                return [];
            }

            applyFiltersAndSort();
            renderSeries();
            return seriesData;
        } catch (error) {
            console.error('Error loading series:', error);
            AniWorld.UI.showToast('Failed to load series', 'error');
            return [];
        } finally {
            AniWorld.UI.hideLoading();
        }
    }

    /**
     * Cycle through filter modes:
     *   - all: Show all series
     *   - missing_episodes: Show only series with missing episodes
     *   - no_episodes: Show only series with zero downloaded episodes
     */
    async function toggleFilterMode() {
        const button = document.getElementById('show-missing-only');
        const icon = button.querySelector('i');
        const text = button.querySelector('span');

        // Cycle through modes
        if (filterMode === 'all') {
            filterMode = 'missing_episodes';
        } else if (filterMode === 'missing_episodes') {
            filterMode = 'no_episodes';
        } else {
            filterMode = 'all';
        }

        // Update button UI and reload list based on new filter.
        updateFilterButtonUI();
        await loadSeries();

        // Clear selection when filter changes
        if (AniWorld.SelectionManager) {
            AniWorld.SelectionManager.clearSelection();
        }
    }

    /**
     * Update the filter button UI to reflect current filter mode
     */
    function updateFilterButtonUI() {
        const button = document.getElementById('show-missing-only');
        if (!button) {
            return;
        }

        const icon = button.querySelector('i');
        const text = button.querySelector('span');

        const isActive = filterMode !== 'all';
        button.setAttribute('data-active', isActive);
        button.classList.toggle('active', isActive);

        if (filterMode === 'missing_episodes') {
            icon.className = 'fas fa-filter';
            text.textContent = 'Missing Episodes Only';
        } else if (filterMode === 'no_episodes') {
            icon.className = 'fas fa-ban';
            text.textContent = 'No Episodes';
        } else {
            icon.className = 'fas fa-filter-circle-xmark';
            text.textContent = 'Show All Series';
        }
    }

    /**
     * Toggle alphabetical sorting
     */
    function toggleAlphabeticalSort() {
        sortAlphabetical = !sortAlphabetical;
        const button = document.getElementById('sort-alphabetical');

        button.setAttribute('data-active', sortAlphabetical);
        button.classList.toggle('active', sortAlphabetical);

        const icon = button.querySelector('i');
        const text = button.querySelector('span');

        if (sortAlphabetical) {
            icon.className = 'fas fa-sort-alpha-up';
            text.textContent = 'Default Sort';
        } else {
            icon.className = 'fas fa-sort-alpha-down';
            text.textContent = 'A-Z Sort';
        }

        applyFiltersAndSort();
        renderSeries();
    }

    /**
     * Apply current filters and sorting to series data
     */
    function applyFiltersAndSort() {
        let filtered = seriesData.slice();

        // Apply client-side filter so that real-time WebSocket updates
        // (e.g. an episode being marked downloaded) are immediately
        // reflected without a full server reload.
        if (filterMode === 'missing_episodes') {
            filtered = filtered.filter(function(s) {
                return s.missing_episodes > 0;
            });
        }
        // 'no_episodes' filter state is maintained server-side;
        // don't try to replicate it client-side here.

        // Sort based on the current sorting mode
        filtered.sort(function(a, b) {
            if (sortAlphabetical) {
                // Pure alphabetical sorting
                return AniWorld.UI.getDisplayName(a).localeCompare(AniWorld.UI.getDisplayName(b));
            } else {
                // Default sorting: missing episodes first (descending), then by name
                if (a.missing_episodes > 0 && b.missing_episodes === 0) return -1;
                if (a.missing_episodes === 0 && b.missing_episodes > 0) return 1;

                // If both have missing episodes, sort by count (descending)
                if (a.missing_episodes > 0 && b.missing_episodes > 0) {
                    if (a.missing_episodes !== b.missing_episodes) {
                        return b.missing_episodes - a.missing_episodes;
                    }
                }

                // For series with same missing episode status, maintain stable order
                return 0;
            }
        });

        filteredSeriesData = filtered;
    }

    /**
     * Render series cards in the grid
     */
    function renderSeries() {
        const grid = document.getElementById('series-grid');
        // Always use filteredSeriesData — applyFiltersAndSort() is always
        // called before renderSeries(), so filteredSeriesData is current.
        // The old fallback to seriesData was incorrect: when a filter is
        // active and filteredSeriesData is empty it must show the empty-state
        // message, not fall through to unfiltered seriesData.
        const dataToRender = filteredSeriesData;

        if (dataToRender.length === 0) {
            let message;
            if (filterMode === 'missing_episodes') {
                message = 'No series with missing episodes found.';
            } else if (filterMode === 'no_episodes') {
                message = 'No series with zero downloaded episodes found.';
            } else {
                message = 'No series found. Try searching for anime or rescanning your directory.';
            }

            grid.innerHTML =
                '<div class="text-center" style="grid-column: 1 / -1; padding: 2rem;">' +
                '<i class="fas fa-tv" style="font-size: 48px; color: var(--color-text-tertiary); margin-bottom: 1rem;"></i>' +
                '<p style="color: var(--color-text-secondary);">' + message + '</p>' +
                '</div>';
            return;
        }

        grid.innerHTML = dataToRender.map(function(serie) {
            return createSerieCard(serie);
        }).join('');

        // Bind checkbox events
        grid.querySelectorAll('.series-checkbox').forEach(function(checkbox) {
            checkbox.addEventListener('change', function(e) {
                if (AniWorld.SelectionManager) {
                    AniWorld.SelectionManager.toggleSerieSelection(e.target.dataset.key, e.target.checked);
                }
            });
        });

    }

    /**
     * Get loading indicator HTML for a series
     * @param {Object} serie - Series data object
     * @returns {string} HTML string
     */
    function getLoadingIndicatorHTML(serie) {
        const statusMessages = {
            'pending': 'Queued for loading...',
            'loading_episodes': 'Loading episodes...',
            'loading_nfo': 'Generating NFO metadata...',
            'loading_logo': 'Downloading logo...',
            'loading_images': 'Downloading images...'
        };

        const statusMessage = statusMessages[serie.loading_status] || 'Loading...';

        return '<div class="loading-indicator">' +
            '<div class="loading-status">' +
            '<span class="status-text"><i class="fas fa-spinner fa-spin"></i> ' + statusMessage + '</span>' +
            '<div class="progress-items">' +
            getProgressItemsHTML(serie) +
            '</div>' +
            '</div>' +
            '</div>';
    }

    /**
     * Get progress items HTML
     * @param {Object} serie - Series data object
     * @returns {string} HTML string
     */
    function getProgressItemsHTML(serie) {
        const items = [
            { key: 'episodes_loaded', label: 'Episodes' },
            { key: 'nfo_loaded', label: 'NFO' },
            { key: 'logo_loaded', label: 'Logo' },
            { key: 'images_loaded', label: 'Images' }
        ];

        return items.map(function(item) {
            const isLoaded = serie[item.key];
            return '<div class="progress-item ' + (isLoaded ? 'completed' : 'pending') + '">' +
                '<span class="icon">' + (isLoaded ? '✓' : '⋯') + '</span>' +
                '<span class="label">' + item.label + '</span>' +
                '</div>';
        }).join('');
    }

    /**
     * Create HTML for a series card
     * @param {Object} serie - Series data object
     * @returns {string} HTML string
     */
    function createSerieCard(serie) {
        const isSelected = AniWorld.SelectionManager ? AniWorld.SelectionManager.isSelected(serie.key) : false;
        const hasMissingEpisodes = serie.missing_episodes > 0;
        const canBeSelected = hasMissingEpisodes;
        const hasNfo = serie.has_nfo || false;
        const isLoading = serie.loading_status && serie.loading_status !== 'completed' && serie.loading_status !== 'failed';
        
        // Debug logging for troubleshooting
        if (serie.key === 'so-im-a-spider-so-what') {
            console.log('[createSerieCard] Spider series:', {
                key: serie.key,
                missing_episodes: serie.missing_episodes,
                missing_episodes_type: typeof serie.missing_episodes,
                episodeDict: serie.episodeDict,
                hasMissingEpisodes: hasMissingEpisodes,
                has_missing: serie.has_missing
            });
        }

        return '<div class="series-card ' + (isSelected ? 'selected' : '') + ' ' +
            (hasMissingEpisodes ? 'has-missing' : 'complete') + ' ' +
            (isLoading ? 'loading' : '') + '" ' +
            'data-key="' + serie.key + '" data-series-id="' + serie.key + '" data-folder="' + serie.folder + '">' +
            '<div class="series-card-header">' +
            '<input type="checkbox" class="series-checkbox" data-key="' + serie.key + '"' +
            (isSelected ? ' checked' : '') + (canBeSelected ? '' : ' disabled') + '>' +
            '<div class="series-info">' +
            '<h3>' + AniWorld.UI.escapeHtml(AniWorld.UI.getDisplayName(serie)) + '</h3>' +
            '<div class="series-folder">' + AniWorld.UI.escapeHtml(serie.folder) + '</div>' +
            '</div>' +
            '<div class="series-status">' +
            (hasMissingEpisodes ? '' : '<i class="fas fa-check-circle status-complete" title="Complete"></i>') +
            (hasNfo ? '<i class="fas fa-file-alt nfo-badge nfo-exists" title="NFO metadata available"></i>' :
                '<i class="fas fa-file-alt nfo-badge nfo-missing" title="No NFO metadata"></i>') +
            '</div>' +
            '</div>' +
            '<div class="series-stats">' +
            '<div class="missing-episodes ' + (hasMissingEpisodes ? 'has-missing' : 'complete') + '">' +
            '<i class="fas ' + (hasMissingEpisodes ? 'fa-exclamation-triangle' : 'fa-check') + '"></i>' +
            '<span>' + (hasMissingEpisodes ? serie.missing_episodes + ' missing episodes' : 'Complete') + '</span>' +
            '</div>' +
            '<span class="series-site">' + serie.site + '</span>' +
            '</div>' +
            (isLoading ? getLoadingIndicatorHTML(serie) : '') +
            '</div>';
    }

    /**
     * Get all series data
     * @returns {Array} Series data array
     */
    function getSeriesData() {
        return seriesData;
    }

    /**
     * Update a series key in the local data arrays after rename.
     * @param {string} oldKey - The previous key
     * @param {string} newKey - The new key
     */
    function updateSeriesKey(oldKey, newKey) {
        if (seriesData) {
            var s = seriesData.find(function(item) { return item.key === oldKey; });
            if (s) s.key = newKey;
        }
        if (filteredSeriesData) {
            var fs = filteredSeriesData.find(function(item) { return item.key === oldKey; });
            if (fs) fs.key = newKey;
        }
    }

    /**
     * Get filtered series data
     * @returns {Array} Filtered series data array
     */
    function getFilteredSeriesData() {
        return filteredSeriesData;
    }

    /**
     * Find a series by key
     * @param {string} key - Series key
     * @returns {Object|undefined} Series object or undefined
     */
    function findByKey(key) {
        return seriesData.find(function(s) {
            return s.key === key;
        });
    }

    /**
     * Update series loading status from WebSocket event
     * @param {Object} data - Loading status data
     */
    function updateSeriesLoadingStatus(data) {
        const seriesKey = data.series_id || data.series_key;
        if (!seriesKey) return;

        // Find series in data
        const serie = findByKey(seriesKey);
        if (!serie) return;

        // Update series data
        serie.loading_status = data.status || data.loading_status;
        if (data.progress) {
            serie.episodes_loaded = data.progress.episodes || false;
            serie.nfo_loaded = data.progress.nfo || false;
            serie.logo_loaded = data.progress.logo || false;
            serie.images_loaded = data.progress.images || false;
        }

        // Update the specific card in the DOM
        const seriesCard = document.querySelector('[data-series-id="' + seriesKey + '"]');
        if (seriesCard) {
            // If loading completed, reload to get fresh data
            if (data.status === 'completed') {
                loadSeries();
            } else {
                // Update loading indicator
                const loadingIndicator = seriesCard.querySelector('.loading-indicator');
                if (loadingIndicator) {
                    loadingIndicator.innerHTML = '<div class="loading-status">' +
                        '<span class="status-text"><i class="fas fa-spinner fa-spin"></i> ' +
                        (data.message || 'Loading...') + '</span>' +
                        '<div class="progress-items">' +
                        getProgressItemsHTML(serie) +
                        '</div>' +
                        '</div>';
                } else if (serie.loading_status !== 'completed' && serie.loading_status !== 'failed') {
                    // Add loading indicator if it doesn't exist
                    const statsDiv = seriesCard.querySelector('.series-stats');
                    if (statsDiv) {
                        statsDiv.insertAdjacentHTML('afterend', getLoadingIndicatorHTML(serie));
                    }
                }

                // Add loading class to card
                seriesCard.classList.add('loading');
            }
        }
    }

    /**
     * Update a single series from WebSocket data
     * @param {Object} updatedData - Updated series data from WebSocket
     */
    function updateSingleSeries(updatedData) {
        if (!updatedData || !updatedData.key) {
            console.warn('Invalid series update data:', updatedData);
            return;
        }

        console.log('[updateSingleSeries] Received data:', updatedData);
        console.log('[updateSingleSeries] missing_episodes type:', typeof updatedData.missing_episodes);
        console.log('[updateSingleSeries] missing_episodes value:', updatedData.missing_episodes);

        // Count total missing episodes from the episode dictionary
        const episodeDict = updatedData.missing_episodes || {};
        console.log('[updateSingleSeries] episodeDict:', episodeDict);
        
        const totalMissing = Object.values(episodeDict).reduce(
            function(sum, episodes) {
                return sum + (Array.isArray(episodes) ? episodes.length : 0);
            },
            0
        );
        
        console.log('[updateSingleSeries] totalMissing calculated:', totalMissing);

        // Transform WebSocket data to match our internal format
        const transformedSerie = {
            key: updatedData.key,
            name: updatedData.name,
            site: updatedData.site || 'aniworld.to',
            folder: updatedData.folder,
            episodeDict: episodeDict,
            missing_episodes: totalMissing,
            has_missing: updatedData.has_missing || totalMissing > 0,
            has_nfo: updatedData.has_nfo || false,
            nfo_created_at: updatedData.nfo_created_at || null,
            nfo_updated_at: updatedData.nfo_updated_at || null,
            tmdb_id: updatedData.tmdb_id || null,
            tvdb_id: updatedData.tvdb_id || null,
            loading_status: updatedData.loading_status || 'completed',
            episodes_loaded: updatedData.episodes_loaded !== false,
            nfo_loaded: updatedData.nfo_loaded !== false,
            logo_loaded: updatedData.logo_loaded !== false,
            images_loaded: updatedData.images_loaded !== false
        };
        
        console.log('[updateSingleSeries] Transformed serie:', transformedSerie);

        // Find existing series in our data
        const existingIndex = seriesData.findIndex(function(s) {
            return s.key === updatedData.key;
        });

        if (existingIndex >= 0) {
            // Update existing series
            seriesData[existingIndex] = transformedSerie;
            console.log('Updated existing series:', updatedData.key, transformedSerie);
        } else {
            // Add new series
            seriesData.push(transformedSerie);
            console.log('Added new series:', updatedData.key, transformedSerie);
        }

        // Reapply filters and re-render
        applyFiltersAndSort();
        renderSeries();
    }

    // Public API
    return {
        init: init,
        loadSeries: loadSeries,
        renderSeries: renderSeries,
        applyFiltersAndSort: applyFiltersAndSort,
        getSeriesData: getSeriesData,
        getFilteredSeriesData: getFilteredSeriesData,
        findByKey: findByKey,
        updateSeriesLoadingStatus: updateSeriesLoadingStatus,
        updateSingleSeries: updateSingleSeries,
        updateSeriesKey: updateSeriesKey
    };
})();
