{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE NoImplicitPrelude #-}

module Language.Haskell.Brittany.Internal.Transformations.T4_Columns where

import qualified Data.Generics.Uniplate.Direct as Uniplate
import qualified GHC.OldList as List
import Language.Haskell.Brittany.Internal.Prelude
import Language.Haskell.Brittany.Internal.Components.BriDoc



transformSimplifyColumns :: BriDoc -> BriDoc
transformSimplifyColumns = Uniplate.rewrite $ \case
  -- BDWrapAnnKey annKey bd ->
  --   BDWrapAnnKey annKey $ transformSimplify bd
  BDEmpty -> Nothing
  BDLit{} -> Nothing
  BDSeq list
    | any
      (\case
        BDSeq{} -> True
        BDEmpty{} -> True
        _ -> False
      )
      list
    -> Just $ BDSeq $ list >>= \case
      BDEmpty -> []
      BDSeq l -> l
      x -> [x]
  BDSeq (BDCols sig1 cols1@(_ : _) : rest)
    | all
      (\case
        BDSeparator -> True
        BDFlushCommentsPrior _ BDSeparator -> True
        BDFlushCommentsPost _ _ BDSeparator -> True
        _ -> False
      )
      rest
    -> Just $ BDCols sig1 (List.init cols1 ++ [BDSeq (List.last cols1 : rest)])
  BDLines lines
    | any
      (\case
        BDLines{} -> True
        BDEmpty{} -> True
        _ -> False
      )
      lines
    -> Just $ BDLines $ filter isNotEmpty $ lines >>= \case
      BDLines l -> l
      x -> [x]
  -- flush-prior floating in
  BDFlushCommentsPrior loc (BDSeq (l : lr)) ->
    Just $ BDSeq (BDFlushCommentsPrior loc l : lr)
  BDFlushCommentsPrior loc (BDLines (l : lr)) ->
    Just $ BDLines (BDFlushCommentsPrior loc l : lr)
  BDFlushCommentsPrior loc (BDCols sig (l : lr)) ->
    Just $ BDCols sig (BDFlushCommentsPrior loc l : lr)
  -- flush-post floating in
  BDFlushCommentsPost loc shouldMark (BDSeq list) ->
    Just
      $ BDSeq
      $ List.init list ++ [BDFlushCommentsPost loc shouldMark $ List.last list]
  BDFlushCommentsPost loc shouldMark (BDLines list) -> Just
    $ BDLines
    $ List.init list ++ [BDFlushCommentsPost loc shouldMark $ List.last list]
  BDFlushCommentsPost loc shouldMark (BDCols sig list) -> Just
    $ BDCols sig
    $ List.init list ++ [BDFlushCommentsPost loc shouldMark $ List.last list]
  -- ensureIndent float-in
  -- not sure if the following rule is necessary; tests currently are
  -- unaffected.
  -- BDEnsureIndent indent (BDLines lines) ->
  --   Just $ BDLines $ BDEnsureIndent indent <$> lines
  -- matching col special transformation
  BDCols sig1 cols1@(_ : _)
    | BDLines lines@(_ : _ : _) <- List.last cols1
    , BDCols sig2 cols2 <- List.last lines
    , sig1 == sig2
    -> Just $ BDLines
      [ BDCols sig1 $ List.init cols1 ++ [BDLines $ List.init lines]
      , BDCols sig2 cols2
      ]
  BDCols sig1 cols1@(_ : _)
    | BDLines lines@(_ : _ : _) <- List.last cols1
    , BDEnsureIndent _ (BDCols sig2 cols2) <- List.last lines
    , sig1 == sig2
    -> Just $ BDLines
      [ BDCols sig1 $ List.init cols1 ++ [BDLines $ List.init lines]
      , BDCols sig2 cols2
      ]
  BDPar ind col1@(BDCols sig1 _) col2@(BDCols sig2 _) | sig1 == sig2 ->
    Just $ BDAddBaseY ind (BDLines [col1, col2])
  -- BDPar ind col1@(BDCols sig1 _) (BDLines (col2@(BDCols sig2 _) : rest))
  --   | sig1 == sig2 -> Just $ BDPar ind (BDLines [col1, col2]) (BDLines rest)
  BDPar ind (BDLines lines1) col2@(BDCols sig2 _)
    | BDCols sig1 _ <- List.last lines1, sig1 == sig2 -> Just
    $ BDAddBaseY ind (BDLines $ lines1 ++ [col2])
  BDPar ind (BDLines lines1) (BDLines (col2@(BDCols sig2 _) : rest))
    | BDCols sig1 _ <- List.last lines1, sig1 == sig2 -> Just
    $ BDPar ind (BDLines $ lines1 ++ [col2]) (BDLines rest)
  -- BDPar ind1 (BDCols sig1 cols1) (BDPar ind2 line (BDCols sig2 cols2))
  --   | sig1==sig2 ->
  --       Just $ BDPar
  --         ind1
  --         (BDLines [BDCols sig1 cols1, BDCols sig])
  BDCols sig1 cols
    | BDPar _ind line (BDCols sig2 cols2) <- List.last cols, sig1 == sig2
    -> Just
      $ BDLines [BDCols sig1 (List.init cols ++ [line]), BDCols sig2 cols2]
  BDCols sig1 cols
    | BDPar _ line (BDLines lines) <- List.last cols
    , all (\case
            BDCols sig2 _ -> sig1 == sig2
            _ -> False
          )
          lines
    -> Just $ BDLines $ BDCols sig1 (List.init cols ++ [line]) : lines
  BDLines [x] -> Just $ x
  BDLines [] -> Just $ BDEmpty
  BDSeq{} -> Nothing
  BDCols{} -> Nothing
  BDSeparator -> Nothing
  BDAddBaseY{} -> Nothing
  BDBaseYPushCur{} -> Nothing
  BDIndentLevelPushCur{} -> Nothing
  BDIndentLevelPop{} -> Nothing
  BDPar{} -> Nothing
  BDAlt{} -> Nothing
  BDForceAlt{} -> Nothing
  BDForwardLineMode{} -> Nothing
  BDExternal{} -> Nothing
  BDPlain{} -> Nothing
  BDLines{} -> Nothing
  BDQueueComments{} -> Nothing
  BDFlushCommentsPrior{} -> Nothing
  BDFlushCommentsPost{} -> Nothing
  BDEntryDelta{} -> Nothing
  BDEnsureIndent{} -> Nothing
  BDDebug{} -> Nothing
