use std::{
    cmp::{
        self,
        Ordering,
    },
    iter,
    mem,
    panic::{
        self,
        AssertUnwindSafe,
    },
    rc::Rc,
    slice,
};

use anyhow::anyhow;
use ecow::EcoVec;
use itertools::Itertools;
use ordermap::{
    OrderMap,
    OrderSet,
};

use crate::{
    env::{
        EuEnv,
        EuEnvCtx,
        EuScope,
    },
    types::{
        EuErr,
        EuRes,
        EuSeqT,
        EuSyn,
        EuType,
    },
    utils::{
        IterExt,
        swap_errors,
        unpanic,
    },
};

impl<'eu> EuType<'eu> {
    pub fn unfold<F>(mut self, mut f: F) -> impl EuSeqT<'eu>
    where
        F: FnMut(&mut Self) -> EuRes<(Self, Self)> + Clone + 'eu,
    {
        iter::from_fn(move || {
            f(&mut self)
                .map(|(st, t)| {
                    self = st;
                    t.to_opt()
                })
                .transpose()
        })
    }

    #[inline]
    pub fn unfold_env(self, f: Self, scope: EuScope<'eu>, ctx: &'eu EuEnvCtx) -> EuRes<Self> {
        f.vecz1(move |f| {
            let f = f.to_expr()?;
            Ok(Self::seq(self.unfold(move |acc| {
                EuEnv::apply_n_2(f.clone(), slice::from_mut(acc), scope.clone(), ctx)
            })))
        })
    }

    #[inline]
    #[must_use]
    pub fn repeat(self) -> impl EuSeqT<'eu> {
        iter::repeat(Ok(self))
    }

    #[inline]
    pub fn repeat_n(self, n: usize) -> EuRes<EcoVec<Self>> {
        self.repeat().take(n).try_collect()
    }

    #[inline]
    #[must_use]
    pub fn cycle(self) -> impl EuSeqT<'eu> {
        match self {
            Self::Seq(it) => it.cycle(),
            _ => self.to_seq().cycle(),
        }
    }

    pub fn at(self, i: isize) -> EuRes<Option<Self>> {
        match self {
            Self::Opt(o) => Ok((i == 0).then(|| o.map(|t| *t)).flatten()),
            Self::Res(r) => Self::Opt(r.ok()).at(i),
            Self::Vec(mut ts) => Ok(if i < 0 {
                ts.len().checked_add_signed(i)
            } else {
                Some(i.cast_unsigned())
            }
            .and_then(|i| ts.make_mut().get_mut(i).map(mem::take))),
            Self::Map(mut kvs) => Ok(if i < 0 {
                kvs.len().checked_add_signed(i)
            } else {
                Some(i.cast_unsigned())
            }
            .and_then(|i| {
                Rc::make_mut(&mut kvs)
                    .get_index_mut(i)
                    .map(|(k, v)| Self::vec([k.clone(), mem::take(v)]))
            })),
            Self::Set(mut ts) => Ok(if i < 0 {
                ts.len().checked_add_signed(i)
            } else {
                Some(i.cast_unsigned())
            }
            .and_then(|i| Rc::make_mut(&mut ts).get_index(i).cloned())),
            Self::Seq(mut it) => {
                if i < 0 {
                    Self::Vec(Self::Seq(it).to_vec()?).at(i)
                } else {
                    it.nth(i.cast_unsigned()).transpose()
                }
            }
            _ => Self::Vec(self.to_vec()?).at(i),
        }
    }

    pub fn take(self, n: isize) -> EuRes<Self> {
        let a = n.unsigned_abs();
        match self {
            Self::Opt(o) => Ok(Self::Opt((n != 0).then_some(o).flatten())),
            Self::Res(r) => Self::Opt(r.ok()).take(n),
            Self::Vec(ts) => Ok(if n < 0 {
                Self::vec(&ts[ts.len().saturating_sub(a)..])
            } else {
                Self::vec(&ts[..cmp::min(a, ts.len())])
            }),
            Self::Map(kvs) => Ok(Self::Map(Rc::new({
                let it = Rc::unwrap_or_clone(kvs).into_iter();
                if n < 0 {
                    it.rev().take(a).rev().collect()
                } else {
                    it.take(a).collect()
                }
            }))),
            Self::Set(ts) => Ok(Self::Set(Rc::new({
                let it = Rc::unwrap_or_clone(ts).into_iter();
                if n < 0 {
                    it.rev().take(a).rev().collect()
                } else {
                    it.take(a).collect()
                }
            }))),
            Self::Seq(it) => {
                if n < 0 {
                    Self::vec(Self::Seq(it).to_vec()?).take(n)
                } else {
                    Ok(Self::seq(it.take(a)))
                }
            }
            _ => Self::Vec(self.to_vec()?).take(n),
        }
    }

    pub fn drop(self, n: isize) -> EuRes<Self> {
        let a = n.unsigned_abs();
        match self {
            Self::Opt(o) => Ok(Self::Opt(if n != 0 { None } else { o })),
            Self::Res(r) => Self::Opt(r.ok()).drop(n),
            Self::Vec(ts) => Ok(if n < 0 {
                Self::vec(&ts[..ts.len().saturating_sub(a)])
            } else {
                Self::vec(&ts[cmp::min(a, ts.len())..])
            }),
            Self::Map(kvs) => Ok(Self::Map(Rc::new({
                let it = Rc::unwrap_or_clone(kvs).into_iter();
                if n < 0 {
                    it.rev().skip(a).rev().collect()
                } else {
                    it.skip(a).collect()
                }
            }))),
            Self::Set(ts) => Ok(Self::Set(Rc::new({
                let it = Rc::unwrap_or_clone(ts).into_iter();
                if n < 0 {
                    it.rev().skip(a).rev().collect()
                } else {
                    it.skip(a).collect()
                }
            }))),
            Self::Seq(it) => {
                if n < 0 {
                    Self::vec(Self::Seq(it).to_vec()?).drop(n)
                } else {
                    Ok(Self::seq(it.skip(a)))
                }
            }
            _ => Self::Vec(self.to_vec()?).take(n),
        }
    }

    pub fn chunk(self, n: isize) -> EuRes<Self> {
        let a = n.unsigned_abs();
        match self {
            Self::Opt(_) => Self::Vec(self.to_vec()?)
                .chunk(n)?
                .map(|t| t.at(0).map(Self::opt)),
            Self::Res(r) => Self::Opt(r.ok()).chunk(n),
            Self::Vec(ts) => {
                if n < 0 {
                    let len = ts.len();
                    Ok(Self::Vec(split(ts, len, a, Self::Vec)))
                } else {
                    Self::Seq(Self::Vec(ts).to_seq()).chunk(n)
                }
            }
            Self::Map(kvs) => Ok(if n < 0 {
                let len = kvs.len();
                Self::Vec(split(Rc::unwrap_or_clone(kvs), len, a, |kvs| {
                    Self::Map(Rc::new(kvs))
                }))
            } else {
                Self::seq(Rc::unwrap_or_clone(kvs).into_iter().batching(move |it| {
                    let kvs: OrderMap<_, _> = it.take(a).collect();
                    (a == 0 || !kvs.is_empty()).then_some(Ok(Self::map_(kvs)))
                }))
            }),
            Self::Set(ts) => Ok(if n < 0 {
                let len = ts.len();
                Self::Vec(split(Rc::unwrap_or_clone(ts), len, a, |ts| {
                    Self::Set(Rc::new(ts))
                }))
            } else {
                Self::seq(Rc::unwrap_or_clone(ts).into_iter().batching(move |it| {
                    let ts: OrderSet<_, _> = it.take(a).collect();
                    (a == 0 || !ts.is_empty()).then_some(Ok(Self::set(ts)))
                }))
            }),
            Self::Seq(it) => {
                if n < 0 {
                    Self::vec(Self::Seq(it).to_vec()?).chunk(n)
                } else {
                    Ok(Self::seq(it.batching(move |it| {
                        it.take(a)
                            .try_collect()
                            .map(|ts: EcoVec<_>| {
                                (a == 0 || !ts.is_empty()).then_some(Self::Vec(ts))
                            })
                            .transpose()
                    })))
                }
            }
            _ => Self::Vec(self.to_vec()?).chunk(n),
        }
    }

    #[inline]
    pub fn window(self, n: usize) -> EuRes<Self> {
        self.divvy(n, 1)
    }

    pub fn divvy(self, n: usize, m: isize) -> EuRes<Self> {
        let a = m.unsigned_abs();
        match self {
            Self::Opt(_) => Self::Vec(self.to_vec()?)
                .divvy(n, m)?
                .map(|t| t.at(0).map(Self::opt)),
            Self::Res(r) => Self::Opt(r.ok()).divvy(n, m),
            Self::Vec(ref ts) => {
                if m < 0 {
                    let l = ts.len().saturating_sub(n).div_ceil(a);
                    self.divvy(n, l.cast_signed())?.to_vec().map(Self::Vec)
                } else {
                    Self::Seq(self.to_seq()).divvy(n, m)
                }
            }
            Self::Map(kvs) => {
                if m < 0 {
                    let l = kvs.len().saturating_sub(n).div_ceil(a);
                    Self::Map(kvs)
                        .divvy(n, l.cast_signed())?
                        .to_vec()
                        .map(Self::Vec)
                } else {
                    let rem_empty = OrderMap::with_capacity(n.saturating_sub(a));
                    let mut rem = rem_empty.clone();
                    let mut first = true;
                    Ok(Self::seq(Rc::unwrap_or_clone(kvs).into_iter().batching(
                        move |it| {
                            if first {
                                first = false;
                            } else {
                                it.dropping(a.saturating_sub(n));
                            }
                            let n_kvs = n - rem.len();
                            let kvs: OrderMap<_, _> = it.take(n_kvs).collect();
                            (kvs.len() >= n_kvs).then(|| {
                                rem.extend(kvs);
                                let res = mem::replace(&mut rem, rem_empty.clone());
                                rem.extend(res.iter().skip(a).map(|(k, v)| (k.clone(), v.clone())));
                                Ok(Self::map_(res))
                            })
                        },
                    )))
                }
            }
            Self::Set(ts) => {
                if m < 0 {
                    let l = ts.len().saturating_sub(n).div_ceil(a);
                    Self::Set(ts)
                        .divvy(n, l.cast_signed())?
                        .to_vec()
                        .map(Self::Vec)
                } else {
                    let rem_empty = OrderSet::with_capacity(n.saturating_sub(a));
                    let mut rem = rem_empty.clone();
                    let mut first = true;
                    Ok(Self::seq(Rc::unwrap_or_clone(ts).into_iter().batching(
                        move |it| {
                            if first {
                                first = false;
                            } else {
                                it.dropping(a.saturating_sub(n));
                            }
                            let n_ts = n - rem.len();
                            let ts: OrderSet<_> = it.take(n_ts).collect();
                            (ts.len() >= n_ts).then(|| {
                                rem.extend(ts);
                                let res = mem::replace(&mut rem, rem_empty.clone());
                                rem.extend(res.iter().skip(a).cloned());
                                Ok(Self::set(res))
                            })
                        },
                    )))
                }
            }
            Self::Seq(it) => {
                if m < 0 {
                    Self::vec(Self::Seq(it).to_vec()?).divvy(n, m)
                } else {
                    let rem_empty = EcoVec::with_capacity(n.saturating_sub(a));
                    let mut rem = rem_empty.clone();
                    let mut first = true;
                    Ok(Self::seq(it.batching(move |it| {
                        if first {
                            first = false;
                        } else {
                            it.dropping(a.saturating_sub(n));
                        }
                        let n_ts = n - rem.len();
                        it.take(n_ts)
                            .try_collect::<_, EcoVec<_>, _>()
                            .map(|ts| {
                                (ts.len() >= n_ts).then(|| {
                                    rem.extend(ts);
                                    let res = mem::replace(&mut rem, rem_empty.clone());
                                    rem.extend(res.iter().skip(a).cloned());
                                    Self::Vec(res)
                                })
                            })
                            .transpose()
                    })))
                }
            }
            _ => Self::Vec(self.to_vec()?).divvy(n, m),
        }
    }

    #[must_use]
    pub fn enumerate(self) -> Self {
        match self {
            Self::Seq(it) => Self::seq(it.enumerate().map(Self::enum_to_pair)),
            _ => Self::seq(self.to_seq()).enumerate(),
        }
    }

    fn enum_to_pair((i, r): (usize, EuRes<Self>)) -> EuRes<Self> {
        let i = i
            .try_into()
            .map_err(|_| anyhow!("failed to convert `{i}` to i64"))?;
        r.map(|t| Self::vec([Self::I64(i), t]))
    }

    #[must_use]
    pub fn pairs(self) -> Self {
        match self {
            Self::Seq(it) => Self::seq(it.map(|r| r?.to_pair().map(|(a, b)| Self::vec([a, b])))),
            _ => Self::seq(self.to_seq()).pairs(),
        }
    }

    pub fn multi_cartesian_product(ts: impl IntoIterator<Item = Self>) -> impl EuSeqT<'eu> {
        ts.into_iter()
            .map(Self::to_seq)
            .multi_cartesian_product()
            .map(|rs| rs.into_iter().try_collect().map(Self::Vec))
    }

    pub fn multi_zip(ts: impl IntoIterator<Item = Self>) -> impl EuSeqT<'eu> {
        let mut it = ts.into_iter().map(Self::to_seq).collect_vec();
        iter::from_fn(move || {
            it.iter_mut()
                .map(Iterator::next)
                .collect::<Option<Result<_, _>>>()
                .map(|r| r.map(Self::Vec))
        })
    }

    pub fn sep(self, sep: Self) -> EuRes<Self> {
        match self {
            Self::Seq(it) => Ok(Self::seq(Iterator::intersperse(it, Ok(sep)))),
            _ if self.is_many() => Ok(Self::Vec(
                Iterator::intersperse(self.into_iter(), sep).collect(),
            )),
            _ => Self::Vec(self.to_vec()?).sep(sep),
        }
    }

    pub fn for_rec<F>(self, f: &mut F) -> EuRes<()>
    where
        F: FnMut(EcoVec<EuSyn<'eu>>) -> EuRes<()>,
    {
        if self.is_vecz() {
            for t in self.to_seq() {
                t?.for_rec(f)?;
            }
            Ok(())
        } else {
            f(self.to_expr()?)
        }
    }

    pub fn vecz1<F>(self, f: F) -> EuRes<Self>
    where
        F: FnOnce(Self) -> EuRes<Self> + Clone + 'eu,
    {
        if self.is_many() {
            self.map(move |t| t.vecz1(f.clone()))
        } else if self.is_once() {
            self.map_once(|t| t.vecz1(f))
        } else {
            f(self)
        }
    }

    pub fn vecz1_2<F>(self, f: F) -> EuRes<(Self, Self)>
    where
        F: FnOnce(Self) -> EuRes<(Self, Self)> + Clone + 'eu,
    {
        if self.is_many() {
            self.map_2(move |t| t.vecz1_2(f.clone()))
        } else if self.is_once() {
            self.map_2_once(|t| t.vecz1_2(f))
        } else {
            f(self)
        }
    }

    pub fn vecz2<F>(self, t: Self, f: F) -> EuRes<Self>
    where
        F: FnOnce(Self, Self) -> EuRes<Self> + Clone + 'eu,
    {
        if self.is_many() || t.is_many() {
            self.zip(t, move |a, b| a.vecz2(b, f.clone()))
        } else if self.is_once() {
            self.zip_once(t, |a, b| a.vecz2(b, f))
        } else {
            f(self, t)
        }
    }

    pub fn map<F>(self, mut f: F) -> EuRes<Self>
    where
        F: FnMut(Self) -> EuRes<Self> + Clone + 'eu,
    {
        match self {
            Self::Seq(it) => Ok(Self::seq(it.map(move |t| f(t?)))),
            Self::Vec(ts) => ts.into_iter().map(f).try_collect().map(Self::Vec),
            Self::Map(kvs) => Rc::unwrap_or_clone(kvs)
                .into_iter()
                .map(|(k, v)| f(v).map(|v| (k, v)))
                .try_collect()
                .map(|kvs| Self::Map(Rc::new(kvs))),
            Self::Set(ts) => Rc::unwrap_or_clone(ts)
                .into_iter()
                .map(f)
                .try_collect()
                .map(|ts| Self::Set(Rc::new(ts))),
            _ => self.map_once(f),
        }
    }

    pub fn map_once<F>(self, f: F) -> EuRes<Self>
    where
        F: FnOnce(Self) -> EuRes<Self> + 'eu,
    {
        match self {
            Self::Opt(o) => o.map(|t| f(*t)).transpose().map(Self::opt),
            Self::Res(r) => swap_errors(r.map(|t| f(*t).map(Box::new))).map(Self::Res),
            _ => f(self),
        }
    }

    pub fn map_env(self, f: Self, scope: EuScope<'eu>, ctx: &'eu EuEnvCtx) -> EuRes<Self> {
        f.vecz1(move |f| {
            let f = f.to_expr()?;
            if self.is_many() {
                self.map(move |t| EuEnv::apply_n_1(f.clone(), &[t], scope.clone(), ctx))
            } else {
                self.map_once(|t| EuEnv::apply_n_1(f, &[t], scope, ctx))
            }
        })
    }

    pub fn map_2<F>(self, mut f: F) -> EuRes<(Self, Self)>
    where
        F: FnMut(Self) -> EuRes<(Self, Self)> + Clone + 'eu,
    {
        match self {
            Self::Seq(_) => Self::vec(self.to_vec()?).map_2(f),
            Self::Vec(ts) => ts
                .into_iter()
                .map(f)
                .try_collect()
                .map(|(a, b)| (Self::Vec(a), Self::Vec(b))),
            Self::Map(kvs) => Rc::unwrap_or_clone(kvs)
                .into_iter()
                .map(|(k, v)| f(v).map(|(v0, v1)| ((k.clone(), v0), (k, v1))))
                .try_collect()
                .map(|(a, b)| (Self::Map(Rc::new(a)), Self::Map(Rc::new(b)))),
            Self::Set(ts) => Rc::unwrap_or_clone(ts)
                .into_iter()
                .map(f)
                .try_collect()
                .map(|(a, b)| (Self::Set(Rc::new(a)), Self::Set(Rc::new(b)))),
            _ => self.map_2_once(f),
        }
    }

    pub fn map_2_once<F>(self, f: F) -> EuRes<(Self, Self)>
    where
        F: FnOnce(Self) -> EuRes<(Self, Self)> + 'eu,
    {
        match self {
            Self::Opt(o) => {
                let (a, b) = o
                    .map(|t| f(*t))
                    .transpose()?
                    .map_or((None, None), |(a, b)| (Some(a), Some(b)));
                Ok((Self::opt(a), Self::opt(b)))
            }
            Self::Res(r) => {
                let (a, b) = swap_errors(r.map(|t| f(*t)))?.map_or_else(
                    |e| (Err(e.clone()), Err(e)),
                    |(a, b)| (Ok(Box::new(a)), Ok(Box::new(b))),
                );
                Ok((Self::Res(a), Self::Res(b)))
            }
            _ => f(self),
        }
    }

    pub fn map_atom_env(self, f: Self, scope: EuScope<'eu>, ctx: &'eu EuEnvCtx) -> EuRes<Self> {
        f.vecz1(move |f| {
            let f = f.to_expr()?;
            self.vecz1(|t| EuEnv::apply_n_1(f, &[t], scope, ctx))
        })
    }

    pub fn flat_map<F>(self, mut f: F) -> EuRes<Self>
    where
        F: FnMut(Self) -> EuRes<Self> + Clone + 'eu,
    {
        match self {
            Self::Seq(it) => Ok(Self::seq(it.flat_map(move |r| match r.and_then(&mut f) {
                Ok(t) => t.to_seq(),
                e => Box::new(iter::once(e)),
            }))),
            _ if self.is_many() => self
                .into_iter()
                .flat_map(move |t| match f(t) {
                    Ok(t) => t.to_seq(),
                    e => Box::new(iter::once(e)),
                })
                .try_collect()
                .map(Self::Vec),
            _ => self.flat_map_once(f),
        }
    }

    pub fn flat_map_once<F>(self, f: F) -> EuRes<Self>
    where
        F: FnOnce(Self) -> EuRes<Self> + 'eu,
    {
        match self {
            Self::Opt(o) => o
                .and_then(|t| match f(*t) {
                    Ok(Self::Opt(o)) => o.map(Ok),
                    t => Some(t.map(Box::new)),
                })
                .transpose()
                .map(Self::Opt),
            Self::Res(r) => swap_errors(r.and_then(|t| match f(*t) {
                Ok(Self::Res(r)) => r.map(Ok),
                t => Ok(t.map(Box::new)),
            }))
            .map(Self::Res),
            _ => f(self),
        }
    }

    pub fn flat_map_env(self, f: Self, scope: EuScope<'eu>, ctx: &'eu EuEnvCtx) -> EuRes<Self> {
        f.vecz1(move |f| {
            let f = f.to_expr()?;
            if self.is_many() {
                self.flat_map(move |t| EuEnv::apply_n_1(f.clone(), &[t], scope.clone(), ctx))
            } else {
                self.flat_map_once(|t| EuEnv::apply_n_1(f, &[t], scope, ctx))
            }
        })
    }

    pub fn flatten(self) -> EuRes<Self> {
        self.flat_map(Ok)
    }

    pub fn flatten_rec(self) -> EuRes<Self> {
        if self.is_vecz() {
            self.flat_map(Self::flatten_rec)
        } else {
            Ok(self)
        }
    }

    pub fn filter<F>(self, mut f: F) -> EuRes<Self>
    where
        F: FnMut(&Self) -> EuRes<bool> + Clone + 'eu,
    {
        match self {
            Self::Seq(it) => Ok(Self::seq(it.filter_map(move |r| {
                r.and_then(|t| f(&t).map(|b| b.then_some(t))).transpose()
            }))),
            Self::Vec(ts) => ts
                .into_iter()
                .filter_map(|t| f(&t).map(|b| b.then_some(t)).transpose())
                .try_collect()
                .map(Self::Vec),
            Self::Map(kvs) => Rc::unwrap_or_clone(kvs)
                .into_iter()
                .filter_map(|kv| f(&kv.1).map(|b| b.then_some(kv)).transpose())
                .try_collect()
                .map(|kvs| Self::Map(Rc::new(kvs))),
            Self::Set(ts) => Rc::unwrap_or_clone(ts)
                .into_iter()
                .filter_map(|t| f(&t).map(|b| b.then_some(t)).transpose())
                .try_collect()
                .map(|ts| Self::Set(Rc::new(ts))),
            _ => self.filter_once(f),
        }
    }

    pub fn filter_once<F>(self, f: F) -> EuRes<Self>
    where
        F: FnOnce(&Self) -> EuRes<bool> + 'eu,
    {
        match self {
            Self::Opt(o) => o
                .and_then(|t| {
                    let t = *t;
                    f(&t).map(|b| b.then_some(t)).transpose()
                })
                .transpose()
                .map(Self::opt),
            Self::Res(r) => Self::Opt(r.ok()).filter_once(f),
            _ => Self::opt(self.to_opt()).filter_once(f),
        }
    }

    pub fn filter_env(self, f: Self, scope: EuScope<'eu>, ctx: &'eu EuEnvCtx) -> EuRes<Self> {
        f.vecz1(move |f| {
            let f = f.to_expr()?;
            if self.is_many() {
                self.filter(move |t| {
                    EuEnv::apply_n_1(f.clone(), slice::from_ref(t), scope.clone(), ctx)
                        .map(Self::into)
                })
            } else {
                self.filter_once(|t| {
                    EuEnv::apply_n_1(f, slice::from_ref(t), scope, ctx).map(Self::into)
                })
            }
        })
    }

    pub fn take_while<F>(self, mut f: F) -> EuRes<Self>
    where
        F: FnMut(&Self) -> EuRes<bool> + Clone + 'eu,
    {
        match self {
            Self::Seq(it) => Ok(Self::seq(it.map_while(move |r| {
                r.and_then(|t| f(&t).map(|b| b.then_some(t))).transpose()
            }))),
            Self::Vec(ts) => ts
                .into_iter()
                .map_while(|t| f(&t).map(|b| b.then_some(t)).transpose())
                .try_collect()
                .map(Self::Vec),
            Self::Map(kvs) => Rc::unwrap_or_clone(kvs)
                .into_iter()
                .map_while(|kv| f(&kv.1).map(|b| b.then_some(kv)).transpose())
                .try_collect()
                .map(|kvs| Self::Map(Rc::new(kvs))),
            Self::Set(ts) => Rc::unwrap_or_clone(ts)
                .into_iter()
                .map_while(|t| f(&t).map(|b| b.then_some(t)).transpose())
                .try_collect()
                .map(|ts| Self::Set(Rc::new(ts))),
            _ => self.take_while_once(f),
        }
    }

    pub fn take_while_once<F>(self, f: F) -> EuRes<Self>
    where
        F: FnOnce(&Self) -> EuRes<bool> + 'eu,
    {
        self.filter_once(f)
    }

    pub fn take_while_env(self, f: Self, scope: EuScope<'eu>, ctx: &'eu EuEnvCtx) -> EuRes<Self> {
        f.vecz1(move |f| {
            let f = f.to_expr()?;
            if self.is_many() {
                self.take_while(move |t| {
                    EuEnv::apply_n_1(f.clone(), slice::from_ref(t), scope.clone(), ctx)
                        .map(Self::into)
                })
            } else {
                self.take_while_once(|t| {
                    EuEnv::apply_n_1(f, slice::from_ref(t), scope, ctx).map(Self::into)
                })
            }
        })
    }

    pub fn drop_while<F>(self, mut f: F) -> EuRes<Self>
    where
        F: FnMut(&Self) -> EuRes<bool> + Clone + 'eu,
    {
        match self {
            Self::Seq(it) => Ok(Self::seq(it.skip_while_ok(f))),
            Self::Vec(ts) => ts
                .into_iter()
                .map(Ok)
                .skip_while_ok(f)
                .try_collect()
                .map(Self::Vec),
            Self::Map(kvs) => Rc::unwrap_or_clone(kvs)
                .into_iter()
                .map(Ok)
                .skip_while_ok(|(_, v)| f(v))
                .try_collect()
                .map(|kvs| Self::Map(Rc::new(kvs))),
            Self::Set(ts) => Rc::unwrap_or_clone(ts)
                .into_iter()
                .map(Ok)
                .skip_while_ok(f)
                .try_collect()
                .map(|kvs| Self::Set(Rc::new(kvs))),
            _ => self.drop_while_once(f),
        }
    }

    pub fn drop_while_once<F>(self, f: F) -> EuRes<Self>
    where
        F: FnOnce(&Self) -> EuRes<bool> + 'eu,
    {
        self.filter_once(|t| f(t).map(|b| !b))
    }

    pub fn drop_while_env(self, f: Self, scope: EuScope<'eu>, ctx: &'eu EuEnvCtx) -> EuRes<Self> {
        f.vecz1(move |f| {
            let f = f.to_expr()?;
            if self.is_many() {
                self.drop_while(move |t| {
                    EuEnv::apply_n_1(f.clone(), slice::from_ref(t), scope.clone(), ctx)
                        .map(Self::into)
                })
            } else {
                self.drop_while_once(|t| {
                    EuEnv::apply_n_1(f, slice::from_ref(t), scope, ctx).map(Self::into)
                })
            }
        })
    }

    pub fn zip<F>(self, t: Self, mut f: F) -> EuRes<Self>
    where
        F: FnMut(Self, Self) -> EuRes<Self> + Clone + 'eu,
    {
        let is_many_0 = self.is_many();
        let is_many_1 = t.is_many();
        if is_many_0 && is_many_1 {
            if self.is_seq() || t.is_seq() {
                Ok(Self::seq(self.to_seq().zip(t.to_seq()).map(
                    move |(a, b)| a.and_then(|a| b.and_then(|b| f(a, b))),
                )))
            } else {
                self.into_iter()
                    .zip(t)
                    .map(|(a, b)| f(a, b))
                    .try_collect()
                    .map(Self::Vec)
            }
        } else if is_many_0 {
            self.map(move |a| f(a, t.clone()))
        } else if is_many_1 {
            t.map(move |b| f(self.clone(), b))
        } else {
            self.zip_once(t, f)
        }
    }

    pub fn zip_once<F>(self, t: Self, f: F) -> EuRes<Self>
    where
        F: FnOnce(Self, Self) -> EuRes<Self> + 'eu,
    {
        match (self, t) {
            (Self::Opt(a), Self::Opt(b)) => {
                a.zip(b).map(|(a, b)| f(*a, *b)).transpose().map(Self::opt)
            }
            (Self::Res(Ok(a)), Self::Res(Ok(b))) => f(*a, *b).map(|t| Self::res(Ok(t))),
            (Self::Res(a), Self::Res(b)) => Ok(Self::Res(a.and(b))),
            (a, b) if a.is_once() => a.map_once(|t| f(t, b)),
            (a, b) if b.is_once() => b.map_once(|t| f(a, t)),
            (a, b) => f(a, b),
        }
    }

    pub fn zip_env(self, t: Self, f: Self, scope: EuScope<'eu>, ctx: &'eu EuEnvCtx) -> EuRes<Self> {
        f.vecz1(move |f| {
            let f = f.to_expr()?;
            if self.is_many() || t.is_many() {
                self.zip(t, move |a, b| {
                    EuEnv::apply_n_1(f.clone(), &[a, b], scope.clone(), ctx)
                })
            } else {
                self.zip_once(t, |a, b| EuEnv::apply_n_1(f, &[a, b], scope, ctx))
            }
        })
    }

    pub fn zip_atom_env(
        self,
        t: Self,
        f: Self,
        scope: EuScope<'eu>,
        ctx: &'eu EuEnvCtx,
    ) -> EuRes<Self> {
        f.vecz1(move |f| {
            let f = f.to_expr()?;
            self.vecz2(t, |a, b| EuEnv::apply_n_1(f, &[a, b], scope, ctx))
        })
    }

    pub fn fold<F>(self, init: Self, mut f: F) -> EuRes<Self>
    where
        F: FnMut(Self, Self) -> EuRes<Self> + 'eu,
    {
        match self {
            Self::Seq(mut it) => it.try_fold(init, |acc, t| f(acc, t?)),
            _ if self.is_many() => self.into_iter().try_fold(init, f),
            _ => self.fold_once(init, f),
        }
    }

    pub fn fold_once<F>(self, init: Self, f: F) -> EuRes<Self>
    where
        F: FnOnce(Self, Self) -> EuRes<Self> + 'eu,
    {
        match self.to_opt() {
            Some(t) => f(init, t),
            None => Ok(init),
        }
    }

    pub fn fold_env(
        self,
        init: Self,
        f: Self,
        scope: EuScope<'eu>,
        ctx: &'eu EuEnvCtx,
    ) -> EuRes<Self> {
        f.vecz1(move |f| {
            let f = f.to_expr()?;
            if self.is_many() {
                self.fold(init, move |acc, t| {
                    EuEnv::apply_n_1(f.clone(), &[acc, t], scope.clone(), ctx)
                })
            } else {
                self.fold_once(init, |acc, t| EuEnv::apply_n_1(f, &[acc, t], scope, ctx))
            }
        })
    }

    pub fn fold1<F>(self, mut f: F) -> EuRes<Option<Self>>
    where
        F: FnMut(Self, Self) -> EuRes<Self> + 'eu,
    {
        match self {
            Self::Seq(it) => it.reduce(|a, b| f(a?, b?)).transpose(),
            _ if self.is_many() => self.into_iter().try_reduce(f),
            _ => Ok(self.fold1_once()),
        }
    }

    #[inline]
    #[must_use]
    pub fn fold1_once(self) -> Option<Self> {
        self.to_opt()
    }

    pub fn fold1_env(self, f: Self, scope: EuScope<'eu>, ctx: &'eu EuEnvCtx) -> EuRes<Self> {
        f.vecz1(move |f| {
            let f = f.to_expr()?;
            if self.is_many() {
                self.fold1(move |a, b| EuEnv::apply_n_1(f.clone(), &[a, b], scope.clone(), ctx))
            } else {
                Ok(self.fold1_once())
            }
            .map(Self::opt)
        })
    }

    pub fn scan<F>(self, init: Self, mut f: F) -> EuRes<Self>
    where
        F: FnMut(&mut Self, Self) -> EuRes<(Self, Self)> + Clone + 'eu,
    {
        match self {
            Self::Seq(it) => Ok(Self::seq(it.scan(init, move |acc, t| {
                t.and_then(|t| f(acc, t))
                    .map(|(st, t)| {
                        *acc = st;
                        t.to_opt()
                    })
                    .transpose()
            }))),
            _ if self.is_many() => self
                .into_iter()
                .scan(init, |acc, t| {
                    f(acc, t)
                        .map(|(st, t)| {
                            *acc = st;
                            t.to_opt()
                        })
                        .transpose()
                })
                .try_collect()
                .map(Self::Vec),
            _ => self.scan_once(init, f),
        }
    }

    pub fn scan_once<F>(self, mut init: Self, f: F) -> EuRes<Self>
    where
        F: FnOnce(&mut Self, Self) -> EuRes<(Self, Self)> + 'eu,
    {
        match self {
            Self::Opt(Some(t)) => Ok(Self::opt(f(&mut init, *t)?.1.to_opt())),
            Self::Res(Ok(t)) => Ok(Self::res(match f(&mut init, *t)?.1 {
                Self::Opt(Some(t)) | Self::Res(Ok(t)) => Ok(*t),
                Self::Res(Err(e)) => Err(*e),
                e @ Self::Opt(None) => Err(e),
                t => Ok(t),
            })),
            _ => Ok(self),
        }
    }

    pub fn scan_env(
        self,
        init: Self,
        f: Self,
        scope: EuScope<'eu>,
        ctx: &'eu EuEnvCtx,
    ) -> EuRes<Self> {
        f.vecz1(move |f| {
            let f = f.to_expr()?;
            if self.is_many() {
                self.scan(init, move |acc, t| {
                    EuEnv::apply_n_2(f.clone(), &[mem::take(acc), t], scope.clone(), ctx)
                })
            } else {
                self.scan_once(init, move |acc, t| {
                    EuEnv::apply_n_2(f, &[mem::take(acc), t], scope, ctx)
                })
            }
        })
    }

    pub fn sort(mut self) -> EuRes<Self> {
        match self {
            Self::Seq(it) => it.sorted().try_collect().map(Self::Vec),
            Self::Vec(ref mut ts) => {
                ts.make_mut().sort();
                Ok(self)
            }
            Self::Map(ref mut kvs) => {
                Rc::make_mut(kvs).sort_unstable_keys();
                Ok(self)
            }
            Self::Set(ref mut ts) => {
                Rc::make_mut(ts).sort_unstable();
                Ok(self)
            }
            _ => Self::Vec(self.to_vec()?).sort(),
        }
    }

    pub fn sort_by<F>(mut self, mut f: F) -> EuRes<Self>
    where
        F: FnMut(&Self, &Self) -> EuRes<Ordering>,
    {
        match self {
            Self::Seq(it) => unpanic(AssertUnwindSafe(|| {
                it.sorted_by(|a, b| {
                    f(
                        a.as_ref().unwrap_or_else(|e| panic::panic_any(e.clone())),
                        b.as_ref().unwrap_or_else(|e| panic::panic_any(e.clone())),
                    )
                    .unwrap_or_else(|e| panic::panic_any(e))
                })
                .try_collect()
                .map_or_else(|e| panic::panic_any(e), Self::Vec)
            }))
            .map_err(|e| {
                #[expect(clippy::missing_panics_doc, reason = "infallible")]
                *e.downcast::<EuErr>().unwrap()
            }),
            Self::Vec(ref mut ts) => {
                let res = unpanic(AssertUnwindSafe(|| {
                    ts.make_mut()
                        .sort_by(|a, b| f(a, b).unwrap_or_else(|e| panic::panic_any(e)));
                }));
                res.map(|()| self).map_err(|e| {
                    #[expect(clippy::missing_panics_doc, reason = "infallible")]
                    *e.downcast::<EuErr>().unwrap()
                })
            }
            Self::Map(ref mut kvs) => {
                let res = unpanic(AssertUnwindSafe(|| {
                    Rc::make_mut(kvs).sort_by(|k0, v0, k1, v1| {
                        f(
                            &Self::vec([k0.clone(), v0.clone()]),
                            &Self::vec([k1.clone(), v1.clone()]),
                        )
                        .unwrap_or_else(|e| panic::panic_any(e))
                    });
                }));
                res.map(|()| self).map_err(|e| {
                    #[expect(clippy::missing_panics_doc, reason = "infallible")]
                    *e.downcast::<EuErr>().unwrap()
                })
            }
            Self::Set(ref mut ts) => {
                let res = unpanic(AssertUnwindSafe(|| {
                    Rc::make_mut(ts)
                        .sort_by(|a, b| f(a, b).unwrap_or_else(|e| panic::panic_any(e)));
                }));
                res.map(|()| self).map_err(|e| {
                    #[expect(clippy::missing_panics_doc, reason = "infallible")]
                    *e.downcast::<EuErr>().unwrap()
                })
            }
            _ => Self::Vec(self.to_vec()?).sort_by(f),
        }
    }

    pub fn sort_by_env(self, f: Self, scope: EuScope<'eu>, ctx: &'eu EuEnvCtx) -> EuRes<Self> {
        f.vecz1(move |f| {
            let f = f.to_expr()?;
            self.sort_by(move |a, b| {
                EuEnv::apply_n_1(f.clone(), &[a.clone(), b.clone()], scope.clone(), ctx)
                    .map(|t| t.cmp(&Self::ibig(0)))
            })
        })
    }

    pub fn sort_by_key<F>(mut self, mut f: F) -> EuRes<Self>
    where
        F: FnMut(&Self) -> EuRes<Self>,
    {
        match self {
            Self::Seq(it) => unpanic(AssertUnwindSafe(|| {
                it.sorted_by_key(|t| {
                    f(t.as_ref().unwrap_or_else(|e| panic::panic_any(e.clone())))
                        .unwrap_or_else(|e| panic::panic_any(e))
                })
                .try_collect()
                .map_or_else(|e| panic::panic_any(e), Self::Vec)
            }))
            .map_err(|e| {
                #[expect(clippy::missing_panics_doc, reason = "infallible")]
                *e.downcast::<EuErr>().unwrap()
            }),
            Self::Vec(ref mut ts) => unpanic(AssertUnwindSafe(|| {
                ts.make_mut()
                    .sort_by_key(|t| f(t).unwrap_or_else(|e| panic::panic_any(e)));
            }))
            .map(|()| self)
            .map_err(|e| {
                #[expect(clippy::missing_panics_doc, reason = "infallible")]
                *e.downcast::<EuErr>().unwrap()
            }),
            Self::Map(ref mut kvs) => unpanic(AssertUnwindSafe(|| {
                Rc::make_mut(kvs).sort_by_key(|k, v| {
                    f(&Self::vec([k.clone(), v.clone()])).unwrap_or_else(|e| panic::panic_any(e))
                });
            }))
            .map(|()| self)
            .map_err(|e| {
                #[expect(clippy::missing_panics_doc, reason = "infallible")]
                *e.downcast::<EuErr>().unwrap()
            }),
            Self::Set(ref mut ts) => unpanic(AssertUnwindSafe(|| {
                Rc::make_mut(ts).sort_by_key(|t| f(t).unwrap_or_else(|e| panic::panic_any(e)));
            }))
            .map(|()| self)
            .map_err(|e| {
                #[expect(clippy::missing_panics_doc, reason = "infallible")]
                *e.downcast::<EuErr>().unwrap()
            }),
            _ => Self::Vec(self.to_vec()?).sort(),
        }
    }

    pub fn sort_by_key_env(self, f: Self, scope: EuScope<'eu>, ctx: &'eu EuEnvCtx) -> EuRes<Self> {
        f.vecz1(move |f| {
            let f = f.to_expr()?;
            self.sort_by_key(|t| {
                EuEnv::apply_n_1(f.clone(), slice::from_ref(t), scope.clone(), ctx)
            })
        })
    }

    pub fn find<F>(self, mut f: F) -> EuRes<Option<Self>>
    where
        F: FnMut(&Self) -> EuRes<bool> + 'eu,
    {
        match self {
            Self::Seq(mut it) => it
                .try_find(|r| r.as_ref().map_err(Clone::clone).and_then(&mut f))
                .and_then(Option::transpose),
            _ if self.is_many() => self.into_iter().try_find(f),
            _ => self.find_once(f),
        }
    }

    pub fn find_once<F>(self, f: F) -> EuRes<Option<Self>>
    where
        F: FnOnce(&Self) -> EuRes<bool> + 'eu,
    {
        match self {
            Self::Opt(o) => o
                .and_then(|t| {
                    let t = *t;
                    f(&t).map(|b| b.then_some(t)).transpose()
                })
                .transpose(),
            Self::Res(r) => Self::Opt(r.ok()).find_once(f),
            _ => Self::opt(self.to_opt()).find_once(f),
        }
    }

    pub fn find_env(self, f: Self, scope: EuScope<'eu>, ctx: &'eu EuEnvCtx) -> EuRes<Self> {
        f.vecz1(move |f| {
            let f = f.to_expr()?;
            if self.is_many() {
                self.find(move |t| {
                    EuEnv::apply_n_1(f.clone(), slice::from_ref(t), scope.clone(), ctx)
                        .map(Self::into)
                })
            } else {
                self.find_once(|t| {
                    EuEnv::apply_n_1(f, slice::from_ref(t), scope, ctx).map(Self::into)
                })
            }
            .map(Self::opt)
        })
    }

    pub fn any<F>(self, f: F) -> EuRes<bool>
    where
        F: FnMut(&Self) -> EuRes<bool> + 'eu,
    {
        self.find(f).map(|o| o.is_some())
    }

    pub fn any_once<F>(self, f: F) -> EuRes<bool>
    where
        F: FnOnce(&Self) -> EuRes<bool> + 'eu,
    {
        self.find_once(f).map(|o| o.is_some())
    }

    pub fn any_env(self, f: Self, scope: EuScope<'eu>, ctx: &'eu EuEnvCtx) -> EuRes<Self> {
        f.vecz1(move |f| {
            let f = f.to_expr()?;
            if self.is_many() {
                self.any(move |t| {
                    EuEnv::apply_n_1(f.clone(), slice::from_ref(t), scope.clone(), ctx)
                        .map(Self::into)
                })
            } else {
                self.any_once(|t| {
                    EuEnv::apply_n_1(f, slice::from_ref(t), scope, ctx).map(Self::into)
                })
            }
            .map(Self::Bool)
        })
    }

    pub fn all<F>(self, mut f: F) -> EuRes<bool>
    where
        F: FnMut(&Self) -> EuRes<bool> + 'eu,
    {
        self.any(move |t| f(t).map(|b| !b)).map(|b| !b)
    }

    pub fn all_once<F>(self, f: F) -> EuRes<bool>
    where
        F: FnOnce(&Self) -> EuRes<bool> + 'eu,
    {
        self.any_once(|t| f(t).map(|b| !b)).map(|b| !b)
    }

    pub fn all_env(self, f: Self, scope: EuScope<'eu>, ctx: &'eu EuEnvCtx) -> EuRes<Self> {
        f.vecz1(move |f| {
            let f = f.to_expr()?;
            if self.is_many() {
                self.all(move |t| {
                    EuEnv::apply_n_1(f.clone(), slice::from_ref(t), scope.clone(), ctx)
                        .map(Self::into)
                })
            } else {
                self.all_once(|t| {
                    EuEnv::apply_n_1(f, slice::from_ref(t), scope, ctx).map(Self::into)
                })
            }
            .map(Self::Bool)
        })
    }
}

fn split<T, U, V, W>(
    ts: impl IntoIterator<Item = T>,
    len: usize,
    a: usize,
    inner: impl Fn(U) -> V,
) -> W
where
    U: FromIterator<T>,
    W: FromIterator<V>,
{
    let l = len / a;
    let mut r = len % a;
    let mut c = a;
    ts.into_iter()
        .batching(move |it| {
            if c == 0 {
                return None;
            }
            c -= 1;
            let mut l = l;
            if r > 0 {
                l += 1;
                r -= 1;
            }
            Some(inner(it.take(l).collect()))
        })
        .collect()
}
