use std::fmt::Display;

use crate::utils::mime::mime_enum::Mime;

use super::routes::Body;

type HeaderMap = Vec<String>;

#[derive(Debug)]
pub enum Outcome<S, E, F> {
    Success(S),
    Failure(E),
    Forward(F),
}

pub trait ResponseBody: Send {
    fn get_data(&self) -> Vec<u8>;
    fn get_mime(&self) -> Mime;
    fn get_len(&self) -> usize;
}

impl ResponseBody for Body {
    fn get_data(&self) -> Vec<u8> {
        self.body()
    }
    fn get_mime(&self) -> Mime {
        self.mime_type()
    }

    fn get_len(&self) -> usize {
        self.get_data().len()
    }
}

impl ResponseBody for &str {
    fn get_data(&self) -> Vec<u8> {
        self.as_bytes().to_vec()
    }

    fn get_mime(&self) -> Mime {
        Mime::TextPlain
    }

    fn get_len(&self) -> usize {
        self.len()
    }
}

impl ResponseBody for String {
    fn get_data(&self) -> Vec<u8> {
        self.as_bytes().to_vec()
    }

    fn get_mime(&self) -> Mime {
        Mime::TextPlain
    }

    fn get_len(&self) -> usize {
        self.len()
    }
}

pub struct Response {
    pub headers: HeaderMap,
    pub status: Option<Status>,
    pub body: Box<dyn ResponseBody>,
}

#[derive(Debug)]
pub enum Status {
    Continue,
    SwitchingProtocols,
    WebDavProcessing,
    ExperimentalEarlyHints,
    Ok,
    Created,
    Accepted,
    NonAuthorativeIfnormation,
    NoContent,
    ResetContent,
    PartialContent,
    WebDavMultiStatus,
    WebDavAlreadyReported,
    HttpDataEncodingImUsed,
    MultipleChoices,
    MovedPermanently,
    Found,
    SeeOther,
    NotModfiied,
    DeprecatedUseProxy,
    UnusedUnused,
    TemporaryRedirect,
    PermanentRedirect,
    BadRequest,
    Unauthorized,
    ExperimentalPaymentRequired,
    Forbidden,
    NotFound,
    MethodNotAllowed,
    NotAcceptable,
    ProxyAuthenticationRequired,
    RequestTimeout,
    Conflict,
    Gone,
    LengthRequired,
    PreconditionFailed,
    PayloadTooLarge,
    UriTooLong,
    UnsupportedMediaType,
    RangeNotSatisfiable,
    ExpectationFailed,
    ImATeapot,
    MisdirectedRequest,
    WebDavUnprocessableContent,
    WebDavLocked,
    WebDavFailedDependency,
    ExperimenalTooEarly,
    UpgradeRequred,
    PreconditionRequired,
    TooManyRequests,
    RequestHeaderFieldsTooLarge,
    UnavailableForLegalReasons,
    InternalServerError,
    NotImplemented,
    BadGetaway,
    ServiceUnavailable,
    GetawayTimeout,
    HttpVersionNotSupported,
    VariantAlsoNegotiates,
    WebDavInsufficientStorage,
    WebDavLoopDetected,
    NotExtended,
    NetworkAuthenticationRequired,
}

impl Display for Status {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Status::Continue => write!(f, "100 Continue"),
            Status::SwitchingProtocols => write!(f, "101 Switching Protocols"),
            Status::WebDavProcessing => write!(f, "102 Processing"),
            Status::ExperimentalEarlyHints => write!(f, "103 Early Hints"),
            Status::Ok => write!(f, "200 OK"),
            Status::Created => write!(f, "201 Created"),
            Status::Accepted => write!(f, "202 Accepted"),
            Status::NonAuthorativeIfnormation => write!(f, "203 Non-Authorative Information"),
            Status::NoContent => write!(f, "204 No Content"),
            Status::ResetContent => write!(f, "205 Reset Content"),
            Status::PartialContent => write!(f, "206 Partial Content"),
            Status::WebDavMultiStatus => write!(f, "207 Mutli-Status"),
            Status::WebDavAlreadyReported => write!(f, "208 Already Reported"),
            Status::HttpDataEncodingImUsed => write!(f, "226 IM Used"),
            Status::MultipleChoices => write!(f, "300 Multiple Choices"),
            Status::MovedPermanently => write!(f, "301 Moved Permanently"),
            Status::Found => write!(f, "302 Found"),
            Status::SeeOther => write!(f, "303 See Other"),
            Status::NotModfiied => write!(f, "304 Not Modified"),
            Status::TemporaryRedirect => write!(f, "307 Temporary Redirect"),
            Status::PermanentRedirect => write!(f, "308 Permanent Redirect"),
            Status::DeprecatedUseProxy => write!(f, "305 Use Proxy"),
            Status::UnusedUnused => write!(f, "306 unused"),
            Status::BadRequest => write!(f, "400 Bad Request"),
            Status::Unauthorized => write!(f, "401 Unauthorized"),
            Status::ExperimentalPaymentRequired => write!(f, "402 Payment Required"),
            Status::Forbidden => write!(f, "403 Forbidden"),
            Status::NotFound => write!(f, "404 Not Found"),
            Status::MethodNotAllowed => write!(f, "405 Method Not Allowed"),
            Status::NotAcceptable => write!(f, "406 Not Acceptable"),
            Status::ProxyAuthenticationRequired => {
                write!(f, "407 Proxy Athentication Required")
            }
            Status::RequestTimeout => write!(f, "408 Request Timout"),
            Status::Conflict => write!(f, "409 Conflict"),
            Status::Gone => write!(f, "410 Gone"),
            Status::LengthRequired => write!(f, "411 Length Required"),
            Status::PreconditionFailed => write!(f, "412 Precondition Failed"),
            Status::PayloadTooLarge => write!(f, "413 Payload Too Large"),
            Status::UriTooLong => write!(f, "414 URI Too Long"),
            Status::UnsupportedMediaType => write!(f, "415 Unsupported Media Type"),
            Status::RangeNotSatisfiable => write!(f, "416 Range Not Satisfiable"),
            Status::ExpectationFailed => write!(f, "417 Expectation Failed"),
            Status::ImATeapot => write!(f, "418 I'm a Teapot"),
            Status::MisdirectedRequest => write!(f, "421 Misdirected Request"),
            Status::WebDavUnprocessableContent => write!(f, "422 Unprocessable Content"),
            Status::WebDavLocked => write!(f, "423 Locked"),
            Status::WebDavFailedDependency => write!(f, "424 Failed Dependency"),
            Status::ExperimenalTooEarly => write!(f, "425 Too Early"),
            Status::UpgradeRequred => write!(f, "426 Upgrade Required"),
            Status::PreconditionRequired => write!(f, "428 Precondition Required"),
            Status::TooManyRequests => write!(f, "429 Too Many Requests"),
            Status::RequestHeaderFieldsTooLarge => {
                write!(f, "431 Request Header Fields Too Large")
            }
            Status::UnavailableForLegalReasons => {
                write!(f, "451 Unavailable For Legal Reasons")
            }
            Status::InternalServerError => write!(f, "500 Internal Server Error"),
            Status::NotImplemented => write!(f, "501 Not Implmenented"),
            Status::BadGetaway => write!(f, "502 Bad Getaway"),
            Status::ServiceUnavailable => write!(f, "503 Service Unavailable"),
            Status::GetawayTimeout => write!(f, "504 Getaway Timeout"),
            Status::HttpVersionNotSupported => write!(f, "505 HTTP Version Not Supported"),
            Status::VariantAlsoNegotiates => write!(f, "506 Variant Also Negotiates"),
            Status::WebDavInsufficientStorage => write!(f, "507 Insufficient Storage"),
            Status::WebDavLoopDetected => write!(f, "508 Loop Detected"),
            Status::NotExtended => write!(f, "510 Not Extendend"),
            Status::NetworkAuthenticationRequired => {
                write!(f, "511 Network Authentication Required")
            }
        }
    }
}