import gleam/result
import gleam/string
import simplifile
import tom

pub type ConfigError {
  IOError(simplifile.FileError)
  TomlError(tom.ParseError)
  MissingKey(tom.GetError)
}

pub type Config {
  Config(storage_path: String, host: String, port: Int, static_path: String)
}

pub fn error_to_string(err: ConfigError) -> String {
  let msg = case err {
    IOError(err) -> simplifile.describe_error(err)
    TomlError(err) -> {
      case err {
        tom.Unexpected(got, expected) ->
          "Unexpected: Got: " <> got <> "Expected: " <> expected
        tom.KeyAlreadyInUse(path) ->
          "Key already used at: " <> string.join(path, ".")
      }
    }
    MissingKey(err) -> {
      case err {
        tom.NotFound(path) -> "Missing Key: " <> string.join(path, ".")
        tom.WrongType(path, expected, got) ->
          "Wrong type at: "
          <> string.join(path, ".")
          <> ", got: "
          <> got
          <> "expected: "
          <> expected
      }
    }
  }

  "Config error: " <> msg
}

pub fn from_file(path: String) -> Result(Config, ConfigError) {
  use config_str <- result.try(result.map_error(
    simplifile.read(from: path),
    IOError,
  ))
  use config_tom <- result.try(result.map_error(
    tom.parse(config_str),
    TomlError,
  ))
  use storage_path <- result.try(result.map_error(
    tom.get_string(config_tom, ["storage_path"]),
    MissingKey,
  ))
  use port <- result.try(result.map_error(
    tom.get_int(config_tom, ["port"]),
    MissingKey,
  ))
  use host <- result.try(result.map_error(
    tom.get_string(config_tom, ["host"]),
    MissingKey,
  ))
  use static_path <- result.try(result.map_error(
    tom.get_string(config_tom, ["static_path"]),
    MissingKey,
  ))

  Ok(Config(storage_path:, port:, host:, static_path:))
}
