module Dodge.Item.Weapon.Utility where
import Dodge.Data
import Dodge.Base.Coordinate
import Dodge.Default
--import Dodge.Picture.Layer
import Dodge.Creature.Action
import Dodge.Item.Weapon.TriggerType
import Dodge.Item.Weapon.ExtraEffect
import Dodge.Default.Weapon
import Dodge.Wall.ForceField
import Dodge.Wall.Move
--import Sound.Data
import Geometry
import Picture
import qualified IntMapHelp as IM
import Shape
import ShapePicture

import Data.Maybe
--import qualified Data.Map.Strict as M
import Control.Lens
--import Control.Monad

rewindGun :: Item
rewindGun = defaultLeftItem
    { _itInvColor = cyan
    , _itConsumption = ChargeableAmmo
        { _wpMaxCharge  = 250
        , _wpCharge = 0
        }
    , _itEffect = ItRewindEffect rewindEffect []
    , _itUse = defaultlUse 
        & lUse .~ useRewindGun
        & eqEq . eqSite .~ GoesOnChest
    }
    & itType . iyBase .~ REWINDER
rewindEffect :: Item -> Creature -> World -> World
rewindEffect itm cr w 
    | Just invid == _crLeftInvSel cr = w & rewindWorlds %~ (take maxcharge . (w' : ))
        & ptrWpCharge .~ length (_rewindWorlds w)
    | otherwise = w & rewindWorlds .~ []
        & ptrWpCharge .~ 0
  where
    invid = fromJust $ _itInvPos itm
    ptrWpCharge = creatures . ix (_crID cr) . crInv . ix invid . itConsumption . wpCharge
    maxcharge = _wpMaxCharge . _itConsumption $ itm
    w' = w & rewindWorlds .~ []
        & timeFlow .~ NormalTimeFlow

useRewindGun :: Item -> Creature -> World -> World
useRewindGun _ _ w = case _rewindWorlds w of
    [w']        -> rewindusing w' [w']
    (w':ws)   -> rewindusing w' ws
    _           -> w
  where
    rewindusing w' ws = w
        & maybeWorld .~ Just' ( w'
--        & creatures . ix (_crID cr) .~ cr
        & upbuts
        & rewindWorlds .~ ws
        )
    upbuts = (keys .~ _keys w) .  (mouseButtons .~ _mouseButtons w)

-- needs to shift this item to the current inventory slot
shrinkGun :: Item
shrinkGun = defaultLeftItem
    {_itUse = defaultlUse {_lUse = hammerCheckL useShrinkGun}
            & useHammer .~ upHammer
--    , _itFloorPict = shrinkGunPic
    , _itAttachment = AttachBool True
    }
    & itType . iyBase .~ SHRINKER

shrinkGunPic :: Item -> SPic
shrinkGunPic _ = noPic $ colorSH violet $ upperPrismPoly 5 $ square 5

-- be careful changing this around; potential problems include updating the
-- creature but using the old crInvSel value
-- 22.05.23 this has been changed from using invids to items
useShrinkGun :: Item -> Creature -> World -> World
useShrinkGun it cr w = if _atBool $ _itAttachment it
    then tryResize 0.5 $ stripNoItems cr . f False UndroppableIdentified . dropExcept cr invid
    else tryResize 1   $ f True Uncursed . setMinInvSize defaultInvSize cr
  where
    invid = fromJust $ _itInvPos it
    tryResize x g = maybe w g $ sizeSelf x cr w
    f isInUse cstatus = creatures . ix (_crID cr) . crInv . ix invid %~
        ( (itAttachment . atBool .~ isInUse) . (itCurseStatus .~ cstatus) )

blinkGun :: Item
blinkGun = defaultLeftItem 
    { _itInvColor = cyan
    , _itUse = defaultlUse 
        & lUse .~ hammerCheckL (shootL $ const blinkAction)
        & useHammer .~ upHammer
        & eqEq . eqSite .~ GoesOnWrist
--    , _itFloorPict = const . noPic . colorSH chartreuse $ upperPrismPoly 2 $ square 2
    }
    & itType . iyBase .~ BLINKER

unsafeBlinkGun :: Item
unsafeBlinkGun = blinkGun
    & itType . iyBase .~ BLINKERUNSAFE
    & itUse . lUse .~ hammerCheckL (shootL $ const unsafeBlinkAction)
    & itUse . eqEq . eqViewDist ?~ 400

effectGun :: String -> (Creature -> World -> World) -> Item
effectGun name eff = defaultWeapon
    { _itUse = defaultrUse
        & rUse .~ const eff
        & useMods .~ [hammerCheckI]
    }
    & itType . iyBase .~ EFFGUN name
autoEffectGun :: String -> (Creature -> World -> World) -> Item
autoEffectGun name eff = defaultWeapon
    { _itUse = defaultrUse {_rUse = const eff}
    }
    & itType . iyBase .~ AUTOEFFGUN name
forceFieldGun :: Item
forceFieldGun = defaultWeapon 
    { _itConsumption = defaultLoadable & laAmmoType .~ ForceFieldAmmo forceField
    , _itUse = ruseInstant useForceFieldGun (HasHammer HammerUp)
        [ hammerCheckI , ammoCheckI , useAmmoAmount 1]
--    , _itFloorPict = \_ -> (,) emptySH $ onLayer FlItLayer $ polygon $ map toV2 [(-4,-4),(-4,4),(4,4),(4,0),(0,0),(0,-4)]
    , _itTargeting = targetRBPress & tgDraw .~ targetDistanceDraw
    , _itParams = ParamMID Nothing
    }
    & itType . iyBase .~ FORCEFIELDGUN
-- I believe because the targeting returns to nothing straight after you release
-- the rmb, it is possible for this to do nothing
-- TODO investigate more and fix
useForceFieldGun :: Item -> Creature -> World -> World
useForceFieldGun itm cr w = fromMaybe w $ do 
    a <- _tgPos $ _itTargeting itm
    let mwp = mouseWorldPos w
        b = if dist a mwp < 100 then mwp else a +.+ 100 *.* normalizeV (mwp -.- a)
        wlline = (a,b)
    return $ w 
        & walls %~ IM.insertWith (\_ x -> x) i forceField {_wlID = i}
        & creatures . ix (_crID cr) . crInv . ix (fromJust (_itInvPos itm)) . itParams . paramMID ?~ i
        & moveWallIDUnsafe i wlline
  where
    i = fromMaybe (IM.newKey (_walls w)) $ itm ^? itParams . paramMID . _Just

-- grapGun = defaultGun 
--     { _itName = "grapGun"
--     , _itIdentity = GrapGun
--     , _wpMaxAmmo = 1
--     , _wpLoadedAmmo = 1
--     , _wpReloadTime = 40
--     , _wpReloadState = 0
--     , _itUseRate = 10
--     , _itUseTime = 0
--     , _itUse = grapFire
--     , _wpSpread = 0.002
--     , _wpRange = 20
--     , _wpIsAuto = False
--     , _itFloorPict = onLayer FlItLayer $ polygon [(-4,-4),(-4,4),(4,4),(4,0),(0,0),(0,-4)]
--     , _itAmount = 1
--     , _itMaxStack = 1
--     , _itAimingSpeed = 1
--     , _itAimingRange = 0.5
--     }
