//! The JSON schema of a Jupyter Notebook, entrypoint is [`JupyterNotebook`]
//!
//! Generated by <https://app.quicktype.io/> from
//! <https://github.com/jupyter/nbformat/blob/16b53251aabf472ad9406ddb1f78b0421c014eeb/nbformat/v4/nbformat.v4.schema.json>
//! Jupyter Notebook v4.5 JSON schema.
//!
//! The following changes were made to the generated version: `Cell::id` is optional because it
//! wasn't required <v4.5, `#[serde(deny_unknown_fields)]` was added where the schema had
//! `"additionalProperties": false` and `#[serde(flatten)] pub other: BTreeMap<String, Value>`
//! for `"additionalProperties": true` as preparation for round-trip support.

use std::collections::{BTreeMap, HashMap};

use serde::{Deserialize, Serialize};
use serde_json::Value;

/// The root of the JSON of a Jupyter Notebook
///
/// Generated by <https://app.quicktype.io/> from
/// <https://github.com/jupyter/nbformat/blob/16b53251aabf472ad9406ddb1f78b0421c014eeb/nbformat/v4/nbformat.v4.schema.json>
/// Jupyter Notebook v4.5 JSON schema.
#[derive(Debug, Serialize, Deserialize)]
pub struct JupyterNotebook {
    /// Array of cells of the current notebook.
    pub cells: Vec<Cell>,
    /// Notebook root-level metadata.
    pub metadata: JupyterNotebookMetadata,
    /// Notebook format (major number). Incremented between backwards incompatible changes to the
    /// notebook format.
    pub nbformat: i64,
    /// Notebook format (minor number). Incremented for backward compatible changes to the
    /// notebook format.
    pub nbformat_minor: i64,
}

/// Notebook raw nbconvert cell.
///
/// Notebook markdown cell.
///
/// Notebook code cell.
#[derive(Debug, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Cell {
    pub attachments: Option<HashMap<String, HashMap<String, SourceValue>>>,
    /// String identifying the type of cell.
    pub cell_type: CellType,
    /// Technically, id isn't required (it's not even present) in schema v4.0 through v4.4, but
    /// it's required in v4.5. Main issue is that pycharm creates notebooks without an id
    /// <https://youtrack.jetbrains.com/issue/PY-59438/Jupyter-notebooks-created-with-PyCharm-are-missing-the-id-field-in-cells-in-the-.ipynb-json>
    pub id: Option<String>,
    /// Cell-level metadata.
    pub metadata: CellMetadata,
    pub source: SourceValue,
    /// The code cell's prompt number. Will be null if the cell has not been run.
    pub execution_count: Option<i64>,
    /// Execution, display, or stream outputs.
    pub outputs: Option<Vec<Output>>,
}

/// Cell-level metadata.
#[derive(Debug, Serialize, Deserialize)]
pub struct CellMetadata {
    /// Raw cell metadata format for nbconvert.
    pub format: Option<String>,
    /// Official Jupyter Metadata for Raw Cells
    ///
    /// Official Jupyter Metadata for Markdown Cells
    ///
    /// Official Jupyter Metadata for Code Cells
    pub jupyter: Option<HashMap<String, Option<Value>>>,
    pub name: Option<String>,
    pub tags: Option<Vec<String>>,
    /// Whether the cell's output is collapsed/expanded.
    pub collapsed: Option<bool>,
    /// Execution time for the code in the cell. This tracks time at which messages are received
    /// from iopub or shell channels
    pub execution: Option<Execution>,
    /// Whether the cell's output is scrolled, unscrolled, or autoscrolled.
    pub scrolled: Option<ScrolledUnion>,
    /// Custom added: round-trip support
    #[serde(flatten)]
    pub other: BTreeMap<String, Value>,
}

/// Execution time for the code in the cell. This tracks time at which messages are received
/// from iopub or shell channels
#[derive(Debug, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Execution {
    /// header.date (in ISO 8601 format) of iopub channel's execute_input message. It indicates
    /// the time at which the kernel broadcasts an execute_input message to connected frontends
    #[serde(rename = "iopub.execute_input")]
    pub iopub_execute_input: Option<String>,
    /// header.date (in ISO 8601 format) of iopub channel's kernel status message when the status
    /// is 'busy'
    #[serde(rename = "iopub.status.busy")]
    pub iopub_status_busy: Option<String>,
    /// header.date (in ISO 8601 format) of iopub channel's kernel status message when the status
    /// is 'idle'. It indicates the time at which kernel finished processing the associated
    /// request
    #[serde(rename = "iopub.status.idle")]
    pub iopub_status_idle: Option<String>,
    /// header.date (in ISO 8601 format) of the shell channel's execute_reply message. It
    /// indicates the time at which the execute_reply message was created
    #[serde(rename = "shell.execute_reply")]
    pub shell_execute_reply: Option<String>,
}

/// Result of executing a code cell.
///
/// Data displayed as a result of code cell execution.
///
/// Stream output from a code cell.
///
/// Output of an error that occurred during code cell execution.
#[derive(Debug, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Output {
    pub data: Option<HashMap<String, SourceValue>>,
    /// A result's prompt number.
    pub execution_count: Option<i64>,
    pub metadata: Option<HashMap<String, Option<Value>>>,
    /// Type of cell output.
    pub output_type: OutputType,
    /// The name of the stream (stdout, stderr).
    pub name: Option<String>,
    /// The stream's text output, represented as an array of strings.
    pub text: Option<TextUnion>,
    /// The name of the error.
    pub ename: Option<String>,
    /// The value, or message, of the error.
    pub evalue: Option<String>,
    /// The error's traceback, represented as an array of strings.
    pub traceback: Option<Vec<String>>,
}

/// Notebook root-level metadata.
#[derive(Debug, Serialize, Deserialize)]
pub struct JupyterNotebookMetadata {
    /// The author(s) of the notebook document
    pub authors: Option<Vec<Option<Value>>>,
    /// Kernel information.
    pub kernelspec: Option<Kernelspec>,
    /// Kernel information.
    pub language_info: Option<LanguageInfo>,
    /// Original notebook format (major number) before converting the notebook between versions.
    /// This should never be written to a file.
    pub orig_nbformat: Option<i64>,
    /// The title of the notebook document
    pub title: Option<String>,
    /// Custom added: round-trip support
    #[serde(flatten)]
    pub other: BTreeMap<String, Value>,
}

/// Kernel information.
#[derive(Debug, Serialize, Deserialize)]
pub struct Kernelspec {
    /// Name to display in UI.
    pub display_name: String,
    /// Name of the kernel specification.
    pub name: String,
    /// Custom added: round-trip support
    #[serde(flatten)]
    pub other: BTreeMap<String, Value>,
}

/// Kernel information.
#[derive(Debug, Serialize, Deserialize)]
pub struct LanguageInfo {
    /// The codemirror mode to use for code in this language.
    pub codemirror_mode: Option<CodemirrorMode>,
    /// The file extension for files in this language.
    pub file_extension: Option<String>,
    /// The mimetype corresponding to files in this language.
    pub mimetype: Option<String>,
    /// The programming language which this kernel runs.
    pub name: String,
    /// The pygments lexer to use for code in this language.
    pub pygments_lexer: Option<String>,
    /// Custom added: round-trip support
    #[serde(flatten)]
    pub other: BTreeMap<String, Value>,
}

/// mimetype output (e.g. text/plain), represented as either an array of strings or a
/// string.
///
/// Contents of the cell, represented as an array of lines.
///
/// The stream's text output, represented as an array of strings.
#[derive(Debug, Serialize, Deserialize)]
#[serde(untagged)]
pub enum SourceValue {
    String(String),
    StringArray(Vec<String>),
}

/// Whether the cell's output is scrolled, unscrolled, or autoscrolled.
#[derive(Debug, Serialize, Deserialize)]
#[serde(untagged)]
pub enum ScrolledUnion {
    Bool(bool),
    Enum(ScrolledEnum),
}

/// mimetype output (e.g. text/plain), represented as either an array of strings or a
/// string.
///
/// Contents of the cell, represented as an array of lines.
///
/// The stream's text output, represented as an array of strings.
#[derive(Debug, Serialize, Deserialize)]
#[serde(untagged)]
pub enum TextUnion {
    String(String),
    StringArray(Vec<String>),
}

/// The codemirror mode to use for code in this language.
#[derive(Debug, Serialize, Deserialize)]
#[serde(untagged)]
pub enum CodemirrorMode {
    AnythingMap(HashMap<String, Option<Value>>),
    String(String),
}

/// String identifying the type of cell.
#[derive(Debug, Serialize, Deserialize, PartialEq, Copy, Clone)]
pub enum CellType {
    #[serde(rename = "code")]
    Code,
    #[serde(rename = "markdown")]
    Markdown,
    #[serde(rename = "raw")]
    Raw,
}

#[derive(Debug, Serialize, Deserialize, Copy, Clone)]
pub enum ScrolledEnum {
    #[serde(rename = "auto")]
    Auto,
}

/// Type of cell output.
#[derive(Debug, Serialize, Deserialize, Copy, Clone)]
pub enum OutputType {
    #[serde(rename = "display_data")]
    DisplayData,
    #[serde(rename = "error")]
    Error,
    #[serde(rename = "execute_result")]
    ExecuteResult,
    #[serde(rename = "stream")]
    Stream,
}
