import bge
import mathutils
from mathutils import Vector

from .math_base import clamp, discretize, lerp

DEFAULT_SETTINGS = {
    'health_initial': 1.0,
    'health_drain_time_s': 30.0,
    'health_max': 1.0,
    'health_immortal': False,
}
TICKS_PER_SECOND = 60
HEALTH_SMOOTHING = 20
VITAL_SIGN_STEP_SIZE = 1/5
NOISE_FREQUENCY = 3
NOISE_AMPLITUDE = 0.1
LIGHT_DISTANCE = 8.0
LIGHT_ATTN_POWER = 2
MUSIC_ATTN_POWER = 4


def init(c):
    char_root = c.owner
    settings = get_settings(char_root.scene)
    char_root['health'] = settings['health_initial']
    char_root['smooth_vitals'] = settings['health_initial']
    char_root['vitals'] = settings['health_initial']


def get_settings(scene):
    try:
        overrides = scene.objects['settings']
    except KeyError:
        overrides = {}

    return {
        k: overrides[k] if k in overrides else default
        for k, default in DEFAULT_SETTINGS.items()}


def init_zone(c):
    zone = c.owner
    if zone['init']:
        return
    sensor = c.sensors['near']
    sensor.distance *= zone.worldScale[0]
    sensor.resetDistance *= zone.worldScale[0]
    zone['init'] = True


def update(c):
    char_root = c.owner
    safe_zone_sensor = c.sensors['safe']
    settings = get_settings(char_root.scene)
    update_health(char_root, safe_zone_sensor.positive, settings)
    update_vitals(char_root)
    if char_root['smooth_vitals'] <= 0.001 and not settings['health_immortal']:
        game_over()
        return

    update_object_color(char_root)
    update_light_intensity(char_root)
    update_light_pos(char_root)

    update_music(char_root)


def game_over():
    bge.logic.startGame('//game_over.blend')


def update_health(char_root, safe, settings):
    if safe:
        char_root['health'] = settings['health_max']
        return

    drain_rate = 1 / (settings['health_drain_time_s'] * 60)
    char_root['health'] = max(char_root['health'] - drain_rate, 0)


def update_vitals(char_root):
    stepped_heath = discretize(char_root['health'], VITAL_SIGN_STEP_SIZE)
    char_root['smooth_vitals'] = lerp(
        char_root['smooth_vitals'], stepped_heath,
        1 / HEALTH_SMOOTHING)

    noise_pos = Vector((bge.logic.getClockTime() * NOISE_FREQUENCY, 0, 0))
    noise = mathutils.noise.noise(noise_pos)
    char_root['vitals'] = clamp(
        char_root['smooth_vitals'] + noise * NOISE_AMPLITUDE, 0, 1)


def update_object_color(char_root):
    arm = char_root.children['arm']
    skin = arm.children['spring']
    skin.color = [char_root['vitals'] ** LIGHT_ATTN_POWER] * 4


def update_light_intensity(char_root):
    lamp = char_root.scene.objects['life_light']
    lamp.energy = char_root['vitals'] ** LIGHT_ATTN_POWER
    lamp.distance = char_root['vitals'] * LIGHT_DISTANCE


def update_light_pos(char_root):
    arm = char_root.children['arm']
    bone_channel = arm.channels['lighthook']
    lamp = char_root.scene.objects['life_light']
    lamp.worldTransform = arm.worldTransform * bone_channel.pose_matrix


def update_music(char_root):
    upbeat = (1 - char_root['smooth_vitals']) ** MUSIC_ATTN_POWER
    bge.logic.sendMessage('upbeat', str(upbeat))
