// Copyright (C) 2023-2025  Lightpanda (Selecy SAS)
//
// Francis Bouvier <francis@lightpanda.io>
// Pierre Tachoire <pierre@lightpanda.io>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.

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

const IS_DEBUG = @import("builtin").mode == .Debug;

pub const Error = error{
    UnsupportedProtocol,
    FailedInit,
    UrlMalformat,
    NotBuiltIn,
    CouldntResolveProxy,
    CouldntResolveHost,
    CouldntConnect,
    WeirdServerReply,
    RemoteAccessDenied,
    FtpAcceptFailed,
    FtpWeirdPassReply,
    FtpAcceptTimeout,
    FtpWeirdPasvReply,
    FtpWeird227Format,
    FtpCantGetHost,
    Http2,
    FtpCouldntSetType,
    PartialFile,
    FtpCouldntRetrFile,
    QuoteError,
    HttpReturnedError,
    WriteError,
    UploadFailed,
    ReadError,
    OutOfMemory,
    OperationTimedout,
    FtpPortFailed,
    FtpCouldntUseRest,
    RangeError,
    SslConnectError,
    BadDownloadResume,
    FileCouldntReadFile,
    LdapCannotBind,
    LdapSearchFailed,
    AbortedByCallback,
    BadFunctionArgument,
    InterfaceFailed,
    TooManyRedirects,
    UnknownOption,
    SetoptOptionSyntax,
    GotNothing,
    SslEngineNotfound,
    SslEngineSetfailed,
    SendError,
    RecvError,
    SslCertproblem,
    SslCipher,
    PeerFailedVerification,
    BadContentEncoding,
    FilesizeExceeded,
    UseSslFailed,
    SendFailRewind,
    SslEngineInitfailed,
    LoginDenied,
    TftpNotfound,
    TftpPerm,
    RemoteDiskFull,
    TftpIllegal,
    TftpUnknownid,
    RemoteFileExists,
    TftpNosuchuser,
    SslCacertBadfile,
    RemoteFileNotFound,
    Ssh,
    SslShutdownFailed,
    Again,
    SslCrlBadfile,
    SslIssuerError,
    FtpPretFailed,
    RtspCseqError,
    RtspSessionError,
    FtpBadFileList,
    ChunkFailed,
    NoConnectionAvailable,
    SslPinnedpubkeynotmatch,
    SslInvalidcertstatus,
    Http2Stream,
    RecursiveApiCall,
    AuthError,
    Http3,
    QuicConnectError,
    Proxy,
    SslClientcert,
    UnrecoverablePoll,
    TooLarge,
    Unknown,
};

pub fn fromCode(code: c.CURLcode) Error {
    if (comptime IS_DEBUG) {
        std.debug.assert(code != c.CURLE_OK);
    }

    return switch (code) {
        c.CURLE_UNSUPPORTED_PROTOCOL => Error.UnsupportedProtocol,
        c.CURLE_FAILED_INIT => Error.FailedInit,
        c.CURLE_URL_MALFORMAT => Error.UrlMalformat,
        c.CURLE_NOT_BUILT_IN => Error.NotBuiltIn,
        c.CURLE_COULDNT_RESOLVE_PROXY => Error.CouldntResolveProxy,
        c.CURLE_COULDNT_RESOLVE_HOST => Error.CouldntResolveHost,
        c.CURLE_COULDNT_CONNECT => Error.CouldntConnect,
        c.CURLE_WEIRD_SERVER_REPLY => Error.WeirdServerReply,
        c.CURLE_REMOTE_ACCESS_DENIED => Error.RemoteAccessDenied,
        c.CURLE_FTP_ACCEPT_FAILED => Error.FtpAcceptFailed,
        c.CURLE_FTP_WEIRD_PASS_REPLY => Error.FtpWeirdPassReply,
        c.CURLE_FTP_ACCEPT_TIMEOUT => Error.FtpAcceptTimeout,
        c.CURLE_FTP_WEIRD_PASV_REPLY => Error.FtpWeirdPasvReply,
        c.CURLE_FTP_WEIRD_227_FORMAT => Error.FtpWeird227Format,
        c.CURLE_FTP_CANT_GET_HOST => Error.FtpCantGetHost,
        c.CURLE_HTTP2 => Error.Http2,
        c.CURLE_FTP_COULDNT_SET_TYPE => Error.FtpCouldntSetType,
        c.CURLE_PARTIAL_FILE => Error.PartialFile,
        c.CURLE_FTP_COULDNT_RETR_FILE => Error.FtpCouldntRetrFile,
        c.CURLE_QUOTE_ERROR => Error.QuoteError,
        c.CURLE_HTTP_RETURNED_ERROR => Error.HttpReturnedError,
        c.CURLE_WRITE_ERROR => Error.WriteError,
        c.CURLE_UPLOAD_FAILED => Error.UploadFailed,
        c.CURLE_READ_ERROR => Error.ReadError,
        c.CURLE_OUT_OF_MEMORY => Error.OutOfMemory,
        c.CURLE_OPERATION_TIMEDOUT => Error.OperationTimedout,
        c.CURLE_FTP_PORT_FAILED => Error.FtpPortFailed,
        c.CURLE_FTP_COULDNT_USE_REST => Error.FtpCouldntUseRest,
        c.CURLE_RANGE_ERROR => Error.RangeError,
        c.CURLE_SSL_CONNECT_ERROR => Error.SslConnectError,
        c.CURLE_BAD_DOWNLOAD_RESUME => Error.BadDownloadResume,
        c.CURLE_FILE_COULDNT_READ_FILE => Error.FileCouldntReadFile,
        c.CURLE_LDAP_CANNOT_BIND => Error.LdapCannotBind,
        c.CURLE_LDAP_SEARCH_FAILED => Error.LdapSearchFailed,
        c.CURLE_ABORTED_BY_CALLBACK => Error.AbortedByCallback,
        c.CURLE_BAD_FUNCTION_ARGUMENT => Error.BadFunctionArgument,
        c.CURLE_INTERFACE_FAILED => Error.InterfaceFailed,
        c.CURLE_TOO_MANY_REDIRECTS => Error.TooManyRedirects,
        c.CURLE_UNKNOWN_OPTION => Error.UnknownOption,
        c.CURLE_SETOPT_OPTION_SYNTAX => Error.SetoptOptionSyntax,
        c.CURLE_GOT_NOTHING => Error.GotNothing,
        c.CURLE_SSL_ENGINE_NOTFOUND => Error.SslEngineNotfound,
        c.CURLE_SSL_ENGINE_SETFAILED => Error.SslEngineSetfailed,
        c.CURLE_SEND_ERROR => Error.SendError,
        c.CURLE_RECV_ERROR => Error.RecvError,
        c.CURLE_SSL_CERTPROBLEM => Error.SslCertproblem,
        c.CURLE_SSL_CIPHER => Error.SslCipher,
        c.CURLE_PEER_FAILED_VERIFICATION => Error.PeerFailedVerification,
        c.CURLE_BAD_CONTENT_ENCODING => Error.BadContentEncoding,
        c.CURLE_FILESIZE_EXCEEDED => Error.FilesizeExceeded,
        c.CURLE_USE_SSL_FAILED => Error.UseSslFailed,
        c.CURLE_SEND_FAIL_REWIND => Error.SendFailRewind,
        c.CURLE_SSL_ENGINE_INITFAILED => Error.SslEngineInitfailed,
        c.CURLE_LOGIN_DENIED => Error.LoginDenied,
        c.CURLE_TFTP_NOTFOUND => Error.TftpNotfound,
        c.CURLE_TFTP_PERM => Error.TftpPerm,
        c.CURLE_REMOTE_DISK_FULL => Error.RemoteDiskFull,
        c.CURLE_TFTP_ILLEGAL => Error.TftpIllegal,
        c.CURLE_TFTP_UNKNOWNID => Error.TftpUnknownid,
        c.CURLE_REMOTE_FILE_EXISTS => Error.RemoteFileExists,
        c.CURLE_TFTP_NOSUCHUSER => Error.TftpNosuchuser,
        c.CURLE_SSL_CACERT_BADFILE => Error.SslCacertBadfile,
        c.CURLE_REMOTE_FILE_NOT_FOUND => Error.RemoteFileNotFound,
        c.CURLE_SSH => Error.Ssh,
        c.CURLE_SSL_SHUTDOWN_FAILED => Error.SslShutdownFailed,
        c.CURLE_AGAIN => Error.Again,
        c.CURLE_SSL_CRL_BADFILE => Error.SslCrlBadfile,
        c.CURLE_SSL_ISSUER_ERROR => Error.SslIssuerError,
        c.CURLE_FTP_PRET_FAILED => Error.FtpPretFailed,
        c.CURLE_RTSP_CSEQ_ERROR => Error.RtspCseqError,
        c.CURLE_RTSP_SESSION_ERROR => Error.RtspSessionError,
        c.CURLE_FTP_BAD_FILE_LIST => Error.FtpBadFileList,
        c.CURLE_CHUNK_FAILED => Error.ChunkFailed,
        c.CURLE_NO_CONNECTION_AVAILABLE => Error.NoConnectionAvailable,
        c.CURLE_SSL_PINNEDPUBKEYNOTMATCH => Error.SslPinnedpubkeynotmatch,
        c.CURLE_SSL_INVALIDCERTSTATUS => Error.SslInvalidcertstatus,
        c.CURLE_HTTP2_STREAM => Error.Http2Stream,
        c.CURLE_RECURSIVE_API_CALL => Error.RecursiveApiCall,
        c.CURLE_AUTH_ERROR => Error.AuthError,
        c.CURLE_HTTP3 => Error.Http3,
        c.CURLE_QUIC_CONNECT_ERROR => Error.QuicConnectError,
        c.CURLE_PROXY => Error.Proxy,
        c.CURLE_SSL_CLIENTCERT => Error.SslClientcert,
        c.CURLE_UNRECOVERABLE_POLL => Error.UnrecoverablePoll,
        c.CURLE_TOO_LARGE => Error.TooLarge,
        else => Error.Unknown,
    };
}

pub const Multi = error{
    BadHandle,
    BadEasyHandle,
    OutOfMemory,
    InternalError,
    BadSocket,
    UnknownOption,
    AddedAlready,
    RecursiveApiCall,
    WakeupFailure,
    BadFunctionArgument,
    AbortedByCallback,
    UnrecoverablePoll,
    Unknown,
};

pub fn fromMCode(code: c.CURLMcode) Multi {
    if (comptime IS_DEBUG) {
        std.debug.assert(code != c.CURLM_OK);
    }

    return switch (code) {
        c.CURLM_BAD_HANDLE => Multi.BadHandle,
        c.CURLM_BAD_EASY_HANDLE => Multi.BadEasyHandle,
        c.CURLM_OUT_OF_MEMORY => Multi.OutOfMemory,
        c.CURLM_INTERNAL_ERROR => Multi.InternalError,
        c.CURLM_BAD_SOCKET => Multi.BadSocket,
        c.CURLM_UNKNOWN_OPTION => Multi.UnknownOption,
        c.CURLM_ADDED_ALREADY => Multi.AddedAlready,
        c.CURLM_RECURSIVE_API_CALL => Multi.RecursiveApiCall,
        c.CURLM_WAKEUP_FAILURE => Multi.WakeupFailure,
        c.CURLM_BAD_FUNCTION_ARGUMENT => Multi.BadFunctionArgument,
        c.CURLM_ABORTED_BY_CALLBACK => Multi.AbortedByCallback,
        c.CURLM_UNRECOVERABLE_POLL => Multi.UnrecoverablePoll,
        else => Multi.Unknown,
    };
}
