"""Karma logging models."""
import math
import random

import pytz
from django.conf import settings
from django.db import models


class PiLogManager(models.Manager):
    """Assemble some queries against PiLog."""

    def simulate(self):
        """Add one more entry to the log, and return it."""
        try:
            latest = self.latest()
        except PiLog.DoesNotExist:
            latest = PiLog.objects.create(simulation_x=0.0, simulation_y=0.0,
                                          total_count_inside=0, total_count=0)
            latest.save()

        inside = latest.total_count_inside
        total = latest.total_count

        x = random.random()
        y = random.random()
        total += 1
        if math.hypot(x, y) < 1:
            inside += 1

        newest = PiLog.objects.create(simulation_x=x, simulation_y=y,
                                      total_count_inside=inside, total_count=total)

        # TODO: remove the x, y return values, now that we track them in the object
        return newest, x, y


class PiLog(models.Model):
    """Track pi as it is estimated over time."""

    simulation_x = models.DecimalField(max_digits=11, decimal_places=10)
    simulation_y = models.DecimalField(max_digits=11, decimal_places=10)
    total_count_inside = models.PositiveIntegerField()
    total_count = models.PositiveIntegerField()
    created = models.DateTimeField(auto_now_add=True)

    objects = PiLogManager()

    class Meta:
        """Options for the PiLog class."""

        get_latest_by = 'created'

    def __str__(self):
        """Provide string representation."""
        tz = pytz.timezone(settings.TIME_ZONE)
        return "({0:d}/{1:d}) @ {2:s}".format(self.total_count_inside, self.total_count,
                                              self.created.astimezone(tz).strftime('%Y-%m-%d %H:%M:%S %Z'))

    @property
    def value(self):
        """Return this log entry's estimated value of pi."""
        if self.total_count == 0:
            return 0.0
        return 4.0 * int(self.total_count_inside) / int(self.total_count)

    @property
    def hit(self):
        """Return if this log entry is inside the unit circle."""
        return math.hypot(self.simulation_x, self.simulation_y) < 1