{-# LANGUAGE OverloadedStrings #-}

module Onomap.Svg (drawMap, renderMap) where

import qualified Data.Map as Map
import Data.Maybe (fromMaybe)
import Data.Text (Text)
import qualified Data.Text as Text
import Data.Text.Lazy (toStrict)
import Graphics.Svg
import Onomap.Types (Area (..), ByArea (..), ScaleToMaximum (..), SvgSettings (..))
import Text.Printf (printf)

renderMap :: SvgSettings -> [Text] -> [Area] -> [(Text, ByArea Double)] -> Text
renderMap settings colorPalette areas statistics = toStrict $ prettyText $ drawMap settings colorPalette areas statistics

drawMap :: SvgSettings -> [Text] -> [Area] -> [(Text, ByArea Double)] -> Element
drawMap settings colorPalette areas statistics =
    doctype <> with (svg11_ content) [Version_ <<- "1.1", Width_ <<- "650", Height_ <<- Text.pack (show (900 + 20 * length statistics))]
  where
    theMaxima = map maximum $ map (getByArea . snd) statistics
    globalMaximum = maximum theMaxima
    localize = Text.replace "." "," . Text.dropWhileEnd (== '.') . Text.dropWhileEnd (== '0')
    showRounded = Text.pack . printf "%.2f"
    frameColor = "black"
    areaPaths =
        foldMap
            ( \area ->
                path_ [Stroke_ <<- frameColor, Stroke_width_ <<- "0.3px", Fill_ <<- "none", D_ <<- path area]
                    <> foldMap
                        ( \((surname, statistic), color, theMaximum) ->
                            let count = fromMaybe 0 (Map.lookup (key area) (getByArea statistic))
                                theTitle =
                                    ( title_
                                        []
                                        ( toElement $
                                            mconcat
                                                [ name area
                                                , ": "
                                                , Text.intercalate
                                                    ", "
                                                    ( map
                                                        ( \(surname, statistic) ->
                                                            let count = fromMaybe 0 (Map.lookup (key area) (getByArea statistic))
                                                             in localize (showRounded count) <> " (" <> Text.toTitle surname <> ")"
                                                        )
                                                        statistics
                                                    )
                                                ]
                                        )
                                    )
                             in path_
                                    [ D_ <<- path area
                                    , Fill_ <<- color
                                    , Fill_opacity_
                                        <<- showRounded
                                            ( if count == 0
                                                then 0
                                                else
                                                    count
                                                        / ( case scaleToMaximum settings of
                                                                Global -> globalMaximum
                                                                Local -> theMaximum
                                                          )
                                            )
                                    , Stroke_ <<- "none"
                                    ]
                                    theTitle
                        )
                        (zip3 statistics (cycle colorPalette) theMaxima)
            )
            areas
    content =
        foldMap
            ( \(index, color, theMaximum) ->
                defs_
                    []
                    ( linearGradient_
                        [ Id_ <<- "legend" <> Text.pack (show index)
                        , X1_ <<- "0"
                        , X2_ <<- case scaleToMaximum settings of
                            Global -> Text.pack (show (recip $ theMaximum / globalMaximum))
                            Local -> "1"
                        , Y1_ <<- "0"
                        , Y2_ <<- "0"
                        ]
                        ( stop_ [Offset_ <<- "0%", Stop_color_ <<- "white"]
                            <> stop_ [Offset_ <<- "100%", Stop_color_ <<- color]
                        )
                    )
            )
            (zip3 [0 ..] colorPalette theMaxima)
            <> foldMap
                ( \(index, (name, statistic)) ->
                    g_
                        []
                        ( rect_
                            [ X_ <<- "165"
                            , Y_ <<- Text.pack (show (880 + 20 * index))
                            , Stroke_ <<- frameColor
                            , Width_ <<- "350"
                            , Height_ <<- "10"
                            , Fill_ <<- "url(#legend" <> Text.pack (show index) <> ")"
                            ]
                            <> text_
                                [ X_ <<- "155"
                                , Y_ <<- Text.pack (show (890 + 20 * index))
                                , Font_size_ <<- "18"
                                , Fill_ <<- "black"
                                , Text_anchor_ <<- "end"
                                ]
                                (toElement $ Text.toTitle name)
                            <> text_
                                [ X_ <<- "525"
                                , Y_ <<- Text.pack (show (890 + 20 * index))
                                , Font_size_ <<- "18"
                                , Fill_ <<- "black"
                                ]
                                (toElement $ localize $ showRounded $ maximum $ getByArea statistic)
                        )
                )
                (zip [0 ..] statistics)
            <> style_ [] "path { mix-blend-mode: multiply; }"
            <> g_ [] areaPaths
