import logging
from couchdbkit.exceptions import ResourceNotFound
from dimagi.utils.couch.database import iter_docs
from dimagi.utils.decorators.memoized import memoized
from corehq.apps.locations.models import Location
from corehq.apps.commtrack.models import SupplyPointCase, StockState, SQLLocation
from corehq.apps.products.models import Product
from dimagi.utils.couch.loosechange import map_reduce
from corehq.apps.reports.api import ReportDataSource
from datetime import datetime, timedelta
from dateutil import parser
from casexml.apps.stock.models import StockTransaction, StockReport
from couchforms.models import XFormInstance
from corehq.apps.reports.commtrack.util import get_relevant_supply_point_ids, product_ids_filtered_by_program
from corehq.apps.reports.commtrack.const import STOCK_SECTION_TYPE
from casexml.apps.stock.utils import months_of_stock_remaining, stock_category, state_stock_category
from corehq.apps.reports.standard.monitoring import MultiFormDrilldownMixin
from decimal import Decimal
from django.db.models import Sum


def format_decimal(d):
    # https://docs.python.org/2/library/decimal.html#decimal-faq
    if d is not None:
        return d.quantize(Decimal(1)) if d == d.to_integral() else d.normalize()
    else:
        return None


def _location_map(location_ids):
    return {
        loc.location_id: loc
        for loc in (SQLLocation.objects
                    .filter(is_archived=False,
                            location_id__in=location_ids)
                    .prefetch_related('location_type'))
    }


def geopoint(location):
    if None in (location.latitude, location.longitude):
        return None
    return '{} {}'.format(location.latitude, location.longitude)


class CommtrackDataSourceMixin(object):

    @property
    def domain(self):
        return self.config.get('domain')

    @property
    @memoized
    def active_location(self):
        return Location.get_in_domain(self.domain, self.config.get('location_id'))

    @property
    @memoized
    def active_product(self):
        prod_id = self.config.get('product_id')
        if prod_id:
            return Product.get(prod_id)

    @property
    @memoized
    def program_id(self):
        prog_id = self.config.get('program_id')
        if prog_id != '':
            return prog_id

    @property
    def start_date(self):
        return self.config.get('startdate') or (datetime.utcnow() - timedelta(30)).date()

    @property
    def end_date(self):
        return self.config.get('enddate') or datetime.utcnow().date()

    @property
    def request(self):
        request = self.config.get('request')
        if request:
            return request


class SimplifiedInventoryDataSource(ReportDataSource, CommtrackDataSourceMixin):
    slug = 'location_inventory'

    def datetime(self):
        """
        Returns a datetime object at the end of the selected
        (or current) date. This is needed to properly filter
        transactions that occur during the day we are filtering
        for
        """
        # note: empty string is parsed as today's date
        date = self.config.get('date', '')

        try:
            date = parser.parse(date).date()
        except ValueError:
            date = datetime.utcnow().date()

        return datetime(date.year, date.month, date.day, 23, 59, 59)

    def get_data(self, slugs=None):
        if self.active_location:
            current_location = self.active_location.sql_location

            if current_location.supply_point_id:
                locations = [current_location]
            else:
                locations = []

            locations += list(
                current_location.get_descendants().filter(
                    is_archived=False,
                    supply_point_id__isnull=False