#![feature(iter_intersperse, let_chains, vec_pop_if)]

use std::{
    fs,
    io::{self, stdout, IsTerminal},
    path::PathBuf,
    process::ExitCode,
};

use clap::Parser as CParser;
use document::Content;
use libterm::RawTerminal;
use pulldown_cmark::Parser;
use setting::{TerminalTypesetter, Typesetter};

pub mod document;
pub mod setting;
pub mod util;

#[derive(Debug, thiserror::Error)]
pub enum Error {
    #[error("{0}")]
    Io(#[from] io::Error),
    #[error("Terminal is too small")]
    TerminalTooSmall,
}

#[derive(Debug, CParser)]
pub struct Args {
    filename: PathBuf,
}

fn run(args: &Args) -> Result<(), Error> {
    let stdout = stdout();
    let page_width = if stdout.is_terminal() {
        stdout.raw_size().map_or(60, |s| s.0)
    } else {
        60
    };
    let right_margin = 8;

    if 10 + right_margin > page_width {
        return Err(Error::TerminalTooSmall);
    }

    let source = fs::read_to_string(&args.filename)?;
    let mut parser = Parser::new(&source);
    let mut root = Content::default();
    root.parse(&mut parser);
    let mut ts = TerminalTypesetter::default();
    ts.set_page_width(page_width - right_margin);
    root.print(&mut ts);
    ts.finish_line();
    Ok(())
}

fn main() -> ExitCode {
    let args = Args::parse();
    match run(&args) {
        Ok(()) => ExitCode::SUCCESS,
        Err(error) => {
            eprintln!("{}: {error}", args.filename.display());
            ExitCode::FAILURE
        }
    }
}
