"""Provides classes related to starships."""

from datetime import timedelta
from sqlalchemy import Column, Float, String
from attrs_sqlalchemy import attrs_sqlalchemy
from .base import Base, ComponentMixin
from util import percent
from distance import m, ly

message_length = 150


@attrs_sqlalchemy
class WormholeDrive(Base, ComponentMixin):
    """
    A wormhole drive.

    distance is the maximum length of a wormhole created by this unit.
    power is how many units of energy are needed by this unit to keep a
    wormhole stable. (subtracted per second)."""
    __tablename__ = 'wormhole_drives'
    distance = Column(Float, nullable=False, default=2.5 * ly)
    power = Column(Float, nullable=False, default=500.0)


@attrs_sqlalchemy
class StarshipDrive(Base, ComponentMixin):
    """
    A starship drive.

    power is multiplied by thrust to decide how much energy this unit requires.
    max_thrust is the maximum acceleration or deceleration for this drive.
    thrust is the current thrust of this drive. If it is a positive number,
    then it is considered accelerating. If it is negative, then the ship is
    considered to be decelerating. If it is None, then the drive is considered
    to be off. In the case that it is not None, it is considered a fraction of
    max_thrust and should be no greater than 1.0, and no less than -1.0.
    """
    __tablename__ = 'starship_drives'
    power = Column(Float, nullable=False, default=5.0)
    max_thrust = Column(Float, nullable=False, default=100 * m)
    thrust = Column(Float, nullable=True)
    start_msg = Column(
        String(message_length),
        nullable=False,
        default='You become aware of an increase in background noise as the '
        'main drive activates.'
    )
    stop_msg = Column(
        String(message_length),
        nullable=False,
        default='The sound of the main drive fades to silence.'
    )
    accelerate_msg = Column(
        String(message_length),
        nullable=False,
        default='You notice the effects of acceleration.'
    )
    decelerate_msg = Column(
        String(message_length),
        nullable=False,
        default='You notice the effects of deceleration.'
    )
    change_direction_msg = Column(
        String(message_length),
        nullable=False,
        default='Gravity shifts slightly then returns to normal.'
    )

    def get_thrust(self):
        """Return the thrust of this drive based on self.thrust and
        self.hp. This number should be considered a full thrust value, not a
        fraction."""
        return (
            (self.thrust or 1.0) / (
                percent(
                    self.hp,
                    self.max_hitpoints
                ) / 100.0
            )
        ) * self.max_thrust

    def start(self, thrust):
        """Start this drive working with the specified thrust."""
        self.thrust = thrust
        self.save()
        self.vehicle.announce_all(self.start_msg)

    def stop(self):
        """Stop this drive."""
        self.thrust = None
        self.save()
        self.vehicle.announce_all(self.stop_msg)

    def time_to_decelerate(self):
        """Returns a timedelta representing how long it will take this drive to
        decelerate its host ship to a full stop."""
        return timedelta(seconds=self.vehicle.speed / abs(self.get_thrust()))

    def distance_to_decelerate(self):
        """Returns the distance (in units) it will take this drive to
        decelerate to a full stop. If the drive is not thrusting, a full
        deceleration is assumed."""
        # Use abs to prevent infinite loops.
        thrust = abs(self.get_thrust() or -1.0)
        speed = self.vehicle.speed
        distance = 0.0
        while speed > 0.0:
            distance += speed
            speed -= thrust
        return distance
