{-# LANGUAGE DeriveGeneric #-}

module OpenSuse.Types.Issue
  ( Issue(..), parseIssue, parseCve, parseBsc, showIssue
  , isCve, isBsc
  )
  where

import OpenSuse.Prelude

import Data.Aeson
import Data.List
import Data.Text ( unpack )
import GHC.Generics ( Generic )
import Text.Read

data Issue = Bsc Natural
           | Cve Natural Natural
  deriving (Show, Eq, Ord, Generic)

instance Hashable Issue
instance Binary Issue
instance NFData Issue

parseIssue :: String -> Issue
parseIssue ('C':'V':'E':'-':cve) = parseCve cve
parseIssue ('b':'s':'c':'#':bsc) = parseBsc bsc
parseIssue bsc                   = parseBsc bsc

showIssue :: Issue -> String
showIssue (Cve y n) = "CVE-" ++ show y ++ "-" ++ show n
showIssue (Bsc n) = "bsc#" ++ show n

parseCve :: String -> Issue
parseCve cve = Cve (safeRead "cve-year" y) (safeRead "cve-number" n)
  where (y,'-':n) = break (=='-') cve

parseBsc :: String -> Issue     -- TODO: https://gitlab.suse.de/l3ms/smelt/issues/184
parseBsc bsc = Bsc (safeRead "bsc number" (stripFixmeSuffix bsc))

instance FromJSON Issue where
  parseJSON = withText "Issue ID" (return . parseIssue . unpack)

instance FromJSONKey Issue where
  fromJSONKey = FromJSONKeyText (parseIssue . unpack)

safeRead :: Read a => String -> String -> a
safeRead ctx x = fromMaybe (error ("invalid " ++ ctx ++ ": " ++ show x)) (readMaybe x)

stripFixmeSuffix :: String -> String
stripFixmeSuffix x
  | "_FIXME" `isSuffixOf` x = reverse . drop 6 . reverse $ x
  | otherwise               = x

isCve :: Issue -> Bool
isCve (Cve _ _) = True
isCve _ = False

isBsc :: Issue -> Bool
isBsc (Bsc _) = True
isBsc _ = False