// HTTP Download Actor
// Handles download requests and progress queries
var http = use('http');
var os = use('os');

// Actor state
var state = {
    downloading: false,
    current_url: null,
    total_bytes: 0,
    downloaded_bytes: 0,
    start_time: 0,
    error: null,
    connection: null,
    download_msg: null,
    chunks: []
};

// Helper to calculate progress percentage
function get_progress() {
    if (state.total_bytes == 0) {
        return 0;
    }
    return Math.round((state.downloaded_bytes / state.total_bytes) * 100);
}

// Helper to format status response
function get_status() {
    if (!state.downloading) {
        return {
            status: 'idle',
            error: state.error
        };
    }
    
    var elapsed = os.now() - state.start_time;
    var bytes_per_sec = elapsed > 0 ? state.downloaded_bytes / elapsed : 0;
    
    return {
        status: 'downloading',
        url: state.current_url,
        progress: get_progress(),
        downloaded_bytes: state.downloaded_bytes,
        total_bytes: state.total_bytes,
        elapsed_seconds: elapsed,
        bytes_per_second: Math.round(bytes_per_sec)
    };
}

// Main message receiver
$_.receiver(function(msg) {
    switch (msg.type) {
        case 'download':
            if (state.downloading) {
                send(msg, {
                    type: 'error',
                    error: 'Already downloading',
                    current_url: state.current_url
                });
                return;
            }
            
            if (!msg.url) {
                send(msg, {
                    type: 'error',
                    error: 'No URL provided'
                });
                return;
            }
            
            // Start download
            state.downloading = true;
            state.current_url = msg.url;
            state.total_bytes = 0;
            state.downloaded_bytes = 0;
            state.start_time = os.now();
            state.error = null;
            state.download_msg = msg;
            state.chunks = [];
            
            try {
                // Start the connection
                state.connection = http.fetch_start(msg.url, msg.options || {});
                if (!state.connection) {
                    throw new Error('Failed to start download');
                }
                
                // Schedule the first chunk read
                $_.delay(read_next_chunk, 0);
                
            } catch (e) {
                state.error = e.toString();
                state.downloading = false;
                
                send(msg, {
                    type: 'error',
                    error: state.error,
                    url: msg.url
                });
            }
            break;
            
        case 'status':
            log.console(`got status request. current is ${json.encode(get_status())}`)
            send(msg, {
                type: 'status_response',
                ...get_status()
            });
            break;
            
        case 'cancel':
            if (state.downloading) {
                // Cancel the download
                if (state.connection) {
                    http.fetch_close(state.connection);
                    state.connection = null;
                }
                state.downloading = false;
                state.current_url = null;
                state.download_msg = null;
                state.chunks = [];
                
                send(msg, {
                    type: 'cancelled',
                    message: 'Download cancelled',
                    url: state.current_url
                });
            } else {
                send(msg, {
                    type: 'error',
                    error: 'No download in progress'
                });
            }
            break;
            
        default:
            send(msg, {
                type: 'error',
                error: 'Unknown message type: ' + msg.type
            });
    }
});

// Non-blocking chunk reader
function read_next_chunk() {
    if (!state.downloading || !state.connection) {
        return;
    }
    
    try {
        var chunk = http.fetch_read_chunk(state.connection);
        
        if (chunk == null) {
            // Download complete
            finish_download();
            return;
        }
        
        // Store chunk
        state.chunks.push(chunk);
        
        // Update progress
        var info = http.fetch_info(state.connection);
        state.downloaded_bytes = info.bytes_read;
        if (info.headers_complete && info.content_length > 0) {
            state.total_bytes = info.content_length;
        }
        
        // Schedule next chunk read
        $_.delay(read_next_chunk, 0);
        
    } catch (e) {
        // Error during download
        state.error = e.toString();
        if (state.connection) {
            http.fetch_close(state.connection);
        }
        
        if (state.download_msg) {
            send(state.download_msg, {
                type: 'error',
                error: state.error,
                url: state.current_url
            });
        }
        
        // Reset state
        state.downloading = false;
        state.connection = null;
        state.download_msg = null;
        state.chunks = [];
    }
}

// Complete the download and send result
function finish_download() {
    if (state.connection) {
        http.fetch_close(state.connection);
    }
    
    // Combine all chunks into single ArrayBuffer
    var total_size = 0;
    for (var i = 0; i < state.chunks.length; i++) {
        total_size += state.chunks[i].byteLength;
    }
    
    var result = new ArrayBuffer(total_size);
    var view = new Uint8Array(result);
    var offset = 0;
    
    for (var i = 0; i < state.chunks.length; i++) {
        var chunk_view = new Uint8Array(state.chunks[i]);
        view.set(chunk_view, offset);
        offset += state.chunks[i].byteLength;
    }
    
    // Send complete message
    if (state.download_msg) {
        send(state.download_msg, {
            type: 'complete',
            url: state.current_url,
            data: result,
            size: result.byteLength,
            duration: os.now() - state.start_time
        });
    }
    
    // Reset state
    state.downloading = false;
    state.connection = null;
    state.current_url = null;
    state.download_msg = null;
    state.chunks = [];
}