{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE StrictData #-}

-- |
-- Module: Captcha.CapMonster.Internal.Error
-- Copyright: (c) 2022 Edward Yang
-- License: MIT
--
-- This module is for internal-use and does not follow pvp versioning policies.
module Captcha.CapMonster.Internal.Error where

import Control.Exception (Exception)
import Data.Foldable (find)
import Data.Text (Text)
import Network.HTTP.Client (HttpException)

-- | All possible errors when solving a captcha using CapMonster.
data CapMonsterError
  = -- | An error returned by the CapMonster API.
    CapMonsterResponseError CapMonsterErrorCode
  | -- |
    -- An error returned by the CapMonster API that
    -- does not exist as a 'CapMonsterErrorCode' yet.
    --
    -- This error holds the error code, followed by its description.
    UnknownResponseError Text Text
  | -- |
    -- An unknown error occurred. Check the message for more details.
    --
    -- This should never occur. Please report this issue on github if this happens to you.
    UnknownError Text
  | -- | An error when sending the http request.
    NetworkError HttpException
  | -- | The captcha took to long to solve and was timed out.
    TimeoutError
  deriving (Int -> CapMonsterError -> ShowS
[CapMonsterError] -> ShowS
CapMonsterError -> String
(Int -> CapMonsterError -> ShowS)
-> (CapMonsterError -> String)
-> ([CapMonsterError] -> ShowS)
-> Show CapMonsterError
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [CapMonsterError] -> ShowS
$cshowList :: [CapMonsterError] -> ShowS
show :: CapMonsterError -> String
$cshow :: CapMonsterError -> String
showsPrec :: Int -> CapMonsterError -> ShowS
$cshowsPrec :: Int -> CapMonsterError -> ShowS
Show, Show CapMonsterError
Typeable CapMonsterError
Typeable CapMonsterError
-> Show CapMonsterError
-> (CapMonsterError -> SomeException)
-> (SomeException -> Maybe CapMonsterError)
-> (CapMonsterError -> String)
-> Exception CapMonsterError
SomeException -> Maybe CapMonsterError
CapMonsterError -> String
CapMonsterError -> SomeException
forall e.
Typeable e
-> Show e
-> (e -> SomeException)
-> (SomeException -> Maybe e)
-> (e -> String)
-> Exception e
displayException :: CapMonsterError -> String
$cdisplayException :: CapMonsterError -> String
fromException :: SomeException -> Maybe CapMonsterError
$cfromException :: SomeException -> Maybe CapMonsterError
toException :: CapMonsterError -> SomeException
$ctoException :: CapMonsterError -> SomeException
$cp2Exception :: Show CapMonsterError
$cp1Exception :: Typeable CapMonsterError
Exception)

-- | An error code returned by the CapMonster API.
data CapMonsterErrorCode
  = -- | The provided API key does not exist.
    KeyDoesNotExist
  | -- | The size of the captcha must be 100 bytes or larger.
    ZeroCaptchaFileSize
  | -- | The size of the captcha must be less than 50,000 bytes.
    TooBigFileSize
  | -- | Your CapMonster balance is empty.
    ZeroBalance
  | -- | Requests from your current API key is not allowed from your ip.
    IpNotAllowed
  | -- | The captcha cannot be solved. Perhaps it's a corrupted image, or contains too much noise?
    CaptchaUnsolvable
  | -- | The captcha id does not exist. Is the captcha older than 5 minutes?
    InvalidCaptchaId
  | -- | The captcha has not been solved yet.
    CaptchaNotReady
  | -- | You have sent too many requests with an incorrect API key. Try again later.
    IpBanned
  | -- |
    -- The requested method does not exist. You should not ever have to see this error as a user.
    -- If this is ever seen, please open an issue: https://github.com/qwbarch/captcha-haskell/issues
    NoSuchMethod
  | -- | You are being rate limited. Try not to request the result of a captcha more than 1 time per 2 seconds.
    TooManyRequests
  | -- | The specified domain cannot be solved by CapMonster.
    DomainNotAllowed
  | -- | The captcha could not be solved due to no available captcha workers.
    NoSlotAvailable
  deriving (Int -> CapMonsterErrorCode -> ShowS
[CapMonsterErrorCode] -> ShowS
CapMonsterErrorCode -> String
(Int -> CapMonsterErrorCode -> ShowS)
-> (CapMonsterErrorCode -> String)
-> ([CapMonsterErrorCode] -> ShowS)
-> Show CapMonsterErrorCode
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [CapMonsterErrorCode] -> ShowS
$cshowList :: [CapMonsterErrorCode] -> ShowS
show :: CapMonsterErrorCode -> String
$cshow :: CapMonsterErrorCode -> String
showsPrec :: Int -> CapMonsterErrorCode -> ShowS
$cshowsPrec :: Int -> CapMonsterErrorCode -> ShowS
Show, CapMonsterErrorCode -> CapMonsterErrorCode -> Bool
(CapMonsterErrorCode -> CapMonsterErrorCode -> Bool)
-> (CapMonsterErrorCode -> CapMonsterErrorCode -> Bool)
-> Eq CapMonsterErrorCode
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: CapMonsterErrorCode -> CapMonsterErrorCode -> Bool
$c/= :: CapMonsterErrorCode -> CapMonsterErrorCode -> Bool
== :: CapMonsterErrorCode -> CapMonsterErrorCode -> Bool
$c== :: CapMonsterErrorCode -> CapMonsterErrorCode -> Bool
Eq, Eq CapMonsterErrorCode
Eq CapMonsterErrorCode
-> (CapMonsterErrorCode -> CapMonsterErrorCode -> Ordering)
-> (CapMonsterErrorCode -> CapMonsterErrorCode -> Bool)
-> (CapMonsterErrorCode -> CapMonsterErrorCode -> Bool)
-> (CapMonsterErrorCode -> CapMonsterErrorCode -> Bool)
-> (CapMonsterErrorCode -> CapMonsterErrorCode -> Bool)
-> (CapMonsterErrorCode
    -> CapMonsterErrorCode -> CapMonsterErrorCode)
-> (CapMonsterErrorCode
    -> CapMonsterErrorCode -> CapMonsterErrorCode)
-> Ord CapMonsterErrorCode
CapMonsterErrorCode -> CapMonsterErrorCode -> Bool
CapMonsterErrorCode -> CapMonsterErrorCode -> Ordering
CapMonsterErrorCode -> CapMonsterErrorCode -> CapMonsterErrorCode
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: CapMonsterErrorCode -> CapMonsterErrorCode -> CapMonsterErrorCode
$cmin :: CapMonsterErrorCode -> CapMonsterErrorCode -> CapMonsterErrorCode
max :: CapMonsterErrorCode -> CapMonsterErrorCode -> CapMonsterErrorCode
$cmax :: CapMonsterErrorCode -> CapMonsterErrorCode -> CapMonsterErrorCode
>= :: CapMonsterErrorCode -> CapMonsterErrorCode -> Bool
$c>= :: CapMonsterErrorCode -> CapMonsterErrorCode -> Bool
> :: CapMonsterErrorCode -> CapMonsterErrorCode -> Bool
$c> :: CapMonsterErrorCode -> CapMonsterErrorCode -> Bool
<= :: CapMonsterErrorCode -> CapMonsterErrorCode -> Bool
$c<= :: CapMonsterErrorCode -> CapMonsterErrorCode -> Bool
< :: CapMonsterErrorCode -> CapMonsterErrorCode -> Bool
$c< :: CapMonsterErrorCode -> CapMonsterErrorCode -> Bool
compare :: CapMonsterErrorCode -> CapMonsterErrorCode -> Ordering
$ccompare :: CapMonsterErrorCode -> CapMonsterErrorCode -> Ordering
$cp1Ord :: Eq CapMonsterErrorCode
Ord, Int -> CapMonsterErrorCode
CapMonsterErrorCode -> Int
CapMonsterErrorCode -> [CapMonsterErrorCode]
CapMonsterErrorCode -> CapMonsterErrorCode
CapMonsterErrorCode -> CapMonsterErrorCode -> [CapMonsterErrorCode]
CapMonsterErrorCode
-> CapMonsterErrorCode
-> CapMonsterErrorCode
-> [CapMonsterErrorCode]
(CapMonsterErrorCode -> CapMonsterErrorCode)
-> (CapMonsterErrorCode -> CapMonsterErrorCode)
-> (Int -> CapMonsterErrorCode)
-> (CapMonsterErrorCode -> Int)
-> (CapMonsterErrorCode -> [CapMonsterErrorCode])
-> (CapMonsterErrorCode
    -> CapMonsterErrorCode -> [CapMonsterErrorCode])
-> (CapMonsterErrorCode
    -> CapMonsterErrorCode -> [CapMonsterErrorCode])
-> (CapMonsterErrorCode
    -> CapMonsterErrorCode
    -> CapMonsterErrorCode
    -> [CapMonsterErrorCode])
-> Enum CapMonsterErrorCode
forall a.
(a -> a)
-> (a -> a)
-> (Int -> a)
-> (a -> Int)
-> (a -> [a])
-> (a -> a -> [a])
-> (a -> a -> [a])
-> (a -> a -> a -> [a])
-> Enum a
enumFromThenTo :: CapMonsterErrorCode
-> CapMonsterErrorCode
-> CapMonsterErrorCode
-> [CapMonsterErrorCode]
$cenumFromThenTo :: CapMonsterErrorCode
-> CapMonsterErrorCode
-> CapMonsterErrorCode
-> [CapMonsterErrorCode]
enumFromTo :: CapMonsterErrorCode -> CapMonsterErrorCode -> [CapMonsterErrorCode]
$cenumFromTo :: CapMonsterErrorCode -> CapMonsterErrorCode -> [CapMonsterErrorCode]
enumFromThen :: CapMonsterErrorCode -> CapMonsterErrorCode -> [CapMonsterErrorCode]
$cenumFromThen :: CapMonsterErrorCode -> CapMonsterErrorCode -> [CapMonsterErrorCode]
enumFrom :: CapMonsterErrorCode -> [CapMonsterErrorCode]
$cenumFrom :: CapMonsterErrorCode -> [CapMonsterErrorCode]
fromEnum :: CapMonsterErrorCode -> Int
$cfromEnum :: CapMonsterErrorCode -> Int
toEnum :: Int -> CapMonsterErrorCode
$ctoEnum :: Int -> CapMonsterErrorCode
pred :: CapMonsterErrorCode -> CapMonsterErrorCode
$cpred :: CapMonsterErrorCode -> CapMonsterErrorCode
succ :: CapMonsterErrorCode -> CapMonsterErrorCode
$csucc :: CapMonsterErrorCode -> CapMonsterErrorCode
Enum, CapMonsterErrorCode
CapMonsterErrorCode
-> CapMonsterErrorCode -> Bounded CapMonsterErrorCode
forall a. a -> a -> Bounded a
maxBound :: CapMonsterErrorCode
$cmaxBound :: CapMonsterErrorCode
minBound :: CapMonsterErrorCode
$cminBound :: CapMonsterErrorCode
Bounded)

-- | Textual representation of a 'CapMonsterErrorCode'.
errorCode :: CapMonsterErrorCode -> Text
errorCode :: CapMonsterErrorCode -> Text
errorCode = \case
  CapMonsterErrorCode
KeyDoesNotExist -> Text
"ERROR_KEY_DOES_NOT_EXIST"
  CapMonsterErrorCode
ZeroCaptchaFileSize -> Text
"ERROR_ZERO_CAPTCHA_FILESIZE"
  CapMonsterErrorCode
TooBigFileSize -> Text
"ERROR_TOO_BIG_CAPTCHA_FILESIZE"
  CapMonsterErrorCode
ZeroBalance -> Text
"ERROR_ZERO_BALANCE"
  CapMonsterErrorCode
IpNotAllowed -> Text
"ERROR_IP_NOT_ALLOWED"
  CapMonsterErrorCode
CaptchaUnsolvable -> Text
"ERROR_CAPTCHA_UNSOLVABLE"
  CapMonsterErrorCode
InvalidCaptchaId -> Text
"ERROR_NO_SUCH_CAPCHA_ID"
  CapMonsterErrorCode
CaptchaNotReady -> Text
"CAPTCHA_NOT_READY"
  CapMonsterErrorCode
IpBanned -> Text
"ERROR_IP_BANNED"
  CapMonsterErrorCode
NoSuchMethod -> Text
"ERROR_NO_SUCH_METHOD"
  CapMonsterErrorCode
TooManyRequests -> Text
"ERROR_TOO_MUCH_REQUESTS"
  CapMonsterErrorCode
DomainNotAllowed -> Text
"ERROR_DOMAIN_NOT_ALLOWED"
  CapMonsterErrorCode
NoSlotAvailable -> Text
"ERROR_NO_SLOT_AVAILABLE"

-- | Parse an error code into its equivalent 'CapMonsterErrorCode'.
parseError :: Text -> Maybe CapMonsterErrorCode
parseError :: Text -> Maybe CapMonsterErrorCode
parseError Text
code = (CapMonsterErrorCode -> Bool)
-> [CapMonsterErrorCode] -> Maybe CapMonsterErrorCode
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Maybe a
find ((Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== Text
code) (Text -> Bool)
-> (CapMonsterErrorCode -> Text) -> CapMonsterErrorCode -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CapMonsterErrorCode -> Text
errorCode) [CapMonsterErrorCode
forall a. Bounded a => a
minBound .. CapMonsterErrorCode
forall a. Bounded a => a
maxBound]