use crate::enums::event::Event;
use crate::enums::internal_event::InternalEvent;
use crate::models::plain_text::PlainText;
use crate::switchboard_server::p2p::binary_header::BinaryHeader;
use core::str;
use deku::DekuContainerRead;
use std::io::Cursor;

pub fn into_event(message: &Vec<u8>) -> Option<Event> {
    let reply = unsafe { str::from_utf8_unchecked(message.as_slice()) };
    let command = reply.lines().next().unwrap_or_default().to_string() + "\r\n";

    let args: Vec<&str> = command.split_ascii_whitespace().collect();
    match *args.first().unwrap_or(&"") {
        "MSG" => {
            let payload = reply.replace(command.as_str(), "");
            let content_type = payload.lines().nth(1)?;

            if content_type.contains("text/plain")
                && let Some(email) = args.get(1)
            {
                return Some(Event::TextMessage {
                    email: email.to_string(),
                    message: PlainText::new(payload),
                });
            }

            if content_type.contains("text/x-msnmsgr-datacast") {
                let text = payload.split("\r\n\r\n").nth(1).unwrap_or_default();
                if text == "ID: 1"
                    && let Some(email) = args.get(1)
                {
                    return Some(Event::Nudge {
                        email: email.to_string(),
                    });
                }
            }

            if content_type.contains("text/x-msmsgscontrol") {
                let typing_user = payload.lines().nth(2)?;
                return Some(Event::TypingNotification {
                    email: typing_user.replace("TypingUser: ", ""),
                });
            }

            None
        }

        "JOI" => args.get(1).map(|email| Event::ParticipantInSwitchboard {
            email: email.to_string(),
        }),

        "IRO" => args.get(4).map(|email| Event::ParticipantInSwitchboard {
            email: email.to_string(),
        }),

        "BYE" => args.get(1).map(|email| Event::ParticipantLeftSwitchboard {
            email: email.to_string(),
        }),

        _ => None,
    }
}

pub fn into_internal_event(message: &[u8]) -> InternalEvent {
    let reply = unsafe { str::from_utf8_unchecked(message) }.to_string();
    let command = reply.lines().next().unwrap_or_default().to_string() + "\r\n";

    let mut args = command.split_ascii_whitespace();
    match args.next().unwrap_or("") {
        "MSG" => {
            let payload = reply.replace(command.as_str(), "");
            let Some(content_type) = payload.lines().nth(1) else {
                return InternalEvent::ServerReply(reply);
            };

            if content_type == "Content-Type: application/x-msnmsgrp2p" {
                let Some(destination) = payload.lines().find(|line| line.contains("P2P-Dest: "))
                else {
                    return InternalEvent::ServerReply(reply);
                };

                let destination = destination.replace("P2P-Dest: ", "");
                let msg_headers = payload.split("\r\n\r\n").next().unwrap_or_default();

                let binary_payload = message
                    .get((command.len() + msg_headers.len() + "\r\n\r\n".len())..)
                    .unwrap_or_default()
                    .to_vec();

                if binary_payload.len() < 52 {
                    return InternalEvent::ServerReply(reply);
                }

                let binary_header = &binary_payload[..48];
                let mut cursor = Cursor::new(binary_header);
                let Ok((_, binary_header)) = BinaryHeader::from_reader((&mut cursor, 0)) else {
                    return InternalEvent::ServerReply(reply);
                };

                if binary_header.total_data_size == 4 && binary_payload[48..52].eq(&[0; 4])
                    || payload.contains("200 OK")
                {
                    return InternalEvent::P2PShouldAck {
                        destination,
                        message: binary_payload,
                    };
                }

                if binary_header.flag == 0x20 || binary_header.flag == 0x1000020 {
                    return InternalEvent::P2PData {
                        destination,
                        message: binary_payload[..(binary_payload.len() - 4)].to_vec(),
                    };
                }

                if payload.contains("INVITE") {
                    return InternalEvent::P2PInvite {
                        destination,
                        message: binary_payload,
                    };
                }

                if payload.contains("BYE") {
                    return InternalEvent::P2PBye {
                        destination,
                        message: binary_payload,
                    };
                }
            }

            InternalEvent::ServerReply(reply)
        }

        _ => InternalEvent::ServerReply(reply),
    }
}
