module ISINVerification2 where

import Data.Char (isUpper, isDigit, digitToInt)

verifyISIN :: String -> Bool
verifyISIN isin =
  correctFormat isin && mod (oddsum + multiplied_even_sum) 10 == 0
  where
    reverted = reverse $ convertToNumber isin
    theOdds = fst $ collectOddandEven reverted
    theEvens = snd $ collectOddandEven reverted
    oddsum = sum $ map digitToInt theOdds
    multiplied_even_sum = addUpDigits $ map ((* 2) . digitToInt) theEvens

capitalLetters :: String
capitalLetters = ['A','B' .. 'Z']

numbers :: String
numbers = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']

correctFormat :: String -> Bool
correctFormat isin =
  (length isin == 12) &&
  all (`elem` capitalLetters) (take 2 isin) &&
  all (\c -> elem c capitalLetters || elem c numbers) (drop 2 $ take 11 isin) &&
  elem (last isin) numbers

convertToNumber :: String -> String
convertToNumber = concatMap convert
  where
    convert :: Char -> String
    convert c =
      if isDigit c
        then show $ digitToInt c
        else show (fromEnum c - 55)

collectOddandEven :: String -> (String, String)
collectOddandEven term
  | odd $ length term =
    ( concat
        [ take 1 $ drop n term
        | n <- [0,2 .. length term - 1] ]
    , concat
        [ take 1 $ drop d term
        | d <- [1,3 .. length term - 2] ])
  | otherwise =
    ( concat
        [ take 1 $ drop n term
        | n <- [0,2 .. length term - 2] ]
    , concat
        [ take 1 $ drop d term
        | d <- [1,3 .. length term - 1] ])

addUpDigits :: [Int] -> Int
addUpDigits list =
  sum $
  map
    (\d ->
        if d > 9
          then sum $ map digitToInt $ show d
          else d)
    list

printSolution :: String -> IO ()
printSolution str = do
  putStr $ str ++ " is"
  if verifyISIN str
    then putStrLn " valid"
    else putStrLn " not valid"

main :: IO ()
main = do
  let isinnumbers =
        [ "US0378331005"
        , "US0373831005"
        , "U50378331005"
        , "US03378331005"
        , "AU0000XVGZA3"
        , "AU0000VXGZA3"
        , "FR0000988040"
        ]
  mapM_ printSolution isinnumbers