    pub const Client = @import("http/Client.zig");
    pub const Server = @import("http/Server.zig");
    pub const protocol = @import("http/protocol.zig");
    const headers = @import("http/Headers.zig");

    pub const Headers = headers.Headers;
    pub const Field = headers.Field;

    pub const Version = enum {
        @"HTTP/1.0",
        @"HTTP/1.1",
    };

    /// https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods
    /// https://datatracker.ietf.org/doc/html/rfc7231#section-4 Initial definition
    /// https://datatracker.ietf.org/doc/html/rfc5789#section-2 PATCH
    pub const Method = enum {
        GET,
        HEAD,
        POST,
        PUT,
        DELETE,
        CONNECT,
        OPTIONS,
        TRACE,
        PATCH,

        /// Returns true if a request of this method is allowed to have a body
        /// Actual behavior from servers may vary and should still be checked
        pub fn requestHasBody(self: Method) bool {
            return switch (self) {
                .POST, .PUT, .PATCH => true,
                .GET, .HEAD, .DELETE, .CONNECT, .OPTIONS, .TRACE => false,
            };
        }

        /// Returns true if a response to this method is allowed to have a body
        /// Actual behavior from clients may vary and should still be checked
        pub fn responseHasBody(self: Method) bool {
            return switch (self) {
                .GET, .POST, .DELETE, .CONNECT, .OPTIONS, .PATCH => true,
                .HEAD, .PUT, .TRACE => false,
            };
        }

        /// An HTTP method is safe if it doesn't alter the state of the server.
        /// https://developer.mozilla.org/en-US/docs/Glossary/Safe/HTTP
        /// https://datatracker.ietf.org/doc/html/rfc7231#section-4.2.1
        pub fn safe(self: Method) bool {
            return switch (self) {
                .GET, .HEAD, .OPTIONS, .TRACE => true,
                .POST, .PUT, .DELETE, .CONNECT, .PATCH => false,
            };
        }

        /// An HTTP method is idempotent if an identical request can be made once or several times in a row with the same effect while leaving the server in the same state.
        /// https://developer.mozilla.org/en-US/docs/Glossary/Idempotent
        /// https://datatracker.ietf.org/doc/html/rfc7231#section-4.2.2
        pub fn idempotent(self: Method) bool {
            return switch (self) {
                .GET, .HEAD, .PUT, .DELETE, .OPTIONS, .TRACE => true,
                .CONNECT, .POST, .PATCH => false,
            };
        }

        /// A cacheable response is an HTTP response that can be cached, that is stored to be retrieved and used later, saving a new request to the server.
        /// https://developer.mozilla.org/en-US/docs/Glossary/cacheable
        /// https://datatracker.ietf.org/doc/html/rfc7231#section-4.2.3
        pub fn cacheable(self: Method) bool {
            return switch (self) {
                .GET, .HEAD => true,
                .POST, .PUT, .DELETE, .CONNECT, .OPTIONS, .TRACE, .PATCH => false,
            };
        }
    };

    /// https://developer.mozilla.org/en-US/docs/Web/HTTP/Status
    pub const Status = enum(u10) {
        @"continue" = 100, // RFC7231, Section 6.2.1

        switching_protocols = 101, // RFC7231, Section 6.2.2

        processing = 102, // RFC2518

        early_hints = 103, // RFC8297

        ok = 200, // RFC7231, Section 6.3.1

        created = 201, // RFC7231, Section 6.3.2

        accepted = 202, // RFC7231, Section 6.3.3

        non_authoritative_info = 203, // RFC7231, Section 6.3.4

        no_content = 204, // RFC7231, Section 6.3.5

        reset_content = 205, // RFC7231, Section 6.3.6

        partial_content = 206, // RFC7233, Section 4.1

        multi_status = 207, // RFC4918

        already_reported = 208, // RFC5842

        im_used = 226, // RFC3229

        multiple_choice = 300, // RFC7231, Section 6.4.1

        moved_permanently = 301, // RFC7231, Section 6.4.2

        found = 302, // RFC7231, Section 6.4.3

        see_other = 303, // RFC7231, Section 6.4.4

        not_modified = 304, // RFC7232, Section 4.1

        use_proxy = 305, // RFC7231, Section 6.4.5

        temporary_redirect = 307, // RFC7231, Section 6.4.7

        permanent_redirect = 308, // RFC7538

        bad_request = 400, // RFC7231, Section 6.5.1

        unauthorized = 401, // RFC7235, Section 3.1

        payment_required = 402, // RFC7231, Section 6.5.2

        forbidden = 403, // RFC7231, Section 6.5.3

        not_found = 404, // RFC7231, Section 6.5.4

        method_not_allowed = 405, // RFC7231, Section 6.5.5

        not_acceptable = 406, // RFC7231, Section 6.5.6

        proxy_auth_required = 407, // RFC7235, Section 3.2

        request_timeout = 408, // RFC7231, Section 6.5.7

        conflict = 409, // RFC7231, Section 6.5.8

        gone = 410, // RFC7231, Section 6.5.9

        length_required = 411, // RFC7231, Section 6.5.10

        precondition_failed = 412, // RFC7232, Section 4.2][RFC8144, Section 3.2

        payload_too_large = 413, // RFC7231, Section 6.5.11

        uri_too_long = 414, // RFC7231, Section 6.5.12

        unsupported_media_type = 415, // RFC7231, Section 6.5.13][RFC7694, Section 3

        range_not_satisfiable = 416, // RFC7233, Section 4.4

        expectation_failed = 417, // RFC7231, Section 6.5.14

        teapot = 418, // RFC 7168, 2.3.3

        misdirected_request = 421, // RFC7540, Section 9.1.2

        unprocessable_entity = 422, // RFC4918

        locked = 423, // RFC4918

        failed_dependency = 424, // RFC4918

        too_early = 425, // RFC8470

        upgrade_required = 426, // RFC7231, Section 6.5.15

        precondition_required = 428, // RFC6585

        too_many_requests = 429, // RFC6585

        request_header_fields_too_large = 431, // RFC6585

        unavailable_for_legal_reasons = 451, // RFC7725

        internal_server_error = 500, // RFC7231, Section 6.6.1

        not_implemented = 501, // RFC7231, Section 6.6.2

        bad_gateway = 502, // RFC7231, Section 6.6.3

        service_unavailable = 503, // RFC7231, Section 6.6.4

        gateway_timeout = 504, // RFC7231, Section 6.6.5

        http_version_not_supported = 505, // RFC7231, Section 6.6.6

        variant_also_negotiates = 506, // RFC2295

        insufficient_storage = 507, // RFC4918

        loop_detected = 508, // RFC5842

        not_extended = 510, // RFC2774

        network_authentication_required = 511, // RFC6585

        _,

        pub fn phrase(self: Status) ?[]const u8 {
            return switch (self) {
                // 1xx statuses

                .@"continue" => "Continue",
                .switching_protocols => "Switching Protocols",
                .processing => "Processing",
                .early_hints => "Early Hints",

                // 2xx statuses

                .ok => "OK",
                .created => "Created",
                .accepted => "Accepted",
                .non_authoritative_info => "Non-Authoritative Information",
                .no_content => "No Content",
                .reset_content => "Reset Content",
                .partial_content => "Partial Content",
                .multi_status => "Multi-Status",
                .already_reported => "Already Reported",
                .im_used => "IM Used",

                // 3xx statuses

                .multiple_choice => "Multiple Choice",
                .moved_permanently => "Moved Permanently",
                .found => "Found",
                .see_other => "See Other",
                .not_modified => "Not Modified",
                .use_proxy => "Use Proxy",
                .temporary_redirect => "Temporary Redirect",
                .permanent_redirect => "Permanent Redirect",

                // 4xx statuses

                .bad_request => "Bad Request",
                .unauthorized => "Unauthorized",
                .payment_required => "Payment Required",
                .forbidden => "Forbidden",
                .not_found => "Not Found",
                .method_not_allowed => "Method Not Allowed",
                .not_acceptable => "Not Acceptable",
                .proxy_auth_required => "Proxy Authentication Required",
                .request_timeout => "Request Timeout",
                .conflict => "Conflict",
                .gone => "Gone",
                .length_required => "Length Required",
                .precondition_failed => "Precondition Failed",
                .payload_too_large => "Payload Too Large",
                .uri_too_long => "URI Too Long",
                .unsupported_media_type => "Unsupported Media Type",
                .range_not_satisfiable => "Range Not Satisfiable",
                .expectation_failed => "Expectation Failed",
                .teapot => "I'm a teapot",
                .misdirected_request => "Misdirected Request",
                .unprocessable_entity => "Unprocessable Entity",
                .locked => "Locked",
                .failed_dependency => "Failed Dependency",
                .too_early => "Too Early",
                .upgrade_required => "Upgrade Required",
                .precondition_required => "Precondition Required",
                .too_many_requests => "Too Many Requests",
                .request_header_fields_too_large => "Request Header Fields Too Large",
                .unavailable_for_legal_reasons => "Unavailable For Legal Reasons",

                // 5xx statuses

                .internal_server_error => "Internal Server Error",
                .not_implemented => "Not Implemented",
                .bad_gateway => "Bad Gateway",
                .service_unavailable => "Service Unavailable",
                .gateway_timeout => "Gateway Timeout",
                .http_version_not_supported => "HTTP Version Not Supported",
                .variant_also_negotiates => "Variant Also Negotiates",
                .insufficient_storage => "Insufficient Storage",
                .loop_detected => "Loop Detected",
                .not_extended => "Not Extended",
                .network_authentication_required => "Network Authentication Required",

                else => return null,
            };
        }

        pub const Class = enum {
            informational,
            success,
            redirect,
            client_error,
            server_error,
        };

        pub fn class(self: Status) Class {
            return switch (@intFromEnum(self)) {
                100...199 => .informational,
                200...299 => .success,
                300...399 => .redirect,
                400...499 => .client_error,
                else => .server_error,
            };
        }

        test {
            try std.testing.expectEqualStrings("OK", Status.ok.phrase().?);
            try std.testing.expectEqualStrings("Not Found", Status.not_found.phrase().?);
        }

        test {
            try std.testing.expectEqual(@as(?Status.Class, Status.Class.success), Status.ok.class());
            try std.testing.expectEqual(@as(?Status.Class, Status.Class.client_error), Status.not_found.class());
        }
    };

    pub const TransferEncoding = enum {
        chunked,
        // compression is intentionally omitted here, as std.http.Client stores it as content-encoding

    };

    pub const ContentEncoding = enum {
        compress,
        deflate,
        gzip,
        zstd,
    };

    pub const Connection = enum {
        keep_alive,
        close,
    };

    const std = @import("std.zig");

    test {
        _ = Client;
        _ = Method;
        _ = Server;
        _ = Status;
    }