import Control.Monad (when)
import Data.Map qualified as M
import Data.Monoid
import Data.Ratio
import Graphics.X11.ExtraTypes.XF86
import System.Exit
import XMonad
import XMonad.Actions.KeyRemap
import XMonad.Hooks.EwmhDesktops
import XMonad.Hooks.ManageDocks
import XMonad.Hooks.StatusBar
import XMonad.Hooks.StatusBar.PP
import XMonad.Layout.Circle
import XMonad.Layout.DraggingVisualizer
import XMonad.Layout.Grid
import XMonad.Layout.IfMax
import XMonad.Layout.Magnifier
import XMonad.Layout.Spacing
import XMonad.Layout.Tabbed
import XMonad.Layout.ThreeColumns
import XMonad.Layout.VoidBorders
import XMonad.Layout.WindowSwitcherDecoration
import XMonad.Prompt
import XMonad.Prompt.Layout
import XMonad.StackSet qualified as W
import XMonad.Actions.NoBorders
import XMonad.Util.EZConfig
import XMonad.Hooks.ServerMode

myKeys conf@(XConfig {XMonad.modMask = modm}) =
  M.fromList $
    [ ((modm, xK_Return), spawn $ XMonad.terminal conf),
      ((modm .|. shiftMask, xK_q), kill),
      --  -- Rotate through the available layout algorithms
      ((modm, xK_space), sendMessage NextLayout),
      -- rofiing
      ((modm, xK_d), spawn "rofi -show drun"),
      ((modm .|. shiftMask, xK_e), spawn "rofi -show desktopctl -modes desktopctl:desktopctl -show-icons"),
      ((modm, xK_m), spawn "menu-qalc -- -theme gruvbox-dark"),
      ((modm, xK_i), spawn "rofimoji --selector-args '-theme gruvbox-dark' -f alchemical_symbols anatolian_hieroglyphs emojis braille_patterns box_drawing chess_symbols emoticons geometric_shapes gothic greek_extended math mathematical_alphanumeric_symbols mathematical_operators miscellaneous_symbols miscellaneous_mathematical_symbols-a miscellaneous_mathematical_symbols-b miscellaneous_symbols_and_arrows miscellaneous_symbols_and_pictographs miscellaneous_technical modi modifier_tone_letters musical_symbols nerd_font number_forms shorthand_format_controls specials variation_selectors vertical_forms -a copy"),
      -- screenshotting
      -- TODO: Fix/rewrite window-screenshot
      ((modm, xK_w), spawn "window-screenshot.nu"),
      ((modm, xK_s), spawn "flameshot gui -c -p $HOME/Pictures/screenshots"),
      ((modm, xK_a), spawn "flameshot screen -c -p $HOME/Pictures/screenshots"),
      ((modm, xK_t), spawn "ocr-screenshot.sh"),
      ((modm .|. shiftMask, xK_t), spawn "DEVICE=\"bcm5974\"; if [ $(xinput list-props \"$DEVICE\" | awk '/^\\tDevice Enabled \\([0-9]+\\):\\t[01]/ {print $NF}') = \"1\" ]; then xinput disable \"$DEVICE\"; else xinput enable \"$DEVICE\"; fi"),
      -- Push window back into tiling
      ((modm .|. shiftMask, xK_space), withFocused $ windows . W.sink),
      -- Resize viewed windows to the correct size
      ((modm, xK_n), refresh),
      -- Move focus to the next window
      ((modm, xK_Tab), layoutPrompt def),
      -- Move focus
      ((modm, xK_j), windows W.focusDown),
      ((modm, xK_k), windows W.focusUp),
      -- Swap the focused window with the next window
      ((modm .|. shiftMask, xK_j), windows W.swapDown),
      ((modm .|. shiftMask, xK_k), windows W.swapUp),
      -- Shrink the master area
      ((modm, xK_h), sendMessage Shrink),
      ((modm, xK_l), sendMessage Expand),
      -- Increment the number of windows in the master area
      ((modm, xK_comma), sendMessage (IncMasterN 1)),
      ((modm, xK_period), sendMessage (IncMasterN (-1))),
      ((modm, xK_b), sendMessage ToggleStruts >> withFocused toggleBorder),
      -- volume keys
      -- TODO: other media keys
      ((0, xF86XK_AudioRaiseVolume), spawn "amixer -D pulse sset Master 10%+"),
      ((0, xF86XK_AudioLowerVolume), spawn "amixer -D pulse sset Master 10%-"),
      ((0, xF86XK_AudioMute), spawn "amixer -D pulse sset Master toggle"),
      ((0, xF86XK_AudioNext), spawn "playerctl next"),
      ((0, xF86XK_AudioPrev), spawn "playerctl previous"),
      ((0, xF86XK_AudioPause), spawn "playerctl play-pause")
    ]
      ++ [ ((m .|. modm, k), windows $ f i)
           | (i, k) <- zip (XMonad.workspaces conf) [xK_1 .. xK_9],
             (f, m) <- [(W.greedyView, 0), (W.shift, shiftMask)]
         ]

-- TODO: figure out multi screen stuff, including xinerama

-- Mouse bindings: default actions bound to mouse events
myMouseBindings (XConfig {XMonad.modMask = modm}) =
  M.fromList
    -- mod-button1, Set the window to floating mode and move by dragging
    [ ( (modm, button1),
        \w -> do
          focus w
          mouseMoveWindow w
          windows W.shiftMaster
      ),
      -- mod-button2, Raise the window to the top of the stack
      ( (modm, button3),
        \w -> do
          focus w
          mouseResizeWindow w
          windows W.shiftMaster
      )
    ]

tabCfg =
  def
    { activeColor = "#282828",
      inactiveColor = "#1d2021",
      urgentColor = "#9d0006",
      activeBorderColor = "#504945",
      inactiveBorderColor = "#3c3836",
      urgentBorderColor = "#cc241d",
      activeTextColor = "#ebdbb2",
      inactiveTextColor = "#bdae93",
      urgentTextColor = "#ebdbb2"
    }

myLayout = setupSpacing $ avoidStruts $ autoChoose ||| tabbed shrinkText tabCfg
  where
    -- default tiling algorithm partitions the screen into two panes
    autoChoose = IfMax 2 tiled $ IfMax 3 tiled_mag $ IfMax 4 grid_mag threeCol
    setupSpacing = spacingRaw True (Border 0 0 0 0) True (Border 7 7 7 7) True 
    grid_mag = magnifiercz 1.4 Grid
    tiled = Tall nmaster delta ratio
    tiled_mag = magnifiercz' 1.4 tiled
    threeCol = magnifiercz' 1.6 $ ThreeColMid nmaster delta ratio
    -- The default number of windows in the master pane
    nmaster = 1
    -- Default proportion of screen occupied by master pane
    ratio = 1 / 2
    -- Percent of screen to increment by when resizing panes
    delta = 3 / 100

myManageHook =
  composeAll
    [ className =? "MPlayer" --> doFloat,
      className =? "Gimp" --> doFloat,
      className =? "firefox" --> doShift "browser",
      className =? "Evolution" --> doShift "comms",
      className =? "Signal" --> doShift "comms",
      className =? "SchildiChat" --> doShift "comms",
      resource =? "desktop_window" --> doIgnore,
      resource =? "kdesktop" --> doIgnore
    ]

myStartupHook = do
  spawn "pgrep oneko || oneko -tofocus -tora -position +-1+5 -fg palevioletred3 -bg pink -name 'Rose the desktop kitty'"
  spawn "pgrep volumeicon || volumeicon"
  spawn "pgrep nm-applet || nm-applet"
  spawn "pgrep mullvad-gui || mullvad-vpn"
  spawn "feh --bg-fill ~/Pictures/wallpaper.jpg"

xmeowbar = statusBarProp "~/.config/xmobar/xmobar" $ pure xmobarPP
polybar = statusBarProp "polybar" $ pure xmobarPP
barSpawner 0 = pure $ xmeowbar <> polybar 
barSpawner _ = mempty

main :: IO()
main = xmonad $ docks $ dynamicSBs barSpawner $ ewmh defaults

defaults =
  def
    { -- simple stuff
      terminal = "kitty",
      focusFollowsMouse = False,
      clickJustFocuses = False,
      borderWidth = 2,
      modMask = mod4Mask,
      workspaces = ["comms", "browser"] ++ map show [3 .. 9],
      normalBorderColor = "#3c3836",
      focusedBorderColor = "#504945",
      keys = myKeys,
      mouseBindings = myMouseBindings,
      layoutHook =myLayout,
      manageHook = myManageHook,
      startupHook = myStartupHook,
      handleEventHook = serverModeEventHook
    }