use std::ops::Bound;
use safecast::TryCastFrom;
use tc_error::*;
use tc_transact::public::generic::COPY;
use tc_transact::public::helpers::{AttributeHandler, EchoHandler};
use tc_transact::public::value;
use tc_transact::public::{
    ClosureInstance, DeleteHandler, GetHandler, Handler, PostHandler, PutHandler, Route,
    StateInstance,
};
use tc_transact::RPCClient;
use tc_value::{Number, TCString, Value};
use tcgeneric::{Id, Map, PathSegment, TCPathBuf, Tuple};
use crate::{ClusterRef, Refer, Scalar, ScalarType};
impl<State> Route<State> for ScalarType
where
    State: StateInstance,
{
    fn route<'a>(&'a self, _path: &'a [PathSegment]) -> Option<Box<dyn Handler<'a, State> + 'a>> {
        None
    }
}
struct ClusterHandler {
    path: TCPathBuf,
}
impl ClusterHandler {
    fn new(cluster: &ClusterRef, path: &[PathSegment]) -> Self {
        let mut cluster_path = cluster.path().clone();
        cluster_path.extend(path.into_iter().cloned());
        Self { path: cluster_path }
    }
}
impl<'a, State> Handler<'a, State> for ClusterHandler
where
    State: StateInstance,
{
    fn get<'b>(self: Box<Self>) -> Option<GetHandler<'a, 'b, State::Txn, State>>
    where
        'b: 'a,
    {
        Some(Box::new(|txn, key| Box::pin(txn.get(self.path, key))))
    }
    fn put<'b>(self: Box<Self>) -> Option<PutHandler<'a, 'b, State::Txn, State>>
    where
        'b: 'a,
    {
        Some(Box::new(|txn, key, value| {
            Box::pin(txn.put(self.path, key, value))
        }))
    }
    fn post<'b>(self: Box<Self>) -> Option<PostHandler<'a, 'b, State::Txn, State>>
    where
        'b: 'a,
    {
        Some(Box::new(|txn, params| {
            Box::pin(txn.post(self.path, params))
        }))
    }
    fn delete<'b>(self: Box<Self>) -> Option<DeleteHandler<'a, 'b, State::Txn>>
    where
        'b: 'a,
    {
        Some(Box::new(|txn, key| Box::pin(txn.delete(self.path, key))))
    }
}
impl<State> Route<State> for ClusterRef
where
    State: StateInstance,
{
    fn route<'a>(&'a self, path: &'a [PathSegment]) -> Option<Box<dyn Handler<'a, State> + 'a>> {
        Some(Box::new(ClusterHandler::new(self, path)))
    }
}
impl<State> Route<State> for Scalar
where
    State: StateInstance
        + Refer<State>
        + From<Scalar>
        + From<Tuple<Scalar>>
        + From<Map<Scalar>>
        + From<Value>
        + From<Tuple<Value>>
        + From<Number>,
    Box<dyn ClosureInstance<State>>: TryCastFrom<State>,
    Id: TryCastFrom<State>,
    Map<State>: TryFrom<State, Error = TCError> + TryCastFrom<State>,
    Number: TryCastFrom<State>,
    TCString: TryCastFrom<State>,
    Tuple<State>: TryCastFrom<State>,
    Value: TryCastFrom<State>,
{
    fn route<'a>(&'a self, path: &'a [PathSegment]) -> Option<Box<dyn Handler<'a, State> + 'a>> {
        if path == ©[..] {
            return Some(Box::new(AttributeHandler::from(self.clone())));
        }
        match self {
            Self::Cluster(cluster) => cluster.route(path),
            Self::Map(map) => map.route(path),
            Self::Op(op_def) if path.is_empty() => Some(Box::new(op_def.clone())),
            Self::Range((start, end)) => {
                if path.is_empty() {
                    None
                } else {
                    match path[0].as_str() {
                        "start" => match start {
                            Bound::Included(value) => value.route(&path[1..]),
                            Bound::Excluded(value) => value.route(&path[1..]),
                            Bound::Unbounded => Value::None.route(&path[1..]),
                        },
                        "end" => match end {
                            Bound::Included(value) => value.route(&path[1..]),
                            Bound::Excluded(value) => value.route(&path[1..]),
                            Bound::Unbounded => Value::None.route(&path[1..]),
                        },
                        _ => None,
                    }
                }
            }
            Self::Ref(_) => None,
            Self::Value(value) => value.route(path),
            Self::Tuple(tuple) => tuple.route(path),
            _ => None,
        }
    }
}
pub struct Static;
impl<State> Route<State> for Static
where
    State: StateInstance,
{
    fn route<'a>(&'a self, path: &'a [PathSegment]) -> Option<Box<dyn Handler<'a, State> + 'a>> {
        if path.is_empty() {
            Some(Box::new(EchoHandler))
        } else if path[0] == value::PREFIX {
            value::Static.route(&path[1..])
        } else {
            None
        }
    }
}