use std::ffi::c_void;

use milo_parser::{CALLBACK_ACTIVE_ALL, Parser};
use regex::Regex;

pub mod callbacks;
pub mod context;
pub mod llhttp;
pub mod output;

#[allow(unused)]
pub fn create_parser() -> Parser {
  let mut parser = Parser::new();
  let context = Box::new(context::Context::new());
  parser.context = Box::into_raw(context) as *mut c_void;

  parser.callbacks.on_error = callbacks::on_error;
  parser.callbacks.on_finish = callbacks::on_finish;
  parser.callbacks.on_request = callbacks::on_request;
  parser.callbacks.on_response = callbacks::on_response;
  parser.callbacks.on_message_start = callbacks::on_message_start;
  parser.callbacks.on_message_complete = callbacks::on_message_complete;
  parser.callbacks.on_method = callbacks::on_method;
  parser.callbacks.on_url = callbacks::on_url;
  parser.callbacks.on_protocol = callbacks::on_protocol;
  parser.callbacks.on_version = callbacks::on_version;
  parser.callbacks.on_status = callbacks::on_status;
  parser.callbacks.on_reason = callbacks::on_reason;
  parser.callbacks.on_header_name = callbacks::on_header_name;
  parser.callbacks.on_header_value = callbacks::on_header_value;
  parser.callbacks.on_headers = callbacks::on_headers;
  parser.callbacks.on_upgrade = callbacks::on_upgrade;
  parser.callbacks.on_chunk_length = callbacks::on_chunk_length;
  parser.callbacks.on_chunk_extension_name = callbacks::on_chunk_extension_name;
  parser.callbacks.on_chunk_extension_value = callbacks::on_chunk_extension_value;
  parser.callbacks.on_chunk = callbacks::on_chunk;
  parser.callbacks.on_body = callbacks::on_body;
  parser.callbacks.on_data = callbacks::on_data;
  parser.callbacks.on_trailer_name = callbacks::on_trailer_name;
  parser.callbacks.on_trailer_value = callbacks::on_trailer_value;
  parser.callbacks.on_trailers = callbacks::on_trailers;

  parser.active_callbacks = CALLBACK_ACTIVE_ALL;

  parser
}

#[allow(unused)]
pub fn http(input: &str) -> String {
  let trailing_ws = Regex::new(r"(?m)^\s+").unwrap();

  trailing_ws
    .replace_all(input.trim(), "")
    .replace('\n', "")
    .replace("\\r", "\r")
    .replace("\\n", "\n")
    .replace("\\s", " ")
}

#[allow(unused)]
pub fn parse(parser: &mut Parser, content: &str) -> usize {
  let mut context = unsafe { Box::from_raw(parser.context as *mut context::Context) };
  context.input = String::from(content);
  let _ = Box::into_raw(context);

  parser.parse(content.as_ptr(), content.len())
}
