module Parse.Thread
  (
    getThreadFromHtml
  ) where

import Types (Thread (Thread), User (User))
import Text.HTML.TagSoup (Tag(TagOpen), fromAttrib, (~/=))
import Data.ByteString.Char8 (ByteString, unpack)
import qualified Data.ByteString.Char8 as BS (words, drop, length, dropWhile, takeWhile)
import Text.Regex.Posix ((=~))
import Text.Read (readMaybe)
import Data.Char (isDigit)

import Parse.User

import Debug.Trace (trace)

getThreadFromHtml :: [Tag ByteString] -> Maybe Thread
getThreadFromHtml html = do
  threadId <- getThreadIdFromHtml html
  forumId <- getForumIdFromHtml html
  let threadName = getThreadNameFromHtml html
  let user = getThreadUserFromHtml html
  return (Thread threadId forumId threadName user)

getForumIdFromHtml :: [Tag ByteString] -> Maybe Int
getForumIdFromHtml html = do
  let bodyTag = (head . dropWhile (~/= ("<body>" :: String))) html
  let forumId = (read . unpack . BS.drop 4 . head . BS.words . fromAttrib ("class" :: ByteString)) bodyTag :: Int
  return forumId

getThreadIdFromHtml :: [Tag ByteString] -> Maybe Int
getThreadIdFromHtml html = do
  url <- getThreadUrlFromHtml html
  threadId <- getThreadIdFromUrl url
  return threadId

getThreadUrlFromHtml :: [Tag ByteString] -> Maybe ByteString
getThreadUrlFromHtml html = do
  metaTag <- getMetaThreadUrlTag html
  return (fromAttrib "content" metaTag)

getMetaThreadUrlTag :: [Tag ByteString] -> Maybe (Tag ByteString)
getMetaThreadUrlTag html = case dropWhile (~/= metaTag) html of
  [] -> trace "Unable to find meta tag with property 'og:url'" Nothing
  xs -> Just (head xs)
  where metaTag = TagOpen "meta" [("property", "og:url")] :: Tag ByteString

getThreadIdFromUrl :: ByteString -> Maybe Int
getThreadIdFromUrl url = case url =~ ("\\.?([0-9]+)/" :: ByteString) :: ByteString of
  "" -> trace ("Unable to find any matches in the URL: " ++ (show url)) Nothing
  match -> case fixMatch match of
    Nothing -> trace ("Incorrect number of non-number characters in match: " ++ (show match)) Nothing
    Just match -> case (readMaybe . unpack) match :: Maybe Int of
      Nothing -> trace ("Unable to convert `" ++ (show match) ++ "` to Int") Nothing
      x -> x

fixMatch :: ByteString -> Maybe ByteString
fixMatch match
  | (BS.length $ doFix match) < (BS.length match) - 2 = Nothing
  | otherwise = Just $ doFix match
  where doFix = BS.takeWhile isDigit . BS.dropWhile (not . isDigit)

getThreadNameFromHtml :: [Tag ByteString] -> ByteString
getThreadNameFromHtml = fromAttrib ("content" :: ByteString) . head . take 1 . dropWhile (~/= tag)
  where tag = TagOpen "meta" [("property", "og:title")] :: Tag ByteString
