/**
 * Reports API Client for Dynamic Data Loading and Real-time Updates
 * Implements client-side functionality for API endpoints
 * Requirements: 9.1, 9.2, 9.3, 9.4
 */

class ReportsAPI {
    constructor() {
        this.baseUrl = '/reports/api/v2';
        this.refreshInterval = null;
        this.lastUpdate = null;
        this.cache = new Map();
        this.cacheTimeout = 5 * 60 * 1000; // 5 minutes
        
        // Initialize CSRF token
        this.csrfToken = this.getCSRFToken();
        
        // Bind methods
        this.refreshDashboard = this.refreshDashboard.bind(this);
        this.handleError = this.handleError.bind(this);
    }
    
    /**
     * Get CSRF token from cookies
     */
    getCSRFToken() {
        const name = 'csrftoken';
        let cookieValue = null;
        if (document.cookie && document.cookie !== '') {
            const cookies = document.cookie.split(';');
            for (let i = 0; i < cookies.length; i++) {
                const cookie = cookies[i].trim();
                if (cookie.substring(0, name.length + 1) === (name + '=')) {
                    cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                    break;
                }
            }
        }
        return cookieValue;
    }
    
    /**
     * Make API request with error handling
     */
    async makeRequest(url, options = {}) {
        const defaultOptions = {
            headers: {
                'Content-Type': 'application/json',
                'X-CSRFToken': this.csrfToken
            }
        };
        
        const finalOptions = { ...defaultOptions, ...options };
        
        try {
            const response = await fetch(url, finalOptions);
            
            if (!response.ok) {
                throw new Error(`HTTP error! status: ${response.status}`);
            }
            
            const data = await response.json();
            
            if (!data.success && data.error) {
                throw new Error(data.message || data.error);
            }
            
            return data;
        } catch (error) {
            console.error('API request failed:', error);
            this.handleError(error);
            throw error;
        }
    }
    
    /**
     * Get dashboard data with caching
     * Requirements: 9.1, 9.4
     */
    async getDashboardData(options = {}) {
        const {
            period = 'today',
            refresh = false,
            includeCharts = true
        } = options;
        
        const cacheKey = `dashboard_${period}_${includeCharts}`;
        
        // Check cache if not refresh
        if (!refresh && this.cache.has(cacheKey)) {
            const cached = this.cache.get(cacheKey);
            if (Date.now() - cached.timestamp < this.cacheTimeout) {
                return cached.data;
            }
        }
        
        const params = new URLSearchParams({
            period,
            refresh: refresh.toString(),
            include_charts: includeCharts.toString()
        });
        
        const url = `${this.baseUrl}/dashboard-data/?${params}`;
        const data = await this.makeRequest(url);
        
        // Cache the response
        this.cache.set(cacheKey, {
            data,
            timestamp: Date.now()
        });
        
        this.lastUpdate = new Date().toISOString();
        return data;
    }
    
    /**
     * Get filtered report data
     * Requirements: 9.2
     */
    async getFilteredReportData(filters = {}) {
        const {
            reportType = 'dashboard',
            startDate,
            endDate,
            branchId,
            productId,
            status,
            amountMin,
            amountMax,
            includeCharts = true,
            page = 1,
            pageSize = 25
        } = filters;
        
        const params = new URLSearchParams();
        params.append('report_type', reportType);
        params.append('include_charts', includeCharts.toString());
        params.append('page', page.toString());
        params.append('page_size', pageSize.toString());
        
        if (startDate) params.append('start_date', startDate);
        if (endDate) params.append('end_date', endDate);
        if (branchId) params.append('branch_id', branchId);
        if (productId) params.append('product_id', productId);
        if (status) params.append('status', status);
        if (amountMin) params.append('amount_min', amountMin);
        if (amountMax) params.append('amount_max', amountMax);
        
        const url = `${this.baseUrl}/report-filter/?${params}`;
        return await this.makeRequest(url);
    }
    
    /**
     * Get paginated data for large datasets
     * Requirements: 9.3
     */
    async getPaginatedData(options = {}) {
        const {
            dataType = 'loans',
            page = 1,
            pageSize = 25,
            searchQuery = '',
            sortBy = 'id',
            sortOrder = 'desc'
        } = options;
        
        const params = new URLSearchParams({
            data_type: dataType,
            page: page.toString(),
            page_size: pageSize.toString(),
            search: searchQuery,
            sort_by: sortBy,
            sort_order: sortOrder
        });
        
        const url = `${this.baseUrl}/paginated-data/?${params}`;
        return await this.makeRequest(url);
    }
    
    /**
     * Get real-time data updates
     * Requirements: 9.4
     */
    async getRealTimeUpdates(dataTypes = ['summary_metrics']) {
        const params = new URLSearchParams();
        dataTypes.forEach(type => params.append('data_types[]', type));
        
        if (this.lastUpdate) {
            params.append('last_update', this.lastUpdate);
        }
        
        const url = `${this.baseUrl}/real-time-refresh/?${params}`;
        return await this.makeRequest(url);
    }
    
    /**
     * Search across all data types
     */
    async search(query, options = {}) {
        const {
            type = 'all',
            limit = 10
        } = options;
        
        const params = new URLSearchParams({
            q: query,
            type,
            limit: limit.toString()
        });
        
        const url = `${this.baseUrl}/search/?${params}`;
        return await this.makeRequest(url);
    }
    
    /**
     * Export filtered data
     */
    async exportData(reportType, filters = {}, format = 'csv') {
        const params = new URLSearchParams({
            report_type: reportType,
            format,
            ...filters
        });
        
        const url = `${this.baseUrl}/export/?${params}`;
        
        // For file downloads, we need to handle differently
        const response = await fetch(url, {
            headers: {
                'X-CSRFToken': this.csrfToken
            }
        });
        
        if (!response.ok) {
            throw new Error(`Export failed: ${response.status}`);
        }
        
        // Create download link
        const blob = await response.blob();
        const downloadUrl = window.URL.createObjectURL(blob);
        const link = document.createElement('a');
        link.href = downloadUrl;
        
        // Get filename from response headers
        const contentDisposition = response.headers.get('Content-Disposition');
        const filename = contentDisposition 
            ? contentDisposition.split('filename=')[1].replace(/"/g, '')
            : `export_${Date.now()}.${format}`;
        
        link.download = filename;
        document.body.appendChild(link);
        link.click();
        document.body.removeChild(link);
        window.URL.revokeObjectURL(downloadUrl);
        
        return { success: true, filename };
    }
    
    /**
     * Start real-time refresh
     * Requirements: 9.4
     */
    startRealTimeRefresh(intervalMs = 30000, dataTypes = ['summary_metrics']) {
        this.stopRealTimeRefresh(); // Clear any existing interval
        
        this.refreshInterval = setInterval(async () => {
            try {
                const updates = await this.getRealTimeUpdates(dataTypes);
                if (updates.has_updates) {
                    this.handleRealTimeUpdates(updates.updated_data);
                }
            } catch (error) {
                console.error('Real-time refresh failed:', error);
            }
        }, intervalMs);
        
        console.log(`Real-time refresh started (${intervalMs}ms interval)`);
    }
    
    /**
     * Stop real-time refresh
     */
    stopRealTimeRefresh() {
        if (this.refreshInterval) {
            clearInterval(this.refreshInterval);
            this.refreshInterval = null;
            console.log('Real-time refresh stopped');
        }
    }
    
    /**
     * Handle real-time updates
     */
    handleRealTimeUpdates(updatedData) {
        // Dispatch custom events for different data types
        Object.keys(updatedData).forEach(dataType => {
            const event = new CustomEvent('reportsDataUpdate', {
                detail: {
                    dataType,
                    data: updatedData[dataType],
                    timestamp: new Date().toISOString()
                }
            });
            document.dispatchEvent(event);
        });
    }
    
    /**
     * Refresh dashboard data and update UI
     */
    async refreshDashboard() {
        try {
            const data = await this.getDashboardData({ refresh: true });
            
            // Dispatch refresh event
            const event = new CustomEvent('dashboardRefresh', {
                detail: { data, timestamp: new Date().toISOString() }
            });
            document.dispatchEvent(event);
            
            return data;
        } catch (error) {
            console.error('Dashboard refresh failed:', error);
            throw error;
        }
    }
    
    /**
     * Handle API errors
     */
    handleError(error) {
        // Show user-friendly error message
        const errorEvent = new CustomEvent('reportsAPIError', {
            detail: {
                error: error.message,
                timestamp: new Date().toISOString()
            }
        });
        document.dispatchEvent(errorEvent);
    }
    
    /**
     * Clear cache
     */
    clearCache() {
        this.cache.clear();
        console.log('API cache cleared');
    }
    
    /**
     * Get cache statistics
     */
    getCacheStats() {
        return {
            size: this.cache.size,
            keys: Array.from(this.cache.keys()),
            timeout: this.cacheTimeout
        };
    }
}

/**
 * Dashboard UI Controller
 * Handles UI updates and interactions
 */
class DashboardController {
    constructor(api) {
        this.api = api;
        this.charts = new Map();
        this.currentFilters = {};
        this.currentPage = 1;
        this.pageSize = 25;
        
        this.init();
    }
    
    init() {
        this.setupEventListeners();
        this.loadInitialData();
    }
    
    setupEventListeners() {
        // Listen for API events
        document.addEventListener('dashboardRefresh', this.handleDashboardRefresh.bind(this));
        document.addEventListener('reportsDataUpdate', this.handleDataUpdate.bind(this));
        document.addEventListener('reportsAPIError', this.handleAPIError.bind(this));
        
        // Setup UI event listeners
        this.setupFilterListeners();
        this.setupPaginationListeners();
        this.setupRefreshListeners();
        this.setupSearchListeners();
    }
    
    setupFilterListeners() {
        // Date range filters
        const startDateInput = document.getElementById('start-date');
        const endDateInput = document.getElementById('end-date');
        
        if (startDateInput && endDateInput) {
            const applyFilters = () => {
                this.currentFilters.startDate = startDateInput.value;
                this.currentFilters.endDate = endDateInput.value;
                this.applyFilters();
            };
            
            startDateInput.addEventListener('change', applyFilters);
            endDateInput.addEventListener('change', applyFilters);
        }
        
        // Report type filter
        const reportTypeSelect = document.getElementById('report-type');
        if (reportTypeSelect) {
            reportTypeSelect.addEventListener('change', (e) => {
                this.currentFilters.reportType = e.target.value;
                this.applyFilters();
            });
        }
        
        // Status filter
        const statusSelect = document.getElementById('status-filter');
        if (statusSelect) {
            statusSelect.addEventListener('change', (e) => {
                this.currentFilters.status = e.target.value;
                this.applyFilters();
            });
        }
        
        // Quick filter buttons
        document.querySelectorAll('.quick-filter-btn').forEach(btn => {
            btn.addEventListener('click', (e) => {
                const period = e.target.dataset.period;
                this.applyQuickFilter(period);
            });
        });
    }
    
    setupPaginationListeners() {
        // Pagination controls
        document.addEventListener('click', (e) => {
            if (e.target.classList.contains('page-btn')) {
                const page = parseInt(e.target.dataset.page);
                this.loadPage(page);
            }
        });
        
        // Page size selector
        const pageSizeSelect = document.getElementById('page-size');
        if (pageSizeSelect) {
            pageSizeSelect.addEventListener('change', (e) => {
                this.pageSize = parseInt(e.target.value);
                this.currentPage = 1;
                this.applyFilters();
            });
        }
    }
    
    setupRefreshListeners() {
        // Manual refresh button
        const refreshBtn = document.getElementById('refresh-btn');
        if (refreshBtn) {
            refreshBtn.addEventListener('click', () => {
                this.refreshData();
            });
        }
        
        // Auto-refresh toggle
        const autoRefreshToggle = document.getElementById('auto-refresh');
        if (autoRefreshToggle) {
            autoRefreshToggle.addEventListener('change', (e) => {
                if (e.target.checked) {
                    this.api.startRealTimeRefresh();
                } else {
                    this.api.stopRealTimeRefresh();
                }
            });
        }
    }
    
    setupSearchListeners() {
        const searchInput = document.getElementById('global-search');
        const searchBtn = document.getElementById('search-btn');
        
        if (searchInput) {
            let searchTimeout;
            
            searchInput.addEventListener('input', (e) => {
                clearTimeout(searchTimeout);
                searchTimeout = setTimeout(() => {
                    this.performSearch(e.target.value);
                }, 300);
            });
        }
        
        if (searchBtn) {
            searchBtn.addEventListener('click', () => {
                const query = searchInput ? searchInput.value : '';
                this.performSearch(query);
            });
        }
    }
    
    async loadInitialData() {
        try {
            this.showLoading();
            const data = await this.api.getDashboardData();
            this.updateDashboard(data);
            this.hideLoading();
        } catch (error) {
            this.hideLoading();
            this.showError('Failed to load dashboard data');
        }
    }
    
    async applyFilters() {
        try {
            this.showLoading();
            const data = await this.api.getFilteredReportData({
                ...this.currentFilters,
                page: this.currentPage,
                pageSize: this.pageSize
            });
            this.updateReportData(data);
            this.hideLoading();
        } catch (error) {
            this.hideLoading();
            this.showError('Failed to apply filters');
        }
    }
    
    async loadPage(page) {
        this.currentPage = page;
        await this.applyFilters();
    }
    
    async refreshData() {
        try {
            this.showLoading();
            await this.api.refreshDashboard();
            this.hideLoading();
        } catch (error) {
            this.hideLoading();
            this.showError('Failed to refresh data');
        }
    }
    
    async performSearch(query) {
        if (!query || query.length < 2) {
            this.clearSearchResults();
            return;
        }
        
        try {
            const results = await this.api.search(query);
            this.displaySearchResults(results);
        } catch (error) {
            this.showError('Search failed');
        }
    }
    
    applyQuickFilter(period) {
        const today = new Date();
        let startDate, endDate;
        
        switch (period) {
            case 'today':
                startDate = endDate = today.toISOString().split('T')[0];
                break;
            case 'week':
                startDate = new Date(today.setDate(today.getDate() - 7)).toISOString().split('T')[0];
                endDate = new Date().toISOString().split('T')[0];
                break;
            case 'month':
                startDate = new Date(today.getFullYear(), today.getMonth(), 1).toISOString().split('T')[0];
                endDate = new Date().toISOString().split('T')[0];
                break;
            case 'quarter':
                const quarter = Math.floor(today.getMonth() / 3);
                startDate = new Date(today.getFullYear(), quarter * 3, 1).toISOString().split('T')[0];
                endDate = new Date().toISOString().split('T')[0];
                break;
        }
        
        // Update filter inputs
        const startDateInput = document.getElementById('start-date');
        const endDateInput = document.getElementById('end-date');
        
        if (startDateInput) startDateInput.value = startDate;
        if (endDateInput) endDateInput.value = endDate;
        
        this.currentFilters.startDate = startDate;
        this.currentFilters.endDate = endDate;
        this.applyFilters();
    }
    
    updateDashboard(data) {
        // Update summary metrics
        this.updateSummaryCards(data.summary_metrics);
        
        // Update charts
        if (data.chart_data) {
            this.updateCharts(data.chart_data);
        }
        
        // Update detailed data
        if (data.detailed_data) {
            this.updateDetailedData(data.detailed_data);
        }
    }
    
    updateSummaryCards(metrics) {
        Object.keys(metrics).forEach(key => {
            const element = document.getElementById(`metric-${key.replace(/_/g, '-')}`);
            if (element) {
                const value = metrics[key];
                if (typeof value === 'number') {
                    element.textContent = key.includes('rate') || key.includes('percent') 
                        ? `${value.toFixed(1)}%`
                        : value.toLocaleString();
                } else {
                    element.textContent = value;
                }
            }
        });
    }
    
    updateCharts(chartData) {
        Object.keys(chartData).forEach(chartId => {
            const chartConfig = chartData[chartId];
            this.renderChart(chartId, chartConfig);
        });
    }
    
    renderChart(chartId, config) {
        const canvas = document.getElementById(`chart-${chartId}`);
        if (!canvas) return;
        
        // Destroy existing chart
        if (this.charts.has(chartId)) {
            this.charts.get(chartId).destroy();
        }
        
        // Create new chart
        const ctx = canvas.getContext('2d');
        const chart = new Chart(ctx, {
            type: config.type,
            data: {
                labels: config.labels,
                datasets: config.datasets || [{
                    data: config.data,
                    backgroundColor: config.backgroundColor,
                    borderColor: config.borderColor,
                    borderWidth: config.borderWidth || 1
                }]
            },
            options: {
                responsive: true,
                maintainAspectRatio: false,
                plugins: {
                    title: {
                        display: !!config.title,
                        text: config.title
                    },
                    legend: {
                        display: config.type !== 'line'
                    }
                },
                scales: config.type === 'line' || config.type === 'bar' ? {
                    y: {
                        beginAtZero: true,
                        ticks: {
                            callback: function(value) {
                                return config.formatCurrency ? 
                                    'KES ' + value.toLocaleString() : 
                                    value.toLocaleString();
                            }
                        }
                    }
                } : {}
            }
        });
        
        this.charts.set(chartId, chart);
    }
    
    updateReportData(data) {
        // Update data table
        this.updateDataTable(data.data);
        
        // Update pagination
        this.updatePagination(data.pagination);
        
        // Update charts if included
        if (data.charts) {
            this.updateCharts(data.charts);
        }
        
        // Update summary
        if (data.summary) {
            this.updateSummary(data.summary);
        }
    }
    
    updateDataTable(data) {
        const tableBody = document.getElementById('data-table-body');
        if (!tableBody) return;
        
        tableBody.innerHTML = '';
        
        // Handle different data structures
        let items = [];
        if (Array.isArray(data)) {
            items = data;
        } else if (data.loans) {
            items = data.loans;
        } else if (data.requests) {
            items = data.requests;
        } else if (data.payments) {
            items = data.payments;
        }
        
        items.forEach(item => {
            const row = this.createTableRow(item);
            tableBody.appendChild(row);
        });
    }
    
    createTableRow(item) {
        const row = document.createElement('tr');
        
        // Create cells based on item type
        if (item.loan_number) {
            // Loan item
            row.innerHTML = `
                <td>${item.loan_number}</td>
                <td>${item.borrower_name}</td>
                <td>KES ${item.principal_amount?.toLocaleString() || 0}</td>
                <td>KES ${item.outstanding_balance?.toLocaleString() || 0}</td>
                <td><span class="badge badge-${this.getStatusClass(item.status)}">${item.status}</span></td>
                <td>${item.due_date ? new Date(item.due_date).toLocaleDateString() : '-'}</td>
            `;
        } else if (item.request_number) {
            // Customer request item
            row.innerHTML = `
                <td>${item.request_number}</td>
                <td>${item.customer_name}</td>
                <td>${item.request_type}</td>
                <td>${item.subject}</td>
                <td><span class="badge badge-${this.getStatusClass(item.status)}">${item.status}</span></td>
                <td>${new Date(item.created_at).toLocaleDateString()}</td>
            `;
        } else if (item.receipt_number) {
            // Repayment item
            row.innerHTML = `
                <td>${item.receipt_number}</td>
                <td>${item.loan_number}</td>
                <td>${item.borrower_name}</td>
                <td>KES ${item.amount?.toLocaleString() || 0}</td>
                <td>${new Date(item.payment_date).toLocaleDateString()}</td>
            `;
        }
        
        return row;
    }
    
    getStatusClass(status) {
        const statusClasses = {
            'Active': 'success',
            'Completed': 'info',
            'Overdue': 'danger',
            'Pending': 'warning',
            'In Progress': 'info',
            'Resolved': 'success'
        };
        return statusClasses[status] || 'secondary';
    }
    
    updatePagination(pagination) {
        const paginationContainer = document.getElementById('pagination-container');
        if (!paginationContainer) return;
        
        let paginationHTML = '';
        
        // Previous button
        if (pagination.has_previous) {
            paginationHTML += `<button class="btn btn-sm btn-outline-primary page-btn" data-page="${pagination.previous_page}">Previous</button>`;
        }
        
        // Page numbers
        const startPage = Math.max(1, pagination.current_page - 2);
        const endPage = Math.min(pagination.total_pages, pagination.current_page + 2);
        
        for (let i = startPage; i <= endPage; i++) {
            const isActive = i === pagination.current_page;
            paginationHTML += `<button class="btn btn-sm ${isActive ? 'btn-primary' : 'btn-outline-primary'} page-btn" data-page="${i}">${i}</button>`;
        }
        
        // Next button
        if (pagination.has_next) {
            paginationHTML += `<button class="btn btn-sm btn-outline-primary page-btn" data-page="${pagination.next_page}">Next</button>`;
        }
        
        paginationContainer.innerHTML = paginationHTML;
        
        // Update pagination info
        const paginationInfo = document.getElementById('pagination-info');
        if (paginationInfo) {
            paginationInfo.textContent = `Showing ${pagination.start_index}-${pagination.end_index} of ${pagination.total_items} items`;
        }
    }
    
    updateSummary(summary) {
        Object.keys(summary).forEach(key => {
            const element = document.getElementById(`summary-${key.replace(/_/g, '-')}`);
            if (element) {
                const value = summary[key];
                element.textContent = typeof value === 'number' ? value.toLocaleString() : value;
            }
        });
    }
    
    displaySearchResults(results) {
        const searchResults = document.getElementById('search-results');
        if (!searchResults) return;
        
        let html = '<div class="search-results-container">';
        
        Object.keys(results.results).forEach(type => {
            const items = results.results[type];
            if (items.length > 0) {
                html += `<div class="search-category">
                    <h6>${type.charAt(0).toUpperCase() + type.slice(1)}</h6>
                    <ul class="list-unstyled">`;
                
                items.forEach(item => {
                    html += `<li class="search-result-item" data-type="${type}" data-id="${item.id}">
                        ${this.formatSearchResult(item, type)}
                    </li>`;
                });
                
                html += '</ul></div>';
            }
        });
        
        html += '</div>';
        searchResults.innerHTML = html;
        searchResults.style.display = 'block';
    }
    
    formatSearchResult(item, type) {
        switch (type) {
            case 'loans':
                return `<strong>${item.loan_number}</strong> - ${item.borrower_name} (KES ${item.amount.toLocaleString()})`;
            case 'customers':
                return `<strong>${item.name}</strong> - ${item.phone} (${item.email})`;
            case 'requests':
                return `<strong>${item.request_number}</strong> - ${item.subject} (${item.customer_name})`;
            default:
                return JSON.stringify(item);
        }
    }
    
    clearSearchResults() {
        const searchResults = document.getElementById('search-results');
        if (searchResults) {
            searchResults.style.display = 'none';
            searchResults.innerHTML = '';
        }
    }
    
    handleDashboardRefresh(event) {
        this.updateDashboard(event.detail.data);
        this.showSuccess('Dashboard refreshed successfully');
    }
    
    handleDataUpdate(event) {
        const { dataType, data } = event.detail;
        
        // Update specific data type
        switch (dataType) {
            case 'summary_metrics':
                this.updateSummaryCards(data);
                break;
            case 'loans_due_today':
                this.updateLoansDueToday(data);
                break;
            case 'recent_repayments':
                this.updateRecentRepayments(data);
                break;
            case 'customer_requests':
                this.updateCustomerRequests(data);
                break;
        }
    }
    
    handleAPIError(event) {
        this.showError(event.detail.error);
    }
    
    showLoading() {
        const loader = document.getElementById('loading-indicator');
        if (loader) loader.style.display = 'block';
    }
    
    hideLoading() {
        const loader = document.getElementById('loading-indicator');
        if (loader) loader.style.display = 'none';
    }
    
    showSuccess(message) {
        this.showNotification(message, 'success');
    }
    
    showError(message) {
        this.showNotification(message, 'error');
    }
    
    showNotification(message, type = 'info') {
        // Create notification element
        const notification = document.createElement('div');
        notification.className = `alert alert-${type === 'error' ? 'danger' : type} alert-dismissible fade show`;
        notification.innerHTML = `
            ${message}
            <button type="button" class="btn-close" data-bs-dismiss="alert"></button>
        `;
        
        // Add to notification container
        const container = document.getElementById('notification-container') || document.body;
        container.appendChild(notification);
        
        // Auto-remove after 5 seconds
        setTimeout(() => {
            if (notification.parentNode) {
                notification.parentNode.removeChild(notification);
            }
        }, 5000);
    }
}

// Initialize when DOM is loaded
document.addEventListener('DOMContentLoaded', function() {
    // Create global instances
    window.reportsAPI = new ReportsAPI();
    window.dashboardController = new DashboardController(window.reportsAPI);
    
    console.log('Reports API and Dashboard Controller initialized');
});

// Export for module usage
if (typeof module !== 'undefined' && module.exports) {
    module.exports = { ReportsAPI, DashboardController };
}