/**
 * EasyStream API Helper
 * Modern fetch-based API client with JWT token management
 */
class EasyStreamAPI {
    constructor(baseURL = '/api') {
        this.baseURL = baseURL;
        this.token = this.getStoredToken();
        this.tokenExpiry = this.getStoredTokenExpiry();
    }

    /**
     * Store JWT token in localStorage
     * @param {string} token JWT token
     * @param {number} expiresIn Expiry time in seconds
     */
    setToken(token, expiresIn = 86400) {
        this.token = token;
        this.tokenExpiry = Date.now() + (expiresIn * 1000);

        if (typeof localStorage !== 'undefined') {
            localStorage.setItem('jwt_token', token);
            localStorage.setItem('jwt_expiry', this.tokenExpiry.toString());
        }
    }

    /**
     * Get stored token from localStorage
     * @returns {string|null}
     */
    getStoredToken() {
        if (typeof localStorage === 'undefined') return null;

        const expiry = localStorage.getItem('jwt_expiry');
        if (expiry && Date.now() > parseInt(expiry)) {
            // Token expired, clear it
            this.clearToken();
            return null;
        }

        return localStorage.getItem('jwt_token');
    }

    /**
     * Get stored token expiry
     * @returns {number|null}
     */
    getStoredTokenExpiry() {
        if (typeof localStorage === 'undefined') return null;
        const expiry = localStorage.getItem('jwt_expiry');
        return expiry ? parseInt(expiry) : null;
    }

    /**
     * Clear stored token
     */
    clearToken() {
        this.token = null;
        this.tokenExpiry = null;

        if (typeof localStorage !== 'undefined') {
            localStorage.removeItem('jwt_token');
            localStorage.removeItem('jwt_expiry');
        }
    }

    /**
     * Check if user is authenticated
     * @returns {boolean}
     */
    isAuthenticated() {
        if (!this.token) return false;
        if (this.tokenExpiry && Date.now() > this.tokenExpiry) {
            this.clearToken();
            return false;
        }
        return true;
    }

    /**
     * Get authorization headers
     * @returns {Object}
     */
    getAuthHeaders() {
        const headers = {
            'Content-Type': 'application/json',
            'Accept': 'application/json'
        };

        if (this.token) {
            headers['Authorization'] = `Bearer ${this.token}`;
        }

        return headers;
    }

    /**
     * Make API request
     * @param {string} endpoint API endpoint
     * @param {Object} options Fetch options
     * @returns {Promise<Object>}
     */
    async request(endpoint, options = {}) {
        const url = endpoint.startsWith('http') ? endpoint : `${this.baseURL}${endpoint}`;

        const config = {
            ...options,
            headers: {
                ...this.getAuthHeaders(),
                ...options.headers
            }
        };

        try {
            const response = await fetch(url, config);

            // Handle different response types
            const contentType = response.headers.get('content-type');
            let data;

            if (contentType && contentType.includes('application/json')) {
                data = await response.json();
            } else {
                data = await response.text();
            }

            if (!response.ok) {
                // Handle authentication errors
                if (response.status === 401) {
                    this.clearToken();
                    throw new Error(data.message || 'Authentication failed');
                }

                throw new Error(data.message || `Request failed with status ${response.status}`);
            }

            return data;

        } catch (error) {
            console.error('API request failed:', error);
            throw error;
        }
    }

    /**
     * GET request
     * @param {string} endpoint API endpoint
     * @param {Object} params Query parameters
     * @returns {Promise<Object>}
     */
    async get(endpoint, params = {}) {
        const queryString = new URLSearchParams(params).toString();
        const url = queryString ? `${endpoint}?${queryString}` : endpoint;

        return this.request(url, {
            method: 'GET'
        });
    }

    /**
     * POST request
     * @param {string} endpoint API endpoint
     * @param {Object} data Request body
     * @returns {Promise<Object>}
     */
    async post(endpoint, data = {}) {
        return this.request(endpoint, {
            method: 'POST',
            body: JSON.stringify(data)
        });
    }

    /**
     * PUT request
     * @param {string} endpoint API endpoint
     * @param {Object} data Request body
     * @returns {Promise<Object>}
     */
    async put(endpoint, data = {}) {
        return this.request(endpoint, {
            method: 'PUT',
            body: JSON.stringify(data)
        });
    }

    /**
     * DELETE request
     * @param {string} endpoint API endpoint
     * @returns {Promise<Object>}
     */
    async delete(endpoint) {
        return this.request(endpoint, {
            method: 'DELETE'
        });
    }

    // ===== Authentication Methods =====

    /**
     * Login with JWT token
     * @param {string} identifier Username or email
     * @param {string} password Password
     * @param {number} expiresIn Optional token expiry in seconds
     * @returns {Promise<Object>}
     */
    async login(identifier, password, expiresIn = null) {
        try {
            const data = await this.post('/auth.php?action=login_token', {
                identifier,
                password,
                expires_in: expiresIn
            });

            if (data.success && data.token) {
                this.setToken(data.token, data.expires_in || 86400);
            }

            return data;

        } catch (error) {
            console.error('Login failed:', error);
            throw error;
        }
    }

    /**
     * Logout and clear token
     * @returns {Promise<Object>}
     */
    async logout() {
        try {
            // Optionally call backend logout endpoint
            // (though with JWT, client-side token removal is usually sufficient)
            const data = await this.post('/auth.php?action=logout', {});
            this.clearToken();
            return data;

        } catch (error) {
            // Clear token even if API call fails
            this.clearToken();
            throw error;
        }
    }

    /**
     * Get current user info
     * @returns {Promise<Object>}
     */
    async getCurrentUser() {
        if (!this.isAuthenticated()) {
            throw new Error('Not authenticated');
        }

        return this.get('/auth.php?action=verify_token');
    }

    /**
     * Verify token validity
     * @returns {Promise<boolean>}
     */
    async verifyToken() {
        if (!this.token) return false;

        try {
            const data = await this.get('/auth.php?action=verify_token');
            return data.success && data.valid;
        } catch (error) {
            this.clearToken();
            return false;
        }
    }

    // ===== Video API Methods =====

    /**
     * Get videos list
     * @param {Object} params Query parameters (page, limit, sort, etc.)
     * @returns {Promise<Object>}
     */
    async getVideos(params = {}) {
        return this.get('/videos.php', params);
    }

    /**
     * Get video by ID
     * @param {string} videoId Video ID
     * @returns {Promise<Object>}
     */
    async getVideo(videoId) {
        return this.get(`/videos.php?id=${videoId}`);
    }

    /**
     * Upload video metadata
     * @param {Object} videoData Video metadata
     * @returns {Promise<Object>}
     */
    async createVideo(videoData) {
        return this.post('/videos.php', videoData);
    }

    /**
     * Update video
     * @param {string} videoId Video ID
     * @param {Object} videoData Updated video data
     * @returns {Promise<Object>}
     */
    async updateVideo(videoId, videoData) {
        return this.put(`/videos.php?id=${videoId}`, videoData);
    }

    /**
     * Delete video
     * @param {string} videoId Video ID
     * @returns {Promise<Object>}
     */
    async deleteVideo(videoId) {
        return this.delete(`/videos.php?id=${videoId}`);
    }

    /**
     * Search videos
     * @param {string} query Search query
     * @param {Object} params Additional parameters
     * @returns {Promise<Object>}
     */
    async searchVideos(query, params = {}) {
        return this.get('/videos.php', { action: 'search', q: query, ...params });
    }

    /**
     * Like/unlike video
     * @param {string} fileKey Video file key
     * @param {string} likeType 'like' or 'dislike'
     * @returns {Promise<Object>}
     */
    async likeVideo(fileKey, likeType = 'like') {
        return this.post('/videos.php?action=like', { file_key: fileKey, like_type: likeType });
    }

    /**
     * Increment video view count
     * @param {string} fileKey Video file key
     * @returns {Promise<Object>}
     */
    async recordVideoView(fileKey) {
        return this.post('/videos.php?action=view', { file_key: fileKey });
    }

    /**
     * Add/remove video from watch later
     * @param {string} fileKey Video file key
     * @returns {Promise<Object>}
     */
    async toggleWatchLater(fileKey) {
        return this.post('/videos.php?action=watch_later', { file_key: fileKey });
    }

    // ===== User API Methods =====

    /**
     * Get user profile
     * @param {string} userId User ID (optional, defaults to current user)
     * @returns {Promise<Object>}
     */
    async getUserProfile(userId = null) {
        if (userId) {
            return this.get(`/user.php?id=${userId}`);
        }
        return this.get('/user.php?action=profile');
    }

    /**
     * Get current user's profile (alias)
     * @returns {Promise<Object>}
     */
    async getMyProfile() {
        return this.get('/user.php?action=me');
    }

    /**
     * Update user profile
     * @param {Object} userData Updated user data
     * @returns {Promise<Object>}
     */
    async updateProfile(userData) {
        return this.put('/user.php', userData);
    }

    /**
     * Upload user avatar
     * @param {File} file Avatar file
     * @returns {Promise<Object>}
     */
    async uploadAvatar(file) {
        const formData = new FormData();
        formData.append('avatar', file);

        return this.request('/user.php?action=avatar', {
            method: 'POST',
            headers: {
                'Authorization': `Bearer ${this.token}`
            },
            body: formData
        });
    }

    /**
     * Get user statistics
     * @returns {Promise<Object>}
     */
    async getUserStats() {
        return this.get('/user.php?action=stats');
    }

    /**
     * Get user's videos
     * @param {number} userId User ID (optional)
     * @param {Object} params Query parameters
     * @returns {Promise<Object>}
     */
    async getUserVideos(userId = null, params = {}) {
        const queryParams = userId ? { ...params, id: userId } : params;
        return this.get('/user.php?action=videos', queryParams);
    }

    /**
     * Get user's subscriptions
     * @returns {Promise<Object>}
     */
    async getUserSubscriptions() {
        return this.get('/user.php?action=subscriptions');
    }

    /**
     * Get user's subscribers
     * @param {number} userId User ID (optional)
     * @returns {Promise<Object>}
     */
    async getUserSubscribers(userId = null) {
        const params = userId ? { id: userId } : {};
        return this.get('/user.php?action=subscribers', params);
    }

    // ===== Comments API Methods =====

    /**
     * Get comments for a video
     * @param {string} fileKey Video file key
     * @param {Object} params Query parameters
     * @returns {Promise<Object>}
     */
    async getComments(fileKey, params = {}) {
        return this.get('/comments.php', { file_key: fileKey, ...params });
    }

    /**
     * Get single comment with replies
     * @param {number} commentId Comment ID
     * @returns {Promise<Object>}
     */
    async getComment(commentId) {
        return this.get(`/comments.php?id=${commentId}`);
    }

    /**
     * Create new comment
     * @param {string} fileKey Video file key
     * @param {string} commentText Comment text
     * @param {number} parentId Parent comment ID (for replies)
     * @returns {Promise<Object>}
     */
    async createComment(fileKey, commentText, parentId = null) {
        return this.post('/comments.php?action=create', {
            file_key: fileKey,
            comment_text: commentText,
            parent_id: parentId
        });
    }

    /**
     * Update comment
     * @param {number} commentId Comment ID
     * @param {string} commentText Updated text
     * @returns {Promise<Object>}
     */
    async updateComment(commentId, commentText) {
        return this.put(`/comments.php?id=${commentId}`, {
            comment_text: commentText
        });
    }

    /**
     * Delete comment
     * @param {number} commentId Comment ID
     * @returns {Promise<Object>}
     */
    async deleteComment(commentId) {
        return this.delete(`/comments.php?id=${commentId}`);
    }

    /**
     * Like/unlike comment
     * @param {number} commentId Comment ID
     * @returns {Promise<Object>}
     */
    async likeComment(commentId) {
        return this.post('/comments.php?action=like', { comment_id: commentId });
    }

    /**
     * Report comment
     * @param {number} commentId Comment ID
     * @param {string} reason Report reason
     * @returns {Promise<Object>}
     */
    async reportComment(commentId, reason) {
        return this.post('/comments.php?action=report', {
            comment_id: commentId,
            reason: reason
        });
    }

    // ===== Subscriptions API Methods =====

    /**
     * Get user's subscriptions
     * @returns {Promise<Object>}
     */
    async getSubscriptions() {
        return this.get('/subscriptions.php?action=list');
    }

    /**
     * Get channel's subscribers
     * @param {number} channelId Channel ID
     * @param {Object} params Query parameters
     * @returns {Promise<Object>}
     */
    async getSubscribers(channelId, params = {}) {
        return this.get('/subscriptions.php?action=subscribers', {
            channel_id: channelId,
            ...params
        });
    }

    /**
     * Get subscription feed (videos from subscribed channels)
     * @param {Object} params Query parameters
     * @returns {Promise<Object>}
     */
    async getSubscriptionFeed(params = {}) {
        return this.get('/subscriptions.php?action=feed', params);
    }

    /**
     * Check if subscribed to a channel
     * @param {number} channelId Channel ID
     * @returns {Promise<Object>}
     */
    async checkSubscription(channelId) {
        return this.get('/subscriptions.php?action=check', { channel_id: channelId });
    }

    /**
     * Subscribe to a channel
     * @param {number} channelId Channel ID
     * @returns {Promise<Object>}
     */
    async subscribe(channelId) {
        return this.post('/subscriptions.php', { channel_id: channelId });
    }

    /**
     * Unsubscribe from a channel
     * @param {number} channelId Channel ID
     * @returns {Promise<Object>}
     */
    async unsubscribe(channelId) {
        return this.delete(`/subscriptions.php?channel_id=${channelId}`);
    }

    // ===== Social API Methods =====

    /**
     * Get social feed
     * @param {Object} params Query parameters
     * @returns {Promise<Object>}
     */
    async getSocialFeed(params = {}) {
        return this.get('/social.php', params);
    }

    // ===== Helper Methods =====

    /**
     * Upload file with progress tracking
     * @param {string} endpoint Upload endpoint
     * @param {File} file File to upload
     * @param {Object} additionalData Additional form data
     * @param {Function} onProgress Progress callback
     * @returns {Promise<Object>}
     */
    async uploadFile(endpoint, file, additionalData = {}, onProgress = null) {
        return new Promise((resolve, reject) => {
            const xhr = new XMLHttpRequest();
            const formData = new FormData();

            formData.append('file', file);

            // Add additional data
            Object.keys(additionalData).forEach(key => {
                formData.append(key, additionalData[key]);
            });

            // Progress tracking
            if (onProgress && xhr.upload) {
                xhr.upload.addEventListener('progress', (e) => {
                    if (e.lengthComputable) {
                        const percentComplete = (e.loaded / e.total) * 100;
                        onProgress(percentComplete, e.loaded, e.total);
                    }
                });
            }

            // Handle completion
            xhr.addEventListener('load', () => {
                if (xhr.status >= 200 && xhr.status < 300) {
                    try {
                        const response = JSON.parse(xhr.responseText);
                        resolve(response);
                    } catch (e) {
                        resolve({ success: true, data: xhr.responseText });
                    }
                } else {
                    try {
                        const error = JSON.parse(xhr.responseText);
                        reject(new Error(error.message || `Upload failed with status ${xhr.status}`));
                    } catch (e) {
                        reject(new Error(`Upload failed with status ${xhr.status}`));
                    }
                }
            });

            // Handle errors
            xhr.addEventListener('error', () => {
                reject(new Error('Upload failed due to network error'));
            });

            xhr.addEventListener('abort', () => {
                reject(new Error('Upload aborted'));
            });

            // Add auth header
            if (this.token) {
                xhr.setRequestHeader('Authorization', `Bearer ${this.token}`);
            }

            // Send request
            const url = endpoint.startsWith('http') ? endpoint : `${this.baseURL}${endpoint}`;
            xhr.open('POST', url);
            xhr.send(formData);
        });
    }

    /**
     * Handle API errors consistently
     * @param {Error} error Error object
     * @param {Function} callback Optional callback
     */
    handleError(error, callback = null) {
        console.error('API Error:', error);

        // Show user-friendly error message
        const message = error.message || 'An unexpected error occurred';

        if (callback) {
            callback(message);
        } else if (typeof window !== 'undefined' && window.showNotification) {
            window.showNotification('error', message);
        } else {
            alert(message);
        }

        return { success: false, error: message };
    }
}

// Create global instance
if (typeof window !== 'undefined') {
    window.EasyStreamAPI = EasyStreamAPI;
    window.api = new EasyStreamAPI();
}

// Export for module systems
if (typeof module !== 'undefined' && module.exports) {
    module.exports = EasyStreamAPI;
}
