use std::thread;
use mio::{Events, Poll, Token, Ready, PollOpt};
use mio::tcp::TcpStream;
use mio_extras::channel::{channel, Sender, Receiver};

use crate::common::clientpool::{ClientPool, ClientAction, ClientPoolAction};
use crate::common::serverstate::{RecvServerPacket, SendServerPacket, ServerState, OnConnect, ClientId};





fn recv_from_clientpool<STATE, S, R, E>(state: &mut STATE,
                                        pool_recv: &Receiver<ClientPoolAction<R>>,
                                        pool_send: &Sender<ClientAction<S>>) where
    STATE: ServerState<SendPacket=S, RecvPacket=R, PacketError=E>,
    S: SendServerPacket,
    R: RecvServerPacket,
    E: std::fmt::Debug,
{
    loop {
        match pool_recv.try_recv() {
            Ok(incoming) => {
                match incoming {
                    ClientPoolAction::NewClient(client_id) => {
                        for s in state.on_connect(client_id).into_iter() {
                            match s {
                                OnConnect::Cipher((in_cipher, out_cipher)) => {
                                    pool_send.send(ClientAction::EncryptionKeys(client_id, in_cipher, out_cipher)).unwrap();
                                }
                                OnConnect::Packet(pkt) => {
                                    pool_send.send(ClientAction::Packet(client_id, pkt)).unwrap();
                                }
                            }
                        }
                    },
                    ClientPoolAction::Packet(client_id, pkt) => {
                        let to_send = state.handle(client_id, &pkt);
                        match to_send {
                            Ok(pkts) =>  {
                                for p in pkts {
                                    pool_send.send(ClientAction::Packet(p.0, p.1)).unwrap();
                                }
                            },
                            Err(err) => {
                                // TODO: break?
                                println!("[handler error]: {:?} {:?}", client_id, err);
                            }
                        }
                    }
                }
            },
            Err(_err) => {
                break;
            }
        }
    }  
}


pub fn mainloop<STATE, S, R, E>(mut state: STATE, port: u16) where
    STATE: ServerState<SendPacket=S, RecvPacket=R, PacketError=E> + Send + 'static,
    S: SendServerPacket + std::fmt::Debug + Send + 'static,
    R: RecvServerPacket + std::fmt::Debug + Send + 'static,
    E: std::fmt::Debug,
{
    let (pool_send, pool_recv) = channel();
    //let (patch_handler_send, patch_handler_recv) = channel::<ClientPoolAction<RecvPatchPacket>>();
    let (handler_send, handler_recv) = channel();

    //let sender_clone = patch_handler_send.clone();
    let client_thread = thread::spawn(move || {
        let clientpool = ClientPool::new(pool_recv, handler_send, port);
        clientpool.io_loop();
    });

    let handler_threadpool = threadpool::ThreadPool::new(4);
    let handler_thread = thread::spawn(move || {
        let poll = Poll::new().unwrap();
        poll.register(&handler_recv, Token(0), Ready::readable(), PollOpt::edge()).unwrap();

        let mut events = Events::with_capacity(1024);

        loop {
            poll.poll(&mut events, None).unwrap();
            
            for event in &events {
                match event.token() {
                    Token(0) => recv_from_clientpool(&mut state, &handler_recv, &pool_send),
                    _ => panic!()
                }
            }
        }
    });

    client_thread.join().unwrap();
    handler_thread.join().unwrap();
}