use core::fmt::Debug;
use core::marker::PhantomData;

use crate::ctor::Ctor;

use crate::ctor::Handler;
use crate::ctor::Map;
use crate::ctx::CtxGuard;
use crate::ctx::Match;
use crate::debug_ctor_beg;
use crate::debug_ctor_reval;
use crate::debug_ctor_stage;
use crate::debug_regex_beg;
use crate::debug_regex_reval;
use crate::debug_regex_stage;
use crate::err::Error;
use crate::map::Select0;
use crate::map::Select1;
use crate::map::SelectEq;
use crate::regex::Regex;
use crate::regex::impl_not_for_regex;
use crate::span::Span;

///
/// Sequentially composes two expressions, requiring **both** to match in order.
///
/// The [`Then`] combinator implements **sequence semantics** where:
/// 1. The `left` expression must match first
/// 2. Upon success, the `right` expression must match at the **advanced position**
/// 3. Both expressions must succeed for the entire combinator to succeed
/// 4. On any failure, the context is **atomically reset** to the initial position
///
/// This is the fundamental building block for constructing compound patterns,
/// similar to concatenation in regular expressions (`ab` matches 'a' followed by 'b').
/// Unlike manual sequencing, [`Then`] automatically handles context management,
/// error propagation, and span concatenation with zero runtime overhead.
///
/// # Regex
///
/// In regex mode, [`Then`] returns a **combined span** covering both expressions:
/// 1. Attempts to match `left` at current position
/// 2. On success, attempts to match `right` at **advanced position**
/// 3. On both successes:
///    - Concatenates spans using `Span::add_assign`
///    - Returns single span covering entire matched region
/// 4. On any failure:
///    - Resets context to initial position
///    - Returns first error encountered
///
/// The resulting span is **contiguous** and covers exactly the input consumed by both expressions.
///
/// ## Example
/// ```
/// # use neure::prelude::*;
/// #
/// # fn main() -> Result<(), Box<dyn core::error::Error>> {
///     let str = neu::ascii_alphabetic().many1();
///     let str = str.enclose("\"", "\"");
///     let int = neu::digit(10).many1();
///     let tuple = str.then(int.prefix(" "));
///
///     assert_eq!(
///         CharsCtx::new(r#""Galaxy" 42"#).try_mat(&tuple)?,
///         Span::new(0, 11)
///     );
///
/// #   Ok(())
/// # }
/// ```
///
/// # Ctor
///
/// In constructor mode, [`Then`] returns a **tuple of values** `(O1, O2)`:
/// 1. Constructs value from `left` expression
/// 2. On success, constructs value from `right` expression at advanced position
/// 3. On both successes:
///    - Returns tuple `(left_value, right_value)`
///    - Context advances past both expressions
/// 4. On any failure:
///    - Resets context to initial position
///    - Returns first error encountered
///
/// This enables structured data extraction from sequential patterns, such as:
/// - Parsing `(key, value)` pairs
/// - Extracting components from compound identifiers
/// - Building AST nodes from multiple tokens
///
/// ## Example
/// ```
/// # use neure::prelude::*;
/// #
/// # fn main() -> Result<(), Box<dyn core::error::Error>> {
///     let answer = neu::digit(10).many1();
///     let desc = neu::word().many1();
///     let desc = desc.sep(neu::whitespace().many0()).prefix(" ");
///
///     let parser = answer.then(desc);
///     let (answer, desc) = CharsCtx::new("42 is the answer").ctor(&parser)?;
///
///     assert_eq!(answer, "42");
///     assert_eq!(desc, ["is", "the", "answer"]);
///
/// #   Ok(())
/// # }
/// ```
pub struct Then<C, L, R> {
    left: L,
    right: R,
    marker: PhantomData<C>,
}

impl_not_for_regex!(Then<C, L, R>);

impl<C, L, R> Debug for Then<C, L, R>
where
    L: Debug,
    R: Debug,
{
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        f.debug_struct("Then")
            .field("left", &self.left)
            .field("right", &self.right)
            .finish()
    }
}

impl<C, L, R> Default for Then<C, L, R>
where
    L: Default,
    R: Default,
{
    fn default() -> Self {
        Self {
            left: Default::default(),
            right: Default::default(),
            marker: Default::default(),
        }
    }
}

impl<C, L, R> Clone for Then<C, L, R>
where
    L: Clone,
    R: Clone,
{
    fn clone(&self) -> Self {
        Self {
            left: self.left.clone(),
            right: self.right.clone(),
            marker: self.marker,
        }
    }
}

impl<C, L, R> Copy for Then<C, L, R>
where
    L: Copy,
    R: Copy,
{
}

impl<C, L, R> Then<C, L, R> {
    pub const fn new(pat: L, then: R) -> Self {
        Self {
            left: pat,
            right: then,
            marker: PhantomData,
        }
    }

    pub const fn left(&self) -> &L {
        &self.left
    }

    pub const fn left_mut(&mut self) -> &mut L {
        &mut self.left
    }

    pub const fn right(&self) -> &R {
        &self.right
    }

    pub const fn right_mut(&mut self) -> &mut R {
        &mut self.right
    }

    pub fn set_left(&mut self, pat: L) -> &mut Self {
        self.left = pat;
        self
    }

    pub fn set_right(&mut self, then: R) -> &mut Self {
        self.right = then;
        self
    }

    pub fn _0<O>(self) -> Map<C, Self, Select0, O> {
        Map::new(self, Select0)
    }

    pub fn _1<O>(self) -> Map<C, Self, Select1, O> {
        Map::new(self, Select1)
    }

    pub fn _eq<I1, I2>(self) -> Map<C, Self, SelectEq, (I1, I2)> {
        Map::new(self, SelectEq)
    }
}

impl<'a, C, L, R, O1, O2, H> Ctor<'a, C, (O1, O2), H> for Then<C, L, R>
where
    L: Ctor<'a, C, O1, H>,
    R: Ctor<'a, C, O2, H>,
    C: Match<'a>,
    H: Handler<C>,
{
    #[inline(always)]
    fn construct(&self, ctx: &mut C, func: &mut H) -> Result<(O1, O2), Error> {
        let mut ctx = CtxGuard::new(ctx);

        debug_ctor_beg!("Then", ctx.beg());

        let ret =
            debug_ctor_stage!("Then", "l", self.left.construct(ctx.ctx(), func)).and_then(|ret1| {
                debug_ctor_stage!("Then", "r", self.right.construct(ctx.ctx(), func))
                    .map(|ret2| (ret1, ret2))
            });
        let ret = ctx.process_ret(ret);

        debug_ctor_reval!("Then", ctx.beg(), ctx.end(), ret.is_ok());
        ret
    }
}

impl<'a, C, L, R> Regex<C> for Then<C, L, R>
where
    L: Regex<C>,
    R: Regex<C>,
    C: Match<'a>,
{
    #[inline(always)]
    fn try_parse(&self, ctx: &mut C) -> Result<Span, Error> {
        let mut ctx = CtxGuard::new(ctx);

        debug_regex_beg!("Then", ctx.beg());

        let mut ret = debug_regex_stage!("Then", "l", ctx.try_mat(&self.left)?);

        ret.add_assign(debug_regex_stage!("Then", "r", ctx.try_mat(&self.right)?));
        debug_regex_reval!("Then", Ok(ret))
    }
}

///
/// Conditionally extends a match with an optional suffix **only if** a test expression succeeds.
///
/// [`IfThen`] implements a **conditional sequence** pattern where:
/// 1. First matches the `left` expression (required)
/// 2. Then tests the `test` expression at the current position
/// 3. **Only if `test` succeeds**, matches the `right` expression
/// 4. Crucially: **`test` failure does NOT cause overall failure** - only `left` is required
///
/// This differs from standard sequence combinators by making the suffix conditional:
/// - Unlike [`Then<L, R>`]: The suffix (`test`+`right`) is optional
///
/// # Regex
///
/// Returns a [`Span`] covering:
/// - **Always** includes `left`'s matched text
/// - **Only if `test` succeeds**: Includes `test` + `right` matched text
/// - If `test` fails: Returns only `left`'s span (no error)
/// - If `test` succeeds but `right` fails: **Entire match fails**
///
/// ## Example
/// ```
/// # use neure::prelude::*;
/// #
/// # fn main() -> Result<(), Box<dyn core::error::Error>> {
///     let name = neu::word().many1();
///     let paras = name.sep(", ").enclose("<", ">");
///     let test = regex::assert("<", true);
///     let parser = name.if_then(test, paras);
///
///     assert_eq!(CharsCtx::new("Vec").try_mat(&parser)?, Span::new(0, 3));
///     assert_eq!(
///         CharsCtx::new("Vec<A, B>").try_mat(&parser)?,
///         Span::new(0, 9)
///     );
///
/// #   Ok(())
/// # }
/// ```
///
/// # Ctor
/// Returns a tuple `(O1, Option<O2>)` where:
/// - `O1`: Value constructed from `left` (always present)
/// - `Option<O2>`:
///   - `Some(O2)` if **both `test` and `right` succeeded**
///   - `None` if `test` failed
///
/// ## Example
/// ```
/// # use neure::prelude::*;
/// #
/// # fn main() -> Result<(), Box<dyn core::error::Error>> {
///     let val = neu::ascii_alphabetic().many1();
///     let tuple = val.if_then(",".skip_ws(), val).enclose("(", ")");
///
///     assert_eq!(CharsCtx::new("(abc)").ctor(&tuple)?, ("abc", None));
///     assert_eq!(
///         CharsCtx::new("(abc, cde)").ctor(&tuple)?,
///         ("abc", Some("cde"))
///     );
///
/// #   Ok(())
/// # }
/// ```
pub struct IfThen<C, L, I, R> {
    left: L,
    test: I,
    right: R,
    marker: PhantomData<C>,
}

impl_not_for_regex!(IfThen<C, L, I, R>);

impl<C, L, I, R> Debug for IfThen<C, L, I, R>
where
    L: Debug,
    R: Debug,
    I: Debug,
{
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        f.debug_struct("IfThen")
            .field("left", &self.left)
            .field("test", &self.test)
            .field("right", &self.right)
            .finish()
    }
}

impl<C, L, I, R> Default for IfThen<C, L, I, R>
where
    L: Default,
    R: Default,
    I: Default,
{
    fn default() -> Self {
        Self {
            left: Default::default(),
            test: Default::default(),
            right: Default::default(),
            marker: Default::default(),
        }
    }
}

impl<C, L, I, R> Clone for IfThen<C, L, I, R>
where
    L: Clone,
    R: Clone,
    I: Clone,
{
    fn clone(&self) -> Self {
        Self {
            test: self.test.clone(),
            left: self.left.clone(),
            right: self.right.clone(),
            marker: self.marker,
        }
    }
}

impl<C, L, I, R> Copy for IfThen<C, L, I, R>
where
    L: Copy,
    R: Copy,
    I: Copy,
{
}

impl<C, L, I, R> IfThen<C, L, I, R> {
    pub const fn new(left: L, test: I, right: R) -> Self {
        Self {
            test,
            left,
            right,
            marker: PhantomData,
        }
    }

    pub const fn test(&self) -> &I {
        &self.test
    }

    pub const fn test_mut(&mut self) -> &mut I {
        &mut self.test
    }

    pub const fn left(&self) -> &L {
        &self.left
    }

    pub const fn left_mut(&mut self) -> &mut L {
        &mut self.left
    }

    pub const fn right(&self) -> &R {
        &self.right
    }

    pub const fn right_mut(&mut self) -> &mut R {
        &mut self.right
    }

    pub fn set_test(&mut self, test: I) -> &mut Self {
        self.test = test;
        self
    }

    pub fn set_left(&mut self, pat: L) -> &mut Self {
        self.left = pat;
        self
    }

    pub fn set_right(&mut self, then: R) -> &mut Self {
        self.right = then;
        self
    }

    pub fn _0<O>(self) -> Map<C, Self, Select0, O> {
        Map::new(self, Select0)
    }

    pub fn _1<O>(self) -> Map<C, Self, Select1, O> {
        Map::new(self, Select1)
    }

    pub fn _eq<I1, I2>(self) -> Map<C, Self, SelectEq, (I1, I2)> {
        Map::new(self, SelectEq)
    }
}

impl<'a, C, L, I, R, O1, O2, H> Ctor<'a, C, (O1, Option<O2>), H> for IfThen<C, L, I, R>
where
    L: Ctor<'a, C, O1, H>,
    R: Ctor<'a, C, O2, H>,
    I: Regex<C>,
    C: Match<'a>,
    H: Handler<C>,
{
    #[inline(always)]
    fn construct(&self, ctx: &mut C, func: &mut H) -> Result<(O1, Option<O2>), Error> {
        let mut ctx = CtxGuard::new(ctx);

        debug_ctor_beg!("IfThen", ctx.beg());

        let l = debug_ctor_stage!("IfThen", "l", self.left.construct(ctx.ctx(), func));
        let l = ctx.process_ret(l)?;

        // reset offset if test failed
        let test = {
            let mut if_ctx = CtxGuard::new(ctx.ctx());

            debug_ctor_stage!("IfThen", "test", if_ctx.try_mat(&self.test)).is_ok()
        };

        let pair = if test {
            let r = debug_ctor_stage!("IfThen", "r", self.right.construct(ctx.ctx(), func));
            let r = ctx.process_ret(r)?;

            // if matched, return (01, Some(O2))
            (l, Some(r))
        } else {
            // not matched, return None
            (l, None)
        };

        debug_ctor_reval!("IfThen", ctx.beg(), ctx.end(), true);
        Ok(pair)
    }
}

impl<'a, C, L, I, R> Regex<C> for IfThen<C, L, I, R>
where
    I: Regex<C>,
    L: Regex<C>,
    R: Regex<C>,
    C: Match<'a>,
{
    #[inline(always)]
    fn try_parse(&self, ctx: &mut C) -> Result<Span, Error> {
        let mut ctx = CtxGuard::new(ctx);

        debug_regex_beg!("IfThen", ctx.beg());

        let mut ret = debug_regex_stage!("IfThen", "l", ctx.try_mat(&self.left)?);

        // reset offset if test failed
        let span = {
            let mut if_ctx = CtxGuard::new(ctx.ctx());

            debug_regex_stage!("IfThen", "test", if_ctx.try_mat(&self.test))
        };

        if let Ok(span) = span {
            ret.add_assign(span);
            ret.add_assign(debug_regex_stage!("IfThen", "r", ctx.try_mat(&self.right)?));
        }
        debug_regex_reval!("IfThen", Ok(ret))
    }
}
