use super::*;
use rxqlite_lite_common::*;
use std::error::Error;

pub trait RXQliteInto<U> {
  fn into_lite(self) -> U;
}

impl RXQliteInto<LearnerNotFound> for openraft::error::LearnerNotFound<NodeId> 
{
  fn into_lite(self) -> LearnerNotFound {
    LearnerNotFound {
      node_id: self.node_id,
    }
  }
}

impl RXQliteInto<EmptyMembership> for openraft::error::EmptyMembership
{
  fn into_lite(self) -> EmptyMembership {
    EmptyMembership {}
  }
}


impl RXQliteInto<InProgress> for openraft::error::InProgress<NodeId> 
{
  fn into_lite(self) -> InProgress {
    InProgress {
      committed: self.committed.map(|x|x.into_lite()),
      membership_log_id: self.membership_log_id.map(|x|x.into_lite()),
    }
  }
}

impl RXQliteInto<ChangeMembershipError> for openraft::error::ChangeMembershipError<NodeId> 
{
  fn into_lite(self) -> ChangeMembershipError {
    match self {
      Self::InProgress(e)=>ChangeMembershipError::InProgress(e.into_lite()),
      Self::EmptyMembership(e)=>ChangeMembershipError::EmptyMembership(e.into_lite()),
      Self::LearnerNotFound(e)=>ChangeMembershipError::LearnerNotFound(e.into_lite()),
    }
  }
}

impl RXQliteInto<ForwardToLeader> for openraft::error::ForwardToLeader<NodeId, Node> 
{
  fn into_lite(self) -> ForwardToLeader {
    ForwardToLeader {
      leader_id: self.leader_id,
      leader_node: self.leader_node,
    }
  }
}

impl RXQliteInto<ClientWriteError> for openraft::error::ClientWriteError<NodeId, Node> 
{
  fn into_lite(self) -> ClientWriteError {
    match self {
      Self::ForwardToLeader(e)=>ClientWriteError::ForwardToLeader(e.into_lite()),
      Self::ChangeMembershipError(e)=>ClientWriteError::ChangeMembershipError(e.into_lite()),
    }
  }
}

impl<Err: Error,FromErr> RXQliteInto<RaftError<Err>> for openraft::error::RaftError<NodeId, FromErr> 
  where FromErr: Error + RXQliteInto<Err> + Send + Sync
{
  fn into_lite(self) -> RaftError<Err> {
    match self {
      Self::APIError(e)=>RaftError::APIError(e.into_lite()),
      Self::Fatal(e)=>RaftError::Fatal(e.into_lite()),
    }
  }
}

impl RXQliteInto<RPCTypes> for openraft::RPCTypes 
{
  fn into_lite(self) -> RPCTypes {
    match self {
      Self::Vote=>RPCTypes::Vote,
      Self::AppendEntries=>RPCTypes::AppendEntries,
      Self::InstallSnapshot=>RPCTypes::InstallSnapshot,
    }
  }
}

impl RXQliteInto<Timeout> for openraft::error::Timeout<NodeId> 
{
  fn into_lite(self) -> Timeout {
    Timeout {
      action: self.action.into_lite(),
      id: self.id,
      target: self.target,
      timeout: self.timeout,
    }
  }
}

impl<T,U> RXQliteInto<RemoteError<U>> for openraft::error::RemoteError<NodeId,Node,T> 
where  T: Error + RXQliteInto<U>,
       U: Error
{
  fn into_lite(self) -> RemoteError<U> {
    RemoteError {
      target: self.target,
      target_node: self.target_node,
      source: self.source.into_lite(),
    }
  }
}

impl<Err: Error,FromErr> RXQliteInto<RPCError<Err>> for openraft::error::RPCError<NodeId, Node, FromErr> 
  where FromErr: Error + RXQliteInto<Err> + Send + Sync
{
  fn into_lite(self) -> RPCError<Err> {
    match self {
      Self::Timeout(to)=>RPCError::Timeout(to.into_lite()),
      Self::Unreachable(_)=>RPCError::Unreachable,
      Self::PayloadTooLarge(_)=>RPCError::PayloadTooLarge,
      Self::Network(_)=>RPCError::Network,
      Self::RemoteError(re)=>RPCError::RemoteError(re.into_lite()),
    }
  }
}

impl RXQliteInto<ClientWriteResponse> for typ::ClientWriteResponse {
  fn into_lite(self) -> ClientWriteResponse {
    ClientWriteResponse {
      log_id: self.log_id.into_lite(),
      data: self.data,
      membership:self.membership.map(|x|(&x).into_lite())
    }
  }
}

impl RXQliteInto<Infallible> for openraft::error::Infallible {
  fn into_lite(self) -> Infallible {
    panic!();
  }
}


impl<FromRes,FromErr,Res,Err> RXQliteInto<Result<Res,Err>> for Result<FromRes,FromErr > 
where FromRes: RXQliteInto<Res>,
  FromErr: RXQliteInto<Err>
{
  fn into_lite(self) -> Result<Res,Err> {
    self.map(|x| x.into_lite()).map_err(|err| err.into_lite())
  }
}

impl RXQliteInto<LeaderId> for typ::LeaderId {
  fn into_lite(self) -> LeaderId {
    LeaderId {
      term: self.term,
      node_id: self.node_id,
    }
  }
}

impl RXQliteInto<LogId> for typ::LogId {
  fn into_lite(self) -> LogId {
    LogId {
      leader_id: self.leader_id.into_lite(),
      index: self.index,
    }
  }
}

impl RXQliteInto<Vote> for typ::Vote {
  fn into_lite(self) -> Vote {
    Vote {
      leader_id: self.leader_id.into_lite(),
      committed: self.committed

,
    }
  }
}

impl RXQliteInto<ServerState> for openraft::ServerState {
  fn into_lite(self) -> ServerState {
    match self {
      Self::Learner=>ServerState::Learner,
      Self::Follower=>ServerState::Follower,
      Self::Candidate=>ServerState::Candidate,
      Self::Leader=>ServerState::Leader,
      Self::Shutdown=>ServerState::Shutdown,
    }
  }
}

//not using unsafe

impl RXQliteInto<Membership> for &typ::Membership {
  fn into_lite(self) -> Membership {
    Membership {
      configs : self.get_joint_config().clone(),
      nodes: self.nodes().map(|(id,node)|(*id,node.clone())).collect(),
    }
  }
}

impl RXQliteInto<StoredMembership> for &typ::StoredMembership {
  fn into_lite(self) -> StoredMembership {
    StoredMembership {
      log_id: self.log_id().map(|x|x.into_lite()),
      membership: self.membership().into_lite(),
    }
  }
}

impl RXQliteInto<Fatal> for openraft::error::Fatal<NodeId> {
  fn into_lite(self) -> Fatal {
    match self {
      Self::StorageError(_)=>Fatal::StorageError,
      Self::Panicked=>Fatal::Panicked,
      Self::Stopped=>Fatal::Stopped,
      
    }
  }
}
impl RXQliteInto<RaftMetrics> for typ::RaftMetrics {
  fn into_lite(self) -> RaftMetrics {
    RaftMetrics {
      running_state: self.running_state.map_err(|err| err.into_lite() ),
      id: self.id,
      current_term: self.current_term,
      vote: self.vote.into_lite(),
      last_log_index: self.last_log_index,
      last_applied: self.last_applied.map(|x|x.into_lite()),
      snapshot: self.snapshot.map(|x|x.into_lite()),
      purged: self.purged.map(|x|x.into_lite()),
      state: self.state.into_lite(),
      current_leader: self.current_leader,
      millis_since_quorum_ack: self.millis_since_quorum_ack,
      membership_config: self.membership_config.into_lite(),
    }
  }
}

