module Dodge.Block where
import Dodge.Data
import Dodge.Base.Collide
import Dodge.Material
--import Dodge.Block.Debris
import Dodge.Zone
import Dodge.WorldEvent.Sound
import Dodge.Wall.Delete
import Dodge.Wall.Dust
import RandomHelp
import Geometry
--import Geometry.ConvexPoly

import Data.Foldable
import Data.Function
import Data.Maybe
import qualified Data.IntSet as IS
import qualified Data.IntMap.Strict as IM
import Control.Lens
import qualified Streaming.Prelude as S
import qualified Data.Graph.Inductive as FGL

splinterBlock :: Block -> World -> World
splinterBlock bl w = foldr unshadowBlock w (_blShadows bl) -- foldr shiftTowardCen w (_blWallIDs bl)
    & originsIDsAt [MaterialSound bm 0,MaterialSound bm 1,MaterialSound bm 2]
        (weakenMatS bm) (_blPos bl)
  where
    bm = fromMaybe Stone $ do
        wlids <- w ^? blocks . ix (_blID bl) . blWallIDs
        (wlid,_) <- IS.minView wlids
        w ^? walls . ix wlid . wlMaterial

unshadowBlock :: Int -> World -> World
unshadowBlock wlid w = case w ^? walls . ix wlid of
    Just wl -> w
        & walls . ix wlid . wlDraw .~ True
        & wlZoning . znObjects . ix x . ix y . ix wlid . wlDraw .~ True
      where
        V2 x y = wlZoneOfPoint $ uncurry midPoint (_wlLine wl)
    Nothing -> w

checkBlockHP :: Block -> World -> World
checkBlockHP bl
    | _blHP bl < 1 = destroyBlock bl
    | otherwise = id

destroyBlock :: Block -> World -> World
destroyBlock bl w = w
    & flip (foldr unshadowBlock) (_blShadows bl)
    & _blDeath bl bl
    & deleteWallIDs wlids
    & maybeClearPaths (_blObstructs bl) -- must happen after the walls are deleted
    & blocks %~ IM.delete (_blID bl)
--    & matDesSound (_blMaterial bl) pos
    & flip (foldr (wlDustAt awl)) (map (pos +.+) ps)
  where
    wlids = _blWallIDs bl
    awl = _walls w IM.! IS.findMin wlids
    pos = fst . _wlLine $ _walls w IM.! IS.findMin wlids
    ps = replicateM 25 (randInCirc 20) & evalState $ _randGen w

-- this does not handle eg doors blocking the path as well
maybeClearPaths :: [(Int,Int,PathEdge)] -> World -> World
maybeClearPaths ps w = foldl' maybeClearPath w ps

maybeClearPath :: World -> (Int,Int,PathEdge) -> World
maybeClearPath w (x,y,pe) 
    | runIdentity . S.any_ (const True) $ overlapSegWalls (_peStart pe) (_peEnd pe) $ wlsNearSeg (_peStart pe) (_peEnd pe) w
        = w
    | otherwise = w & pathGraph %~ FGL.insEdge (x,y,pe & peObstacles .~ mempty) . FGL.delEdge (x,y) 

destroyDoor :: Door -> World -> World
destroyDoor dr w = w
    & _drDeath dr dr
    & deleteWallIDs wlids
    & doors %~ IM.delete (_drID dr)
    & flip (foldr (wlDustAt awl)) (map (pos +.+) ps)
    & stopPushing (_drPushes dr)
    & destroyMounts (_drMounts dr)
  where
    wlids = _drWallIDs dr
    awl = _walls w IM.! IS.findMin wlids
    pos = fst . _wlLine $ _walls w IM.! IS.findMin wlids
    ps = replicateM 25 (randInCirc 20) & evalState $ _randGen w

destroyMounts :: [MountedObject] -> World -> World
destroyMounts mos w = foldr destroyMount w mos

destroyMount :: MountedObject -> World -> World
destroyMount mo = case mo of
    MountedLS lsid -> lightSources . at lsid .~ Nothing
    MountedProp prid -> props . at prid .~ Nothing

stopPushing :: Maybe Int -> World -> World
stopPushing mdrid w = fromMaybe w $ do
    drid <- mdrid
    dr <- w ^? doors . ix drid
    return $ w & doors . ix drid . drMech .~ const id
        & stopPushing (_drPushes dr)
