module Dodge.Placement.Instance.Turret where
import Color
import Dodge.Data
import Dodge.LevelGen.Data
import Dodge.Default
import Dodge.FloorItem
import Dodge.Wall.Delete
import Dodge.WorldEvent.Explosion
import Dodge.Item.Weapon.BatteryGuns
import Dodge.SoundLogic.LoadSound
import Dodge.SoundLogic
import Geometry
import ShapePicture
import Shape
import Dodge.Base
import Dodge.Base.Collide

import Data.List
import Control.Lens
import qualified Data.IntMap.Strict as IM

putLasTurret :: Float -> Placement
putLasTurret rotSpeed = sps0 $ PutMachine blue (reverse $ square wdth) defaultMachine
    { _mcDraw = drawTurret
    , _mcUpdate = updateTurret rotSpeed
    , _mcType = lasTurret
    , _mcHP = 50000
    }
lasTurret :: MachineType
lasTurret = Turret
    { _tuWeapon = lasGun
    , _tuTurnSpeed = 0.1
    , _tuFireTime = 0
    }

updateTurret :: Float -> Machine -> World -> World
updateTurret rotSpeed mc w 
    | _mcHP mc < 1 = w & machines %~ IM.delete mcid
        & deleteWallIDs (_mcWallIDs mc)
        & makeExplosionAt mcpos
        & copyItemToFloor mcpos lasGun
    | otherwise = w & doDamage & maybeFire & elecDamBranch
  where
    doDamage = machines . ix mcid %~ 
        ( (mcDamage .~ [Electrical (min 2500 $ max 0 (elecDam - 10)) 0 0 0])
        . (mcHP -~ dam)
        )
    elecDamBranch
        | elecDam < 10 = updateFiringStatus . doTurn
        | otherwise = id
    -- TODO make this use the same function as the lasgun
    maybeFire
        | _tuFireTime (_mcType mc) > 0
            = ( particles %~ (makeLaserAt 5 (mcpos + 15 *.* unitVectorAtAngle mcdir) mcdir :) )
            . soundContinue (MachineSound mcid) mcpos tone440sawtoothquietS (Just 1)
        | otherwise = id
    mcid = _mcID mc
    ypos = _crPos $ you w
    mcpos = _mcPos mc
    mcdir = _mcDir mc
    seesYou = hasLOSIndirect mcpos ypos w
    (elecDams, dams) = partition isElectrical $ _mcDamage mc
    dam = sum $ map _dmAmount dams
    elecDam = sum $ map _dmAmount elecDams
    doTurn  
        | seesYou = machines . ix mcid . mcDir %~ turnTo rotSpeed mcpos ypos
        | otherwise = id
    closeFireAngle = seesYou && angleVV (ypos -.- mcpos) (unitVectorAtAngle mcdir) < 1
    updateFiringStatus 
        | closeFireAngle = machines . ix mcid . mcType . tuFireTime .~ 20
        | otherwise      = machines . ix mcid . mcType . tuFireTime %~ (max 0 . subtract 1)
    
turnTo :: Float -> Point2 -> Point2 -> Float -> Float
turnTo turnSpeed sp tp a
    | vToTarg == V2 0 0 = a
    | angleVV vToTarg vdir <= turnSpeed
                                = argV vToTarg
    | isLHS (sp +.+ vdir) sp tp = a - turnSpeed
    | otherwise                 = a + turnSpeed
  where
    vdir = unitVectorAtAngle a
    vToTarg = tp -.- sp

drawTurret :: Machine -> SPic
drawTurret mc = (rotateSH (-_mcDir mc) . colorSH blue $ upperPrismPoly 20 (square wdth)
    , mempty -- setLayer 5 $ scale 0.5 0.5 $ text $ show $ _mcDir mc )
    )
    <> translateSPz 20 (_itFloorPict it it)
  where
    it = _tuWeapon $ _mcType mc

wdth :: Float
wdth = 10
