#[path = "common/serialization.rs"]
mod serialization;
use std::{
    borrow::Cow,
    io::{Cursor, Read, Seek},
};

use mcap::{
    records::{Channel, Record, SchemaHeader},
    sans_io::{IndexedReadEvent, IndexedReader, SummaryReadEvent, SummaryReader},
};
use serde_json::{json, Value};

use std::env;
use std::process;

pub fn main() {
    let args: Vec<String> = env::args().collect();
    if args.len() < 2 {
        eprintln!("Please supply an MCAP file as argument");
        process::exit(1);
    }
    let file = std::fs::read(&args[1]).expect("file wouldn't open");
    let mut messages: Vec<Value> = vec![];
    let mut cursor = Cursor::new(&file);
    let summary = {
        let mut reader = SummaryReader::new();
        while let Some(event) = reader.next_event() {
            match event.expect("failed gathering summary") {
                SummaryReadEvent::SeekRequest(pos) => {
                    reader.notify_seeked(cursor.seek(pos).expect("failed to seek file"));
                }
                SummaryReadEvent::ReadRequest(n) => {
                    let read = cursor.read(reader.insert(n)).expect("failed to read file");
                    reader.notify_read(read);
                }
            }
        }
        reader.finish().expect("file should have a summary section")
    };

    let mut reader = IndexedReader::new(&summary).expect("failed to initialize indexed reader");
    while let Some(event) = reader.next_event() {
        match event.expect("failed to get next event") {
            IndexedReadEvent::ReadChunkRequest { offset, length } => {
                let chunk_data = &file[offset as usize..][..length];
                reader
                    .insert_chunk_record_data(offset, chunk_data)
                    .expect("failed on insert");
            }
            IndexedReadEvent::Message { header, data } => {
                messages.push(serialization::as_json(&Record::Message {
                    header,
                    data: std::borrow::Cow::Borrowed(data),
                }));
            }
        }
    }

    let mut statistics: Vec<Value> = vec![];
    if let Some(stats) = summary.stats {
        statistics.push(serialization::as_json(&Record::Statistics(stats.clone())));
    };

    let schemas: Vec<_> = summary
        .schemas
        .values()
        .map(|schema| {
            serialization::as_json(&Record::Schema {
                header: SchemaHeader {
                    id: schema.id,
                    name: schema.name.clone(),
                    encoding: schema.encoding.clone(),
                },
                data: Cow::Owned(schema.data.clone().into_owned()),
            })
        })
        .collect();

    let channels: Vec<_> = summary
        .channels
        .values()
        .map(|channel| {
            serialization::as_json(&Record::Channel(Channel {
                id: channel.id,
                schema_id: channel.schema.as_ref().map(|s| s.id).unwrap_or(0),
                topic: channel.topic.clone(),
                message_encoding: channel.message_encoding.clone(),
                metadata: channel.metadata.clone(),
            }))
        })
        .collect();

    let out = json!({
        "messages": messages,
        "schemas": schemas,
        "channels": channels,
        "statistics": statistics,
    });
    print!("{}", serde_json::to_string_pretty(&out).unwrap());
}
