{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE UndecidableInstances #-}

module Data.OSC1337
  ( module Data.OSC1337,
    LatexStr (..),
    latex,
    math,
  )
where

import Codec.Picture
import Codec.Picture.Png (encodePng)
import qualified Data.ByteString as B
import Data.ByteString (ByteString)
import Data.ByteString.Base64 (encode)
import qualified Data.ByteString.Char8 as BC
import Data.ByteString.Lazy (toStrict)
import Data.Sixel.Internal
import System.IO.Unsafe (unsafePerformIO)

data OSCCmd
  = Start
  | End
  | FileName String
  | Size Int
  | Width Int
  | Height Int
  | PreserveAspectRatio Int
  | Inline Int
  | Align String
  | MimeType String
  | ImageDat String
  deriving (Eq)

instance Show OSCCmd where
  show = \case
    Start -> "\ESC]1337;"
    End -> "\a"
    Size s -> "size=" ++ show s ++ ";"
    Width s -> "width=" ++ show s ++ ";"
    Height s -> "height=" ++ show s ++ ";"
    PreserveAspectRatio s -> "preserveAspectRatio=" ++ show s ++ ";"
    Inline s -> "inline=" ++ show s ++ ";"
    Align s -> "align=" ++ s ++ ";"
    MimeType s -> "type=" ++ s ++ ";"
    ImageDat s -> BC.unpack $ encode $ BC.pack s

instance {-# OVERLAPS #-} Show [OSCCmd] where
  show xs = concat $ map show xs

newtype OSCImage = OSCImage {toOSCString :: String} deriving (Eq)

instance Show OSCImage where
  show (OSCImage img) = img

-- | See https://chromium.googlesource.com/apps/libapps/+/master/hterm/doc/ControlSequences.md#OSC-1337
class ToOSC a where
  toOSC :: a -> OSCImage
  putOSC :: a -> IO ()

instance {-# OVERLAPS #-} (Show a) => ToOSC a where
  toOSC xs = OSCImage $ show xs
  putOSC xs = putStrLn $ show xs

img2osc :: Image PixelRGB8 -> ByteString
img2osc img =
  let (Image w h _) = img
      dat = toStrict $ encodePng img
   in B.concat
        [ "\ESC]1337;File=name=",
          encode "display.png",
          ";",
          "width=" <> BC.pack (show w) <> "px;",
          "height=" <> BC.pack (show h) <> "px;",
          "inline=1;:",
          encode dat,
          "\a"
        ]

instance {-# OVERLAPS #-} ToOSC DynamicImage where
  toOSC dimg = toOSC $ convertRGB8 dimg
  putOSC img = putOSC $ convertRGB8 img

instance {-# OVERLAPS #-} ToOSC (Image PixelRGB8) where
  toOSC img = OSCImage (BC.unpack $ img2osc img)
  putOSC img = B.putStr $ img2osc img

putImage :: FilePath -> IO ()
putImage file = do
  readImage file >>= \case
    Left err -> print err
    Right img -> putOSC img

instance Show LatexStr where
  show str = show $ toOSC str

instance ToOSC LatexStr where
  toOSC str = unsafePerformIO $ do
    latex2img str >>= \case
      Left err -> error err
      Right img -> return $ toOSC img
  putOSC img = putStr $ show $ toOSC img