use std::num::ParseFloatError;
use std::num::ParseIntError;

use protobuf::reflect::EnumDescriptor;
use protobuf::reflect::EnumValueDescriptor;
use protobuf::reflect::FieldDescriptor;
use protobuf::reflect::MessageDescriptor;
use protobuf::reflect::ReflectValueBox;
use protobuf::reflect::RuntimeFieldType;
use protobuf::reflect::RuntimeType;
use protobuf::well_known_types::any::Any;
use protobuf::well_known_types::duration::Duration;
use protobuf::well_known_types::field_mask::FieldMask;
use protobuf::well_known_types::struct_;
use protobuf::well_known_types::struct_::ListValue;
use protobuf::well_known_types::struct_::NullValue;
use protobuf::well_known_types::struct_::Struct;
use protobuf::well_known_types::struct_::Value;
use protobuf::well_known_types::timestamp::Timestamp;
use protobuf::well_known_types::wrappers::BoolValue;
use protobuf::well_known_types::wrappers::BytesValue;
use protobuf::well_known_types::wrappers::DoubleValue;
use protobuf::well_known_types::wrappers::FloatValue;
use protobuf::well_known_types::wrappers::Int32Value;
use protobuf::well_known_types::wrappers::Int64Value;
use protobuf::well_known_types::wrappers::StringValue;
use protobuf::well_known_types::wrappers::UInt32Value;
use protobuf::well_known_types::wrappers::UInt64Value;
use protobuf::Enum;
use protobuf::MessageDyn;
use protobuf::MessageFull;
use protobuf_support::lexer::json_number_lit::JsonNumberLit;
use protobuf_support::lexer::lexer_impl::Lexer;
use protobuf_support::lexer::lexer_impl::LexerError;
use protobuf_support::lexer::loc::Loc;
use protobuf_support::lexer::parser_language::ParserLanguage;
use protobuf_support::lexer::token::Token;
use protobuf_support::lexer::tokenizer::Tokenizer;
use protobuf_support::lexer::tokenizer::TokenizerError;

use super::base64;
use super::float;
use super::rfc_3339;
use crate::base64::FromBase64Error;
use crate::well_known_wrapper::WellKnownWrapper;

#[derive(Debug, thiserror::Error)]
enum ParseErrorWithoutLocInner {
    #[error(transparent)]
    TokenizerError(#[from] TokenizerError),
    #[error("Unknown field name: `{}`", .0)]
    UnknownFieldName(String),
    #[error("Unknown enum variant name: `{}`", .0)]
    UnknownEnumVariantName(String),
    #[error(transparent)]
    FromBase64Error(#[from] FromBase64Error),
    #[error(transparent)]
    IncorrectStrLit(#[from] LexerError),
    #[error("Incorrect duration")]
    IncorrectDuration,
    #[error(transparent)]
    Rfc3339(#[from] rfc_3339::Rfc3339ParseError),
    #[error(transparent)]
    ParseIntError(#[from] ParseIntError),
    #[error(transparent)]
    ParseFloatError(#[from] ParseFloatError),
    #[error("Expecting bool")]
    ExpectingBool,
    #[error("Expecting string or integer")]
    ExpectingStrOrInt,
    #[error("Expecting number")]
    ExpectingNumber,
    #[error("Unexpected token")]
    UnexpectedToken,
    #[error("Any parsing is not implemented")]
    AnyParsingIsNotImplemented,
    #[error("Message not initialized")]
    MessageNotInitialized,
}

/// JSON parse error.
#[derive(Debug, thiserror::Error)]
#[error(transparent)]
struct ParseErrorWithoutLoc(ParseErrorWithoutLocInner);

impl From<TokenizerError> for ParseErrorWithoutLoc {
    fn from(e: TokenizerError) -> Self {
        ParseErrorWithoutLoc(ParseErrorWithoutLocInner::TokenizerError(e))
    }
}

impl From<FromBase64Error> for ParseErrorWithoutLoc {
    fn from(e: FromBase64Error) -> Self {
        ParseErrorWithoutLoc(ParseErrorWithoutLocInner::FromBase64Error(e))
    }
}

impl From<ParseIntError> for ParseErrorWithoutLoc {
    fn from(e: ParseIntError) -> Self {
        ParseErrorWithoutLoc(ParseErrorWithoutLocInner::ParseIntError(e))
    }
}

impl From<ParseFloatError> for ParseErrorWithoutLoc {
    fn from(e: ParseFloatError) -> Self {
        ParseErrorWithoutLoc(ParseErrorWithoutLocInner::ParseFloatError(e))
    }
}

impl From<rfc_3339::Rfc3339ParseError> for ParseErrorWithoutLoc {
    fn from(e: rfc_3339::Rfc3339ParseError) -> Self {
        ParseErrorWithoutLoc(ParseErrorWithoutLocInner::Rfc3339(e))
    }
}

/// JSON parse error
#[derive(Debug, thiserror::Error)]
#[error("{} at {}", error, loc)]
pub struct ParseError {
    error: ParseErrorWithoutLoc,
    loc: Loc,
}

type ParseResultWithoutLoc<A> = Result<A, ParseErrorWithoutLoc>;
type ParseResult<A> = Result<A, ParseError>;

#[derive(Clone)]
struct Parser<'a> {
    tokenizer: Tokenizer<'a>,
    parse_options: ParseOptions,
}

trait FromJsonNumber: PartialEq + Sized {
    fn from_f64(v: f64) -> Self;
    fn to_f64(&self) -> f64;
    fn from_string(v: &str) -> ParseResultWithoutLoc<Self>;
}

impl FromJsonNumber for u32 {
    fn from_f64(v: f64) -> Self {
        v as u32
    }

    fn to_f64(&self) -> f64 {
        *self as f64
    }

    fn from_string(v: &str) -> Result<Self, ParseErrorWithoutLoc> {
        Ok(v.parse()?)
    }
}

impl FromJsonNumber for u64 {
    fn from_f64(v: f64) -> Self {
        v as u64
    }

    fn to_f64(&self) -> f64 {
        *self as f64
    }

    fn from_string(v: &str) -> Result<Self, ParseErrorWithoutLoc> {
        Ok(v.parse()?)
    }
}

impl FromJsonNumber for i32 {
    fn from_f64(v: f64) -> Self {
        v as i32
    }

    fn to_f64(&self) -> f64 {
        *self as f64
    }

    fn from_string(v: &str) -> Result<Self, ParseErrorWithoutLoc> {
        Ok(v.parse()?)
    }
}

impl FromJsonNumber for i64 {
    fn from_f64(v: f64) -> Self {
        v as i64
    }

    fn to_f64(&self) -> f64 {
        *self as f64
    }

    fn from_string(v: &str) -> Result<Self, ParseErrorWithoutLoc> {
        Ok(v.parse()?)
    }
}

impl FromJsonNumber for f32 {
    fn from_f64(v: f64) -> Self {
        v as f32
    }

    fn to_f64(&self) -> f64 {
        *self as f64
    }

    fn from_string(v: &str) -> Result<Self, ParseErrorWithoutLoc> {
        if v == float::PROTOBUF_JSON_INF {
            Ok(f32::INFINITY)
        } else if v == float::PROTOBUF_JSON_MINUS_INF {
            Ok(f32::NEG_INFINITY)
        } else if v == float::PROTOBUF_JSON_NAN {
            Ok(f32::NAN)
        } else {
            Ok(v.parse()?)
        }
    }
}

impl FromJsonNumber for f64 {
    fn from_f64(v: f64) -> Self {
        v
    }

    fn to_f64(&self) -> f64 {
        *self
    }

    fn from_string(v: &str) -> Result<Self, ParseErrorWithoutLoc> {
        if v == float::PROTOBUF_JSON_INF {
            Ok(f64::INFINITY)
        } else if v == float::PROTOBUF_JSON_MINUS_INF {
            Ok(f64::NEG_INFINITY)
        } else if v == float::PROTOBUF_JSON_NAN {
            Ok(f64::NAN)
        } else {
            Ok(v.parse()?)
        }
    }
}

impl<'a> Parser<'a> {
    fn read_bool(&mut self) -> ParseResultWithoutLoc<bool> {
        if self.tokenizer.next_ident_if_eq("true")? {
            Ok(true)
        } else if self.tokenizer.next_ident_if_eq("false")? {
            Ok(false)
        } else {
            Err(ParseErrorWithoutLoc(
                ParseErrorWithoutLocInner::ExpectingBool,
            ))
        }
    }

    fn parse_bool(&self, s: &str) -> ParseResultWithoutLoc<bool> {
        if s == "true" {
            Ok(true)
        } else if s == "false" {
            Ok(false)
        } else {
            Err(ParseErrorWithoutLoc(
                ParseErrorWithoutLocInner::ExpectingBool,
            ))
        }
    }

    fn read_json_number_opt(&mut self) -> ParseResultWithoutLoc<Option<JsonNumberLit>> {
        Ok(self.tokenizer.next_token_if_map(|t| match t {
            Token::JsonNumber(v) => Some(v.clone()),
            _ => None,
        })?)
    }

    fn read_number<V: FromJsonNumber>(&mut self) -> ParseResultWithoutLoc<V> {
        if let Some(v) = self.read_json_number_opt()? {
            V::from_string(&v.0)
        } else if self.tokenizer.lookahead_is_str_lit()? {
            let v = self.read_string()?;
            self.parse_number(&v)
        } else {
            Err(ParseErrorWithoutLoc(
                ParseErrorWithoutLocInner::ExpectingNumber,
            ))
        }
    }

    fn parse_number<V: FromJsonNumber>(&self, s: &str) -> ParseResultWithoutLoc<V> {
        V::from_string(s)
    }

    fn merge_wrapper<W>(&mut self, w: &mut W) -> ParseResultWithoutLoc<()>
    where
        W: WellKnownWrapper,
        W::Underlying: FromJsonNumber,
    {
        *w.get_mut() = self.read_number()?;
        Ok(())
    }

    fn merge_bool_value(&mut self, w: &mut BoolValue) -> ParseResultWithoutLoc<()> {
        w.value = self.read_bool()?;
        Ok(())
    }

    fn merge_string_value(&mut self, w: &mut StringValue) -> ParseResultWithoutLoc<()> {
        w.value = self.read_string()?;
        Ok(())
    }

    fn merge_bytes_value(&mut self, w: &mut BytesValue) -> ParseResultWithoutLoc<()> {
        w.value = self.read_bytes()?;
        Ok(())
    }

    fn read_u32(&mut self) -> ParseResultWithoutLoc<u32> {
        self.read_number()
    }

    fn read_u64(&mut self) -> ParseResultWithoutLoc<u64> {
        self.read_number()
    }

    fn read_i32(&mut self) -> ParseResultWithoutLoc<i32> {
        self.read_number()
    }

    fn read_i64(&mut self) -> ParseResultWithoutLoc<i64> {
        self.read_number()
    }

    fn read_f32(&mut self) -> ParseResultWithoutLoc<f32> {
        self.read_number()
    }

    fn read_f64(&mut self) -> ParseResultWithoutLoc<f64> {
        self.read_number()
    }

    fn read_string(&mut self) -> ParseResultWithoutLoc<String> {
        let str_lit = self.tokenizer.next_str_lit()?;

        let mut lexer = Lexer::new(&str_lit.escaped, ParserLanguage::Json);
        let mut r = String::new();
        while !lexer.eof() {
            r.push(
                lexer
                    .next_json_char_value()
                    .map_err(ParseErrorWithoutLocInner::IncorrectStrLit)
                    .map_err(ParseErrorWithoutLoc)?,
            );
        }
        Ok(r)
    }

    fn read_bytes(&mut self) -> ParseResultWithoutLoc<Vec<u8>> {
        let s = self.read_string()?;
        self.parse_bytes(&s)
    }

    fn parse_bytes(&self, s: &str) -> ParseResultWithoutLoc<Vec<u8>> {
        Ok(base64::decode(s)?)
    }

    fn read_enum(&mut self, descriptor: &EnumDescriptor) -> ParseResultWithoutLoc<i32> {
        if descriptor.is::<NullValue>() {
            return Ok(self.read_wk_null_value()?.value());
        }

        if self.tokenizer.lookahead_is_str_lit()? {
            let name = self.read_string()?;
            Ok(self.parse_enum(name, descriptor)?.value())
        } else if self.tokenizer.lookahead_is_json_number()? {
            self.read_i32()
        } else {
            Err(ParseErrorWithoutLoc(
                ParseErrorWithoutLocInner::ExpectingStrOrInt,
            ))
        }
    }

    fn parse_enum(
        &self,
        name: String,
        descriptor: &EnumDescriptor,
    ) -> ParseResultWithoutLoc<EnumValueDescriptor> {
        match descriptor.value_by_name(&name) {
            Some(v) => Ok(v),
            None => Err(ParseErrorWithoutLoc(
                ParseErrorWithoutLocInner::UnknownEnumVariantName(name),
            )),
        }
    }

    fn read_wk_null_value(&mut self) -> ParseResultWithoutLoc<NullValue> {
        self.tokenizer.next_ident_expect_eq("null")?;
        Ok(NullValue::NULL_VALUE)
    }

    fn read_message(
        &mut self,
        descriptor: &MessageDescriptor,
    ) -> ParseResultWithoutLoc<Box<dyn MessageDyn>> {
        let mut m = descriptor.new_instance();
        self.merge_inner(&mut *m)?;
        Ok(m)
    }

    fn read_value(&mut self, t: &RuntimeType) -> ParseResultWithoutLoc<ReflectValueBox> {
        match t {
            RuntimeType::I32 => self.read_i32().map(ReflectValueBox::from),
            RuntimeType::I64 => self.read_i64().map(ReflectValueBox::from),
            RuntimeType::U32 => self.read_u32().map(ReflectValueBox::from),
            RuntimeType::U64 => self.read_u64().map(ReflectValueBox::from),
            RuntimeType::F32 => self.read_f32().map(ReflectValueBox::from),
            RuntimeType::F64 => self.read_f64().map(ReflectValueBox::from),
            RuntimeType::Bool => self.read_bool().map(ReflectValueBox::from),
            RuntimeType::String => self.read_string().map(ReflectValueBox::from),
            RuntimeType::VecU8 => self.read_bytes().map(ReflectValueBox::from),
            RuntimeType::Enum(e) => self
                .read_enum(&e)
                .map(|v| ReflectValueBox::Enum(e.clone(), v)),
            RuntimeType::Message(m) => self.read_message(&m).map(ReflectValueBox::from),
        }
    }

    fn merge_singular_field(
        &mut self,
        message: &mut dyn MessageDyn,
        field: &FieldDescriptor,
        t: &RuntimeType,
    ) -> ParseResultWithoutLoc<()> {
        field.set_singular_field(message, self.read_value(t)?);
        Ok(())
    }

    fn read_list<C>(&mut self, mut read_item: C) -> ParseResultWithoutLoc<()>
    where
        C: for<'b> FnMut(&'b mut Self) -> ParseResultWithoutLoc<()>,
    {
        if self.tokenizer.next_ident_if_eq("null")? {
            return Ok(());
        }

        // TODO: better error reporting on wrong field type
        self.tokenizer.next_symbol_expect_eq('[', "list")?;
        let mut first = true;
        while !self.tokenizer.next_symbol_if_eq(']')? {
            if !first {
                self.tokenizer.next_symbol_expect_eq(',', "list")?;
            }
            first = false;

            read_item(self)?;
        }

        Ok(())
    }

    fn merge_repeated_field(
        &mut self,
        message: &mut dyn MessageDyn,
        field: &FieldDescriptor,
        t: &RuntimeType,
    ) -> ParseResultWithoutLoc<()> {
        let mut repeated = field.mut_repeated(message);
        repeated.clear();

        self.read_list(|s| {
            repeated.push(s.read_value(t)?);
            Ok(())
        })
    }

    fn merge_wk_list_value(&mut self, list: &mut ListValue) -> ParseResultWithoutLoc<()> {
        list.values.clear();

        self.read_list(|s| {
            list.values.push(s.read_wk_value()?);
            Ok(())
        })
    }

    fn read_map<K, Fk, Fi>(
        &mut self,
        mut parse_key: Fk,
        mut read_value_and_insert: Fi,
    ) -> ParseResultWithoutLoc<()>
    where
        Fk: for<'b> FnMut(&Self, String) -> ParseResultWithoutLoc<K>,
        Fi: for<'b> FnMut(&mut Self, K) -> ParseResultWithoutLoc<()>,
    {
        if self.tokenizer.next_ident_if_eq("null")? {
            return Ok(());
        }

        self.tokenizer.next_symbol_expect_eq('{', "map")?;
        let mut first = true;
        while !self.tokenizer.next_symbol_if_eq('}')? {
            if !first {
                self.tokenizer.next_symbol_expect_eq(',', "map")?;
            }
            first = false;

            let key_string = self.read_string()?;
            let k = parse_key(self, key_string)?;

            self.tokenizer.next_symbol_expect_eq(':', "map")?;
            read_value_and_insert(self, k)?;
        }

        Ok(())
    }

    fn parse_key(&self, key: String, t: &RuntimeType) -> ParseResultWithoutLoc<ReflectValueBox> {
        match t {
            RuntimeType::I32 => self.parse_number::<i32>(&key).map(ReflectValueBox::I32),
            RuntimeType::I64 => self.parse_number::<i64>(&key).map(ReflectValueBox::I64),
            RuntimeType::U32 => self.parse_number::<u32>(&key).map(ReflectValueBox::U32),
            RuntimeType::U64 => self.parse_number::<u64>(&key).map(ReflectValueBox::U64),
            RuntimeType::Bool => self.parse_bool(&key).map(ReflectValueBox::Bool),
            RuntimeType::String => Ok(ReflectValueBox::String(key)),
            t @ RuntimeType::F32
            | t @ RuntimeType::F64
            | t @ RuntimeType::VecU8
            | t @ RuntimeType::Enum(..) => panic!("{} cannot be a map key", t),
            RuntimeType::Message(_) => panic!("message cannot be a map key"),
        }
    }

    fn merge_map_field(
        &mut self,
        message: &mut dyn MessageDyn,
        field: &FieldDescriptor,
        kt: &RuntimeType,
        vt: &RuntimeType,
    ) -> ParseResultWithoutLoc<()> {
        let mut map = field.mut_map(message);
        map.clear();

        self.read_map(
            |ss, s| ss.parse_key(s, kt),
            |s, k| {
                let v = s.read_value(vt)?;
                map.insert(k, v);
                Ok(())
            },
        )
    }

    fn merge_wk_struct(&mut self, struct_value: &mut Struct) -> ParseResultWithoutLoc<()> {
        struct_value.fields.clear();

        self.read_map(
            |_, s| Ok(s),
            |s, k| {
                let v = s.read_wk_value()?;
                struct_value.fields.insert(k, v);
                Ok(())
            },
        )
    }

    fn skip_json_value(&mut self) -> ParseResultWithoutLoc<()> {
        if self
            .tokenizer
            .next_ident_if_in(&["true", "false", "null"])?
            .is_some()
        {
        } else if self.tokenizer.lookahead_is_str_lit()? {
            self.tokenizer.next_str_lit()?;
        } else if self.tokenizer.lookahead_is_json_number()? {
            self.read_json_number_opt()?;
        } else if self.tokenizer.lookahead_is_symbol('[')? {
            self.read_list(|s| s.skip_json_value())?;
        } else if self.tokenizer.lookahead_is_symbol('{')? {
            self.read_map(|_, _| Ok(()), |s, ()| s.skip_json_value())?;
        } else {
            return Err(ParseErrorWithoutLoc(
                ParseErrorWithoutLocInner::UnexpectedToken,
            ));
        }
        Ok(())
    }

    fn merge_field(
        &mut self,
        message: &mut dyn MessageDyn,
        field: &FieldDescriptor,
    ) -> ParseResultWithoutLoc<()> {
        match field.runtime_field_type() {
            RuntimeFieldType::Singular(t) => self.merge_singular_field(message, field, &t),
            RuntimeFieldType::Repeated(t) => self.merge_repeated_field(message, field, &t),
            RuntimeFieldType::Map(kt, vt) => self.merge_map_field(message, field, &kt, &vt),
        }
    }

    fn merge_inner(&mut self, message: &mut dyn MessageDyn) -> ParseResultWithoutLoc<()> {
        if let Some(duration) = message.downcast_mut() {
            return self.merge_wk_duration(duration);
        }

        if let Some(timestamp) = message.downcast_mut() {
            return self.merge_wk_timestamp(timestamp);
        }

        if let Some(field_mask) = message.downcast_mut() {
            return self.merge_wk_field_mask(field_mask);
        }

        if let Some(value) = message.downcast_mut() {
            return self.merge_wk_value(value);
        }

        if let Some(value) = message.downcast_mut() {
            return self.merge_wk_any(value);
        }

        if let Some(value) = message.downcast_mut::<DoubleValue>() {
            return self.merge_wrapper(value);
        }

        if let Some(value) = message.downcast_mut::<FloatValue>() {
            return self.merge_wrapper(value);
        }

        if let Some(value) = message.downcast_mut::<Int64Value>() {
            return self.merge_wrapper(value);
        }

        if let Some(value) = message.downcast_mut::<UInt64Value>() {
            return self.merge_wrapper(value);
        }

        if let Some(value) = message.downcast_mut::<Int32Value>() {
            return self.merge_wrapper(value);
        }

        if let Some(value) = message.downcast_mut::<UInt32Value>() {
            return self.merge_wrapper(value);
        }

        if let Some(value) = message.downcast_mut::<BoolValue>() {
            return self.merge_bool_value(value);
        }

        if let Some(value) = message.downcast_mut::<StringValue>() {
            return self.merge_string_value(value);
        }

        if let Some(value) = message.downcast_mut::<BytesValue>() {
            return self.merge_bytes_value(value);
        }

        if let Some(value) = message.downcast_mut::<ListValue>() {
            return self.merge_wk_list_value(value);
        }

        if let Some(value) = message.downcast_mut::<Struct>() {
            return self.merge_wk_struct(value);
        }

        let descriptor = message.descriptor_dyn();

        self.tokenizer.next_symbol_expect_eq('{', "object")?;
        let mut first = true;
        while !self.tokenizer.next_symbol_if_eq('}')? {
            if !first {
                self.tokenizer.next_symbol_expect_eq(',', "object")?;
            }
            first = false;

            let field_name = self.read_string()?;
            // Proto3 JSON parsers are required to accept both
            // the converted `lowerCamelCase` name and the proto field name.
            match descriptor.field_by_name_or_json_name(&field_name) {
                Some(field) => {
                    self.tokenizer.next_symbol_expect_eq(':', "object")?;
                    self.merge_field(message, &field)?;
                }
                None if self.parse_options.ignore_unknown_fields => {
                    self.tokenizer.next_symbol_expect_eq(':', "object")?;
                    self.skip_json_value()?;
                }
                None => {
                    return Err(ParseErrorWithoutLoc(
                        ParseErrorWithoutLocInner::UnknownFieldName(field_name),
                    ))
                }
            };
        }
        Ok(())
    }

    fn merge_wk_duration(&mut self, duration: &mut Duration) -> ParseResultWithoutLoc<()> {
        let s = self.read_string()?;
        let mut lexer = Lexer::new(&s, ParserLanguage::Json);

        fn next_dec(lexer: &mut Lexer) -> ParseResultWithoutLoc<(u64, u32)> {
            let s = lexer.take_while(|c| c >= '0' && c <= '9');

            if s.len() == 0 {
                Ok((0, 0))
            } else {
                match s.parse() {
                    Ok(n) => Ok((n, s.len() as u32)),
                    Err(_) => Err(ParseErrorWithoutLoc(
                        ParseErrorWithoutLocInner::IncorrectDuration,
                    )),
                }
            }
        }

        let minus = lexer.next_char_if_eq('-');
        let seconds = match next_dec(&mut lexer)? {
            (_, 0) => {
                return Err(ParseErrorWithoutLoc(
                    ParseErrorWithoutLocInner::IncorrectDuration,
                ))
            }
            (s, _) => s,
        };
        let nanos = if lexer.next_char_if_eq('.') {
            let (mut a, mut b) = next_dec(&mut lexer)?;
            if b > 9 {
                return Err(ParseErrorWithoutLoc(
                    ParseErrorWithoutLocInner::IncorrectDuration,
                ));
            }
            while b != 9 {
                b += 1;
                a *= 10;
            }

            if a > 999_999_999 {
                return Err(ParseErrorWithoutLoc(
                    ParseErrorWithoutLocInner::IncorrectDuration,
                ));
            }

            a
        } else {
            0
        };

        // The suffix "s" is required
        if !lexer.next_char_if_eq('s') {
            return Err(ParseErrorWithoutLoc(
                ParseErrorWithoutLocInner::IncorrectDuration,
            ));
        }

        if !lexer.eof() {
            return Err(ParseErrorWithoutLoc(
                ParseErrorWithoutLocInner::IncorrectDuration,
            ));
        }

        if minus {
            duration.seconds = -(seconds as i64);
            duration.nanos = -(nanos as i32);
        } else {
            duration.seconds = seconds as i64;
            duration.nanos = nanos as i32;
        }
        Ok(())
    }

    fn merge_wk_timestamp(&mut self, timestamp: &mut Timestamp) -> ParseResultWithoutLoc<()> {
        let s = self.read_string()?;
        let (seconds, nanos) = rfc_3339::TmUtc::parse_rfc_3339(&s)?;
        timestamp.seconds = seconds;
        timestamp.nanos = nanos as i32;
        Ok(())
    }

    fn merge_wk_field_mask(&mut self, field_mask: &mut FieldMask) -> ParseResultWithoutLoc<()> {
        let s = self.read_string()?;
        if !s.is_empty() {
            field_mask.paths = s.split(',').map(|s| s.to_owned()).collect();
        }
        Ok(())
    }

    fn read_wk_list_value(&mut self) -> ParseResultWithoutLoc<ListValue> {
        let mut r = ListValue::new();
        self.merge_wk_list_value(&mut r)?;
        Ok(r)
    }

    fn read_wk_struct(&mut self) -> ParseResultWithoutLoc<Struct> {
        let mut r = Struct::new();
        self.merge_wk_struct(&mut r)?;
        Ok(r)
    }

    fn merge_wk_value(&mut self, value: &mut Value) -> ParseResultWithoutLoc<()> {
        if self.tokenizer.lookahead_is_ident("null")? {
            value.kind = Some(struct_::value::Kind::NullValue(
                self.read_wk_null_value()?.into(),
            ));
        } else if self.tokenizer.lookahead_is_ident("true")?
            || self.tokenizer.lookahead_is_ident("false")?
        {
            value.kind = Some(struct_::value::Kind::BoolValue(self.read_bool()?));
        } else if self.tokenizer.lookahead_is_json_number()? {
            value.kind = Some(struct_::value::Kind::NumberValue(self.read_f64()?));
        } else if self.tokenizer.lookahead_is_str_lit()? {
            value.kind = Some(struct_::value::Kind::StringValue(self.read_string()?));
        } else if self.tokenizer.lookahead_is_symbol('[')? {
            value.kind = Some(struct_::value::Kind::ListValue(self.read_wk_list_value()?));
        } else if self.tokenizer.lookahead_is_symbol('{')? {
            value.kind = Some(struct_::value::Kind::StructValue(self.read_wk_struct()?));
        } else {
            return Err(ParseErrorWithoutLoc(
                ParseErrorWithoutLocInner::UnexpectedToken,
            ));
        }
        Ok(())
    }

    fn merge_wk_any(&mut self, _value: &mut Any) -> ParseResultWithoutLoc<()> {
        Err(ParseErrorWithoutLoc(
            ParseErrorWithoutLocInner::AnyParsingIsNotImplemented,
        ))
    }

    fn read_wk_value(&mut self) -> ParseResultWithoutLoc<Value> {
        let mut v = Value::new();
        self.merge_wk_value(&mut v)?;
        Ok(v)
    }

    fn merge(&mut self, message: &mut dyn MessageDyn) -> ParseResult<()> {
        match self.merge_inner(message) {
            Ok(()) => Ok(()),
            Err(error) => Err(ParseError {
                error,
                loc: self.tokenizer.loc(),
            }),
        }
    }
}

/// JSON parse options.
///
/// # Examples
///
/// ```
/// let parse_options = protobuf_json_mapping::ParseOptions {
///     ignore_unknown_fields: true,
///     ..Default::default()
/// };
/// ```
#[derive(Default, Debug, Clone)]
pub struct ParseOptions {
    /// Ignore unknown fields when parsing.
    ///
    /// When `true` fields with unknown names are ignored.
    /// When `false` parser returns an error on unknown field.
    pub ignore_unknown_fields: bool,
    /// Prevent initializing `ParseOptions` enumerating all field.
    pub _future_options: (),
}

/// Merge JSON into provided message
pub fn merge_from_str_with_options(
    message: &mut dyn MessageDyn,
    json: &str,
    parse_options: &ParseOptions,
) -> ParseResult<()> {
    let mut parser = Parser {
        tokenizer: Tokenizer::new(json, ParserLanguage::Json),
        parse_options: parse_options.clone(),
    };
    parser.merge(message)
}

/// Merge JSON into provided message
pub fn merge_from_str(message: &mut dyn MessageDyn, json: &str) -> ParseResult<()> {
    merge_from_str_with_options(message, json, &ParseOptions::default())
}

/// Parse JSON to protobuf message.
pub fn parse_dyn_from_str_with_options(
    d: &MessageDescriptor,
    json: &str,
    parse_options: &ParseOptions,
) -> ParseResult<Box<dyn MessageDyn>> {
    let mut m = d.new_instance();
    merge_from_str_with_options(&mut *m, json, parse_options)?;
    if let Err(_) = m.check_initialized_dyn() {
        return Err(ParseError {
            error: ParseErrorWithoutLoc(ParseErrorWithoutLocInner::MessageNotInitialized),
            loc: Loc::start(),
        });
    }
    Ok(m)
}

/// Parse JSON to protobuf message.
pub fn parse_dyn_from_str(d: &MessageDescriptor, json: &str) -> ParseResult<Box<dyn MessageDyn>> {
    parse_dyn_from_str_with_options(d, json, &ParseOptions::default())
}

/// Parse JSON to protobuf message.
pub fn parse_from_str_with_options<M: MessageFull>(
    json: &str,
    parse_options: &ParseOptions,
) -> ParseResult<M> {
    let m = parse_dyn_from_str_with_options(&M::descriptor(), json, parse_options)?;
    Ok(*m.downcast_box().unwrap())
}

/// Parse JSON to protobuf message.
pub fn parse_from_str<M: MessageFull>(json: &str) -> ParseResult<M> {
    parse_from_str_with_options(json, &ParseOptions::default())
}