use crate::request::{Method, Request, Uri};
use crate::websocket::{CloseCode, ErrorCode, Message, MessageMode, MessageType};
use openssl::ssl::SslStream;
use std::io::{Error, ErrorKind, Read, Write};
use std::net::TcpStream;
use std::{io};
use std::sync::{Arc, Mutex};
use hpack::{Decoder, Encoder};
use log::{debug, info, warn};
use crate::response::Response;

#[derive(Debug, Clone)]
pub enum Scheme {
    Http(Arc<Mutex<TcpStream>>, String),
    Https(Arc<Mutex<SslStream<TcpStream>>>, String),
}

impl Scheme {
    const CRLF2: [u8; 4] = [13, 10, 13, 10];
    const REQUEST_LINE: [u8; 2] = [13, 10];
    pub fn request_line(&mut self, bytes: &mut Vec<u8>, request: &mut Request) -> io::Result<()> {
        // 头部处理
        loop {
            let pos = bytes.windows(Self::REQUEST_LINE.len()).position(|window| window == Self::REQUEST_LINE);
            if pos.is_none() {
                self.read_data(bytes, request)?;
                continue;
            }
            let data = bytes.drain(..pos.unwrap()).collect::<Vec<u8>>();
            bytes.drain(..Self::REQUEST_LINE.len());
            let res = String::from_utf8_lossy(data.as_slice());
            request.set_request_line(&res, bytes)?;
            break;
        }
        Ok(())
    }
    pub fn request_header(&mut self, bytes: &mut Vec<u8>, request: &mut Request) -> io::Result<()> {
        // 头部处理
        loop {
            let pos = bytes.windows(Self::CRLF2.len()).position(|window| window == Self::CRLF2);
            if pos.is_none() {
                self.read_data(bytes, request)?;
                continue;
            }
            let data = bytes.drain(..pos.unwrap()).collect::<Vec<u8>>();
            bytes.drain(..Self::CRLF2.len());
            let res = String::from_utf8_lossy(data.as_slice());
            request.set_headers(res.lines());
            break;
        }
        Ok(())
    }
    pub fn request_body(&mut self, bytes: &mut Vec<u8>, request: &mut Request) -> io::Result<()> {
        loop {
            if request.body.content_length == 0 {
                break;
            }
            if bytes.len() >= request.body.content_length {
                request.body.set_content(bytes.clone());
                bytes.drain(..request.body.content_length);
                break;
            }
            self.read_data(bytes, request)?;
        }
        Ok(())
    }
    pub fn read_data(&mut self, bytes: &mut Vec<u8>, request: &mut Request) -> io::Result<()> {
        let mut buf = [0u8; 16384];
        let usize = match self {
            Scheme::Http(stream, client_ip) => match stream.lock().unwrap().try_clone()?.read(&mut buf) {
                Ok(e) => e,
                Err(e) => {
                    let header = String::from_utf8_lossy(&buf);
                    return Err(Error::other(format!("读取客户端[{client_ip}]http头部信息失败: {e}  消息内容: [{header:?}]"),
                    ));
                }
            },
            Scheme::Https(stream, client_ip) => match stream.lock().unwrap().read(&mut buf) {
                Ok(e) => e,
                Err(e) => {
                    let header = String::from_utf8_lossy(&buf);
                    return Err(Error::other(
                        format!("读取客户端[{client_ip}]https头部信息失败: {e} 消息内容: [{header:?}]"),
                    ));
                }
            },
        };
        bytes.extend(&buf[..usize]);
        request.raw_data.extend(&buf[..usize]);
        Ok(())
    }
    /// 写入
    pub fn write(&mut self, data: &[u8]) -> io::Result<()> {
        match self {
            Scheme::Http(stream, _) => {
                stream.lock().unwrap().write_all(data)?;
                stream.lock().unwrap().flush()?;
            }
            Scheme::Https(stream, _) => {
                stream.lock().unwrap().write_all(data)?;
                stream.lock().unwrap().flush()?;
            }
        }
        Ok(())
    }
    pub fn read_ws_msg(&mut self) -> io::Result<Message> {
        let mut response = vec![];
        loop {
            let mut buffer = [0u8; 512];
            match self {
                Scheme::Http(stream, _) => {
                    stream.lock().unwrap().set_nonblocking(true)?;
                    match stream.lock().unwrap().read(&mut buffer) {
                        Ok(0) => {
                            return Ok(Message {
                                mode: MessageMode::Client,
                                message_type: MessageType::Close,
                                payload: vec![],
                                text: CloseCode::ClientClose.str(),
                                close: CloseCode::ClientClose,
                                error: ErrorCode::None,
                            })
                        }
                        Ok(n) => {
                            response.extend(buffer[..n].to_vec());
                            let message = Message::parse_message(&mut response);
                            if let MessageType::Continuation = message.message_type { continue; }
                            return Ok(message);
                        }
                        Err(ref e) if e.kind() == ErrorKind::WouldBlock => {
                            return Ok(Message {
                                mode: MessageMode::Client,
                                message_type: MessageType::TimeOut,
                                payload: vec![],
                                text: e.to_string(),
                                close: CloseCode::None,
                                error: ErrorCode::None,
                            });
                        }
                        Err(e) => {
                            return Ok(Message {
                                mode: MessageMode::Client,
                                message_type: MessageType::Error,
                                payload: vec![],
                                text: e.to_string(),
                                close: CloseCode::Other,
                                error: ErrorCode::Unknown,
                            });
                        }
                    };
                }
                Scheme::Https(ref mut stream, _) => {
                    match stream.lock().unwrap().read(&mut buffer) {
                        Ok(0) => {
                            return Ok(Message {
                                mode: MessageMode::Client,
                                message_type: MessageType::Close,
                                payload: vec![],
                                text: CloseCode::ClientClose.str(),
                                close: CloseCode::ClientClose,
                                error: ErrorCode::None,
                            })
                        }
                        Ok(n) => {
                            response.extend(buffer[..n].to_vec());
                            let message = Message::parse_message(&mut response);
                            if let MessageType::Continuation = message.message_type { continue; }
                            {
                                response = vec![];
                                message
                            }
                        }
                        Err(e) => {
                            return Ok(Message {
                                mode: MessageMode::Client,
                                message_type: MessageType::Error,
                                payload: vec![],
                                text: e.to_string(),
                                close: CloseCode::None,
                                error: ErrorCode::None,
                            });
                        }
                    };
                }
            }
        }
    }

    pub fn http2_handle(&mut self, bytes: &mut Vec<u8>, request: &mut Request, response: &mut Response, server_ip: &str, client_ip: &str) -> io::Result<()> {
        let mut body = vec![];
        loop {
            let (payload, frame_type, flags, stream_id) = self.get_http2_packet(bytes, request)?;
            if response.config.debug {
                info!("frame_type: {frame_type:?} flags: {flags} stream_id: {stream_id} data: {payload:?}");
            }
            match frame_type {
                FrameType::Data => {
                    if flags == 1 {
                        body.extend(payload);
                        request.body.set_content(body.clone());
                        body = vec![];
                        response.set_request(request);
                        response.stream_id = stream_id;
                        if bytes.is_empty() {
                            return Ok(());
                        }
                    } else {
                        body.extend(payload);
                    }
                }
                FrameType::Headers => {
                    let mut decoder = Decoder::new();
                    let headers = decoder.decode(&payload).unwrap();
                    for (name, value) in headers {
                        let header_name = unsafe { String::from_utf8_unchecked(name) };
                        let header_value = unsafe { String::from_utf8_unchecked(value) };
                        match header_name.as_str() {
                            ":method" => {
                                request.method = Method::from(header_value.as_str());
                            }
                            ":path" => {
                                request.uri = Uri::from(header_value.as_str());
                            }
                            ":scheme" => request.uri.scheme = header_value.to_string(),
                            ":authority" => {
                                request.header["host"] = header_value.into();
                            }
                            _ => {
                                request.set_http2_headers(&header_name, &header_value);
                            }
                        }
                    }
                    request.handle(server_ip, client_ip);
                    if request.config.debug {
                        let text = request.header.entries().map(|(key, value)| {
                            format!("{key}: {value}")
                        }).collect::<Vec<String>>().join("\n");
                        debug!("\r\n=================请求HTTP2信息=================\r\n{text}\r\n========================================");
                    }
                }
                FrameType::RstStream => {}
                FrameType::Settings => {
                    if !payload.is_empty() {
                        self.http2_init_settings()?;
                    } else {
                        self.http2_settings()?;
                    }
                }
                FrameType::Ping => {}
                FrameType::Goaway => {
                    let text = unsafe { String::from_utf8_unchecked(payload) };
                    //if text.as_str() == "SETTINGS expected" {}
                    if request.config.debug {
                        warn!("Goaway: {text}");
                    }
                    return Ok(());
                }
                FrameType::WindowUpdate => {
                    if response.config.debug {
                        let text = unsafe { String::from_utf8_unchecked(payload) };
                        info!("WindowUpdate: {text}");
                    }
                }
                FrameType::Continuation => {}
                FrameType::None => {}
            }
        }
    }
    /// 发送认证参数
    pub fn http2_init_settings(&mut self) -> io::Result<()> {
        let settings_frame = vec![
            0x00, 0x00, 0x00, // length = 0
            0x04,             // type = SETTINGS
            0x00,             // flags = none
            0x00, 0x00, 0x00, 0x00, // stream id = 0
            0x00, 0x01,       // identifier: SETTINGS_HEADER_TABLE_SIZE
            0x40, 0x00        // value: 16384
        ];
        self.write(settings_frame.as_slice())?;
        Ok(())
    }
    pub fn http2_settings(&mut self) -> io::Result<()> {
        let settings_frame = vec![
            0x00, 0x00, 0x00, // length = 0
            0x04,             // type = SETTINGS
            0x01,             // flags = none
            0x00, 0x00, 0x00, 0x00, // stream id = 0
        ];
        self.write(settings_frame.as_slice())?;
        Ok(())
    }
    pub fn http2_goaway(&mut self, last_stream_id: u32, error_code: u32) -> io::Result<()> {
        // 构造帧头
        let mut frame = Vec::new();
        // length = 8 bytes
        frame.extend_from_slice(&[0x00, 0x00, 0x08]); // length
        frame.push(0x07); // type = GOAWAY
        frame.push(0x00); // flags = none
        frame.extend_from_slice(&[0x00, 0x00, 0x00, 0x00]); // stream id = 0
        frame.extend_from_slice(&last_stream_id.to_be_bytes());
        frame.extend_from_slice(&error_code.to_be_bytes());
        self.write(frame.as_slice())?;
        Ok(())
    }
    fn get_http2_data(&mut self, bytes: &mut Vec<u8>, length: usize, request: &mut Request) -> io::Result<()> {
        loop {
            if bytes.len() >= length {
                return Ok(());
            }
            let mut buf = [0u8; 16384];
            let usize = match self {
                Scheme::Http(stream, client_ip) => {
                    match stream.lock().unwrap().try_clone().unwrap().read(&mut buf) {
                        Ok(e) => e,
                        Err(e) => {
                            return Err(Error::other(
                                format!("读取客户端[{client_ip}]http消息体失败: {e}"),
                            ))
                        }
                    }
                }
                Scheme::Https(stream, client_ip) => match stream.lock().unwrap().read(&mut buf) {
                    Ok(e) => e,
                    Err(e) => {
                        return Err(Error::other(
                            format!("读取客户端[{client_ip}]https消息体失败: {e}"),
                        ))
                    }
                },
            };
            request.raw_data.extend(&buf[..usize]);
            bytes.extend(&buf[..usize]);
            if bytes.len() >= length {
                return Ok(());
            }
        }
    }
    pub fn get_http2_packet(&mut self, bytes: &mut Vec<u8>, request: &mut Request) -> io::Result<(Vec<u8>, FrameType, u8, u32)> {
        self.get_http2_data(bytes, 9, request)?;
        let headers = bytes.drain(..9).collect::<Vec<u8>>();
        let length = ((headers[0] as u32) << 16) | (u32::from(headers[1]) << 8) | u32::from(headers[2]);
        let frame_type = headers[3];
        let flags = headers[4];
        let stream_id = u32::from_be_bytes([headers[5], headers[6], headers[7], headers[8]]) & 0x7FFF_FFFF;
        self.get_http2_data(bytes, length as usize, request)?;
        let payload = bytes.drain(..length as usize).collect::<Vec<u8>>();
        Ok((payload, FrameType::from(frame_type), flags, stream_id))
    }

    pub fn send_http2(&mut self, response: &mut Response) -> io::Result<()> {
        let header_data = self.http2_header(response.stream_id, response);
        let data_frame = self.http2_body(response.stream_id, &response.body.clone(), true);
        self.write(header_data.as_slice())?;
        self.write(data_frame.as_slice())?;
        self.http2_goaway(response.stream_id, 0)?;
        Ok(())
    }
    fn http2_header(&mut self, stream_id: u32, response: &mut Response) -> Vec<u8> {
        let mut encoder = Encoder::new();

        let mut headers = vec![
            (":status".as_bytes().to_vec(), "200".as_bytes().to_vec()),
            ("cache-control".as_bytes().to_vec(), "no-cache".as_bytes().to_vec()),
        ];

        let headers_sub = response.headers.entries().map(|(key, value)| {
            (key.to_string().as_bytes().to_vec(), value.to_string().as_bytes().to_vec())
        }).collect::<Vec<(Vec<u8>, Vec<u8>)>>();

        headers.extend(headers_sub);

        if response.config.debug {
            let mut header = vec![];
            for (name, value) in headers.clone() {
                let header_name = unsafe { String::from_utf8_unchecked(name) };
                let header_value = unsafe { String::from_utf8_unchecked(value) };
                header.push(format!("{header_name}: {header_value}"));
            }
            debug!("\r\n=================响应信息=================\r\n{}\r\n===========================================",header.join("\r\n"));
        }
        let header_block = encoder.encode(headers.iter().map(|h| (&h.0[..], &h.1[..])));


        let length = header_block.len();
        let mut frame = Vec::with_capacity(9 + length);

        // 帧头
        frame.push(u8::try_from((length >> 16) & 0xFF).unwrap()); // length high
        frame.push(u8::try_from((length >> 8) & 0xFF).unwrap());  // length mid
        frame.push(u8::try_from(length & 0xFF).unwrap());         // length low
        frame.push(0x01); // type = HEADERS
        frame.push(0x04);

        // stream ID (big endian)
        frame.extend_from_slice(&(stream_id & 0x7FFF_FFFF).to_be_bytes());
        frame.extend_from_slice(&header_block);
        frame
    }

    fn http2_body(&mut self, stream_id: u32, payload: &[u8], end_stream: bool) -> Vec<u8> {
        let length = payload.len();
        let mut frame = Vec::with_capacity(9 + length);

        frame.push(u8::try_from((length >> 16) & 0xFF).unwrap());
        frame.push(u8::try_from((length >> 8) & 0xFF).unwrap());
        frame.push(u8::try_from(length & 0xFF).unwrap());
        frame.push(0x00); // Type = DATA
        if end_stream {
            frame.push(0x01);
        } else {
            frame.push(0x00); // Flags = END_STREAM
        }
        frame.extend_from_slice(&(stream_id & 0x7FFF_FFFF).to_be_bytes());
        frame.extend_from_slice(payload);
        frame
    }
}
#[derive(Debug)]
pub enum FrameType {
    Data,
    Headers,
    RstStream,
    Settings,
    Ping,
    Goaway,
    WindowUpdate,
    Continuation,
    None,
}
impl FrameType {
    fn from(code: u8) -> FrameType {
        match code {
            0x00 => FrameType::Data,
            0x01 => FrameType::Headers,
            0x03 => FrameType::RstStream,
            0x04 => FrameType::Settings,
            0x06 => FrameType::Ping,
            0x07 => FrameType::Goaway,
            0x08 => FrameType::WindowUpdate,
            0x09 => FrameType::Continuation,
            _ => FrameType::None,
        }
    }
}

/// HTTP协议版本
#[derive(Clone, Debug)]
pub enum Protocol {
    HTTP1_0,
    HTTP1_1,
    HTTP2,
    None,
}

impl Protocol {
    #[must_use]
    pub fn from(name: &str) -> Self {
        match name.to_lowercase().as_str() {
            "http/1.0" => Self::HTTP1_0,
            "http/1.1" => Self::HTTP1_1,
            "http/2.0" | "http/2" => Self::HTTP2,
            _ => {
                warn!("未知协议: {name}");
                Self::None
            }
        }
    }
    pub fn str(&mut self) -> String {
        match self {
            Protocol::HTTP1_0 => "HTTP/1.0",
            Protocol::HTTP1_1 | Protocol::None => "HTTP/1.1",
            Protocol::HTTP2 => "HTTP/2.0",
        }.to_string()
    }
}