from datetime import timedelta
from rest.serializers import ReportTemplateSerializer
from core.views import ModelListViewBase, LoginRequiredMixin, SimpleCreateViewBase, DetailedModelViewBase
from core.views import SimpleUpdateViewBase
from .models import ReportTemplate
from users.models import HEAD_OF_LAB_ID, LAB_GROUP_ID
from django.views.generic import TemplateView
from projects.models import Project
from .forms import ProjectReportTemplateSelectForm
from measurements.models import Measurement


class ReportTemplateListView(LoginRequiredMixin, ModelListViewBase):
    serializer = ReportTemplateSerializer
    require_group = HEAD_OF_LAB_ID


class ReportTemplateDetailView(LoginRequiredMixin, DetailedModelViewBase):
    model = ReportTemplate
    require_group = HEAD_OF_LAB_ID


class ReportTemplateCreateView(LoginRequiredMixin, SimpleCreateViewBase):
    model = ReportTemplate
    require_group = HEAD_OF_LAB_ID


class ReportTemplateUpdateView(LoginRequiredMixin, SimpleUpdateViewBase):
    model = ReportTemplate
    require_group = HEAD_OF_LAB_ID

# report creation forms and stuff
class ProjectReportSetupView(LoginRequiredMixin, TemplateView):
    template_name = 'report_template/create.html'
    project = None

    require_group = LAB_GROUP_ID

    def dispatch(self, request, *args, **kwargs):
        # grab pk from url and fetch the project object
        pk = self.kwargs.get('pk', None)
        self.project = Project.objects.get(pk=pk)
        return super(ProjectReportSetupView, self).dispatch(request, *args, **kwargs)

    def get_context_data(self, **kwargs):
        ctx = super(ProjectReportSetupView, self).get_context_data(**kwargs)
        # query all the things! filter out stuff without a measurement, else this might break
        # the query string later on
        qs = self.project.samples.filter(measurements__isnull=False).prefetch_related('measurements')
        samples = dict()
        for sample in qs:
            samples[sample.pk] = {'sample': sample, 'measurements': sample.measurements.all()}
        ctx['samples'] = samples
        ctx['object'] = self.project
        ctx['form'] = ProjectReportTemplateSelectForm()  # template selection drop down
        ctx['has_templates'] = ReportTemplate.objects.all().count() > 0
        return ctx


class ReportCreatorView(LoginRequiredMixin, TemplateView):
    template_name = 'report_template/template.html'

    require_group = LAB_GROUP_ID

    def get_context_data(self, **kwargs):

        ctx = super(ReportCreatorView, self).get_context_data(**kwargs)

        ctx.update({'commentsColumn': self.request.GET.get('commentsColumn', False),
                    'remarksColumn': self.request.GET.get('remarksColumn', False)})

        sort_key = self.request.GET.get('order_by', '')

        measurement_keys = self.request.GET.get('mkeys', None).split(',')
        measurements = Measurement.objects.filter(pk__in=measurement_keys).order_by(sort_key). \
            prefetch_related('sample', 'sample__contained_in', 'rounds'). \
            values('sample', 'sample__reference', 'sample__contained_in__name', 'sample__name',
                   'finished_at', 'comments', 'pk', 'compliant_result',
                   'sample__sampled_at', 'analysis_result')

        template_object = \
            ReportTemplate.objects.get(pk=self.request.GET.get('report_template', None))

        ctx['measurements'] = measurements

        operator_list = list()
        # pimp up the query dicts from above by looking up additional stuff
        for m in measurements:
            mobject = Measurement.objects.get(pk=m['pk'])
            m['predilution'] = mobject.sample.total_dilution

            # also pull in started at, which is not even a real property but
            # calculated instead thus cannot be retrieved by the database query
            m['started_at'] = mobject.started_at

            # pull in result adjust with predilution
            if mobject.analysis_result is not None:
                m['result'] = round(m['predilution'] * mobject.analysis_result, 2)
                m['analysis_result'] = round(mobject.analysis_result, 2)
            else:  # make sure to avoid key errors on result
                m['result'] = None

            # lookup the number of panelist included in the measurement and the total
            # amount of ites

            m['ite_count'] = mobject.valid_ite_count
            m['panelist_count'] = mobject.unique_panel_count

            # while we're at it, insert the automated remarks
            # non standard compliance wins above all
            m['remark'] = ''
            # measurement without enforced standard compliance (no dz, no blank errors)
            if mobject.standard_identifier <= 0:
                m['remark'] += template_object.not_standard_compliant_remark + '\n'

            # existing result, but below lower detection limit
            if mobject.analysis_result is not None and mobject.analysis_result < template_object.lower_threshold:
                m['remark'] += template_object.lower_threshold_remark + '\n'

            # no ite at all or not enough to give an standard compliant result
            if mobject.analysis_result is None or not mobject.compliant_result:
                m['remark'] += template_object.insufficient_volume_remark + '\n'

            if mobject.sample.supplier is not None:
                m['remark'] += template_object.client_bag_remark + '\n'

            # late analysis
            if mobject.finished_at > (mobject.sample.sampled_at + timedelta(hours=30)):
                m['remark'] += template_object.late_analysis_text

            for r in mobject.rounds.all():
                operator_list.append(r.operator)

        ctx['lab_tech_list'] = map(lambda x: x.first_name[0] + x.last_name[0], set(operator_list))

        project_pk = self.request.GET.get('project', None)
        project = Project.objects.select_related('client', 'contact').filter(id=project_pk). \
            values('contact', 'contact__first_name', 'contact__last_name', 'client', 'reference',
                   'client__zip', 'client__city', 'client__address', 'client__country',
                   'client__client__name', 'name', 'client__phone', 'project_manager__first_name',
                   'project_manager__last_name', 'project_manager').first()

        # via history object, grab creator and time of this project item
        from history.models import HistoryEntry
        from django.contrib.contenttypes.models import ContentType

        # we know at least on entry is around, since someone had to create this stuff, right?
        history = HistoryEntry.objects.filter(content_type=ContentType.objects.get_for_model(Project),
                                              object_id=project_pk).order_by('timestamp').first()

        ctx['created_at'] = history.timestamp
        ctx['created_by'] = '{0}. {1}'.format(self.request.user.first_name[:1],
                                              self.request.user.last_name)

        ctx['created_by_title'] = self.request.user.position

        if project['contact']:
            ctx['contact_person_client'] = '{0}. {1}'.format(project['contact__first_name'][:1],
                                                             project['contact__last_name'])
        else:
            ctx['contact_person_client'] = None

        if project['project_manager']:
            ctx['project_manager'] = '{0}. {1}'.format(project['project_manager__first_name'][:1],
                                                       project['project_manager__last_name'])
        else:
            ctx['project_manager'] = None

        ctx['project'] = project

        # pull in template
        ctx['template'] = template_object
        if template_object.header_logo:
            ctx['header_logo'] = template_object.header_logo.url

        if self.request.user.signature:
            ctx['signature'] = self.request.user.signature.url
        else:
            ctx['signature'] = None

        ctx['header_text'] = template_object.header_text.splitlines()

        return ctx
