//! Accessor parsing: field access, index, iterate, bracket notation

use nom::{
    Parser,
    branch::alt,
    character::complete::{char, multispace0},
    multi::many0,
    sequence::preceded,
};

use super::primitives::{identifier, parse_integer, parse_string_literal};
use crate::filter::ast::Filter;

pub fn parse_accessor_chain(input: &str) -> nom::IResult<&str, Filter> {
    let (input, first) = parse_accessor(input)?;
    let (input, first) = parse_optional_suffix(input, first)?;
    let (input, suffixes) = many0(parse_suffix_with_optional).parse(input)?;

    let filter = suffixes.into_iter().fold(first, |acc, suffix| {
        Filter::Pipe(Box::new(acc), Box::new(suffix))
    });

    Ok((input, filter))
}

fn parse_suffix_with_optional(input: &str) -> nom::IResult<&str, Filter> {
    let (input, filter) = parse_suffix(input)?;
    parse_optional_suffix(input, filter)
}

fn parse_optional_suffix(input: &str, filter: Filter) -> nom::IResult<&str, Filter> {
    if let Ok((input, _)) = char::<&str, nom::error::Error<&str>>('?').parse(input) {
        Ok((input, Filter::Optional(Box::new(filter))))
    } else {
        Ok((input, filter))
    }
}

fn parse_accessor(input: &str) -> nom::IResult<&str, Filter> {
    let (input, _) = char('.').parse(input)?;

    // Try bracket first, then identifier, then identity
    if let Ok((input, filter)) = parse_bracket(input) {
        return Ok((input, filter));
    }

    match identifier(input) {
        Ok((input, name)) => Ok((input, Filter::Field(name))),
        Err(_) => Ok((input, Filter::Identity)),
    }
}

fn parse_suffix(input: &str) -> nom::IResult<&str, Filter> {
    alt((
        preceded(char('.'), parse_identifier_as_field),
        parse_bracket,
    ))
    .parse(input)
}

fn parse_identifier_as_field(input: &str) -> nom::IResult<&str, Filter> {
    let (input, name) = identifier(input)?;
    Ok((input, Filter::Field(name)))
}

fn parse_bracket(input: &str) -> nom::IResult<&str, Filter> {
    let (input, _) = char('[').parse(input)?;
    let (input, _) = multispace0(input)?;

    // Try string literal first (field access)
    if let Ok((input, s)) = parse_string_literal(input) {
        let (input, _) = multispace0(input)?;
        let (input, _) = char(']').parse(input)?;
        return Ok((input, Filter::Field(s)));
    }

    // Try to parse slice or index
    // Slice: [start:end], [:end], [start:], [:]
    // Index: [n]

    // Check for leading colon (slice with no start)
    if let Ok((input, _)) = char::<&str, nom::error::Error<&str>>(':').parse(input) {
        let (input, _) = multispace0(input)?;
        let (input, end) = parse_optional_integer(input)?;
        let (input, _) = multispace0(input)?;
        let (input, _) = char(']').parse(input)?;
        return Ok((input, Filter::Slice(None, end)));
    }

    // Try integer
    if let Ok((input, n)) = parse_integer(input) {
        let (input, _) = multispace0(input)?;

        // Check if followed by colon (slice)
        if let Ok((input, _)) = char::<&str, nom::error::Error<&str>>(':').parse(input) {
            let (input, _) = multispace0(input)?;
            let (input, end) = parse_optional_integer(input)?;
            let (input, _) = multispace0(input)?;
            let (input, _) = char(']').parse(input)?;
            return Ok((input, Filter::Slice(Some(n), end)));
        }

        // Just an index
        let (input, _) = char(']').parse(input)?;
        return Ok((input, Filter::Index(n)));
    }

    // Empty brackets = iterate
    let (input, _) = char(']').parse(input)?;
    Ok((input, Filter::Iterate))
}

fn parse_optional_integer(input: &str) -> nom::IResult<&str, Option<i64>> {
    match parse_integer(input) {
        Ok((input, n)) => Ok((input, Some(n))),
        Err(_) => Ok((input, None)),
    }
}
