from rest_framework import serializers

from clients.models import Client, ContactPerson, ClientOffice, ClientCategory
from panelists.models import Panelist
from bags.models import Bag, BagMaterial
from projects.models import Project
from referencegases.models import ReferenceGas
from samples.models import Sample
from devices.models import Olfactometer, Calibration
from users.models import WinoseUser
from history.models import HistoryEntry
from measurements.models import Measurement, METHOD_KEYS
from .utils import DOBWithAgeSerializer, ChoiceFieldVerbose, RelatedFieldNull, MappedBooleanField
from report_template.models import ReportTemplate
from wnsq.base_settings import TABLE_DATETIME_FORMAT, TABLE_DATE_FORMAT


class ReportTemplateSerializer(serializers.ModelSerializer):
    class Meta:
        model = ReportTemplate
        fields = ['id', 'name']


class PanelistsSerializerWeb(serializers.ModelSerializer):
    date_of_birth = DOBWithAgeSerializer()
    gender = ChoiceFieldVerbose(choice_list=Panelist.GENDERS)
    qualified = MappedBooleanField(true_label='\N{CHECK MARK}', false_label='\N{BALLOT X}')

    class Meta:
        model = Panelist
        fields = ['id', 'qualified', 'first_name', 'last_name',
                  'gender', 'date_of_birth', 'city', 'shorthand']


# ctrl sw does not get the fancier bools since this makes ser/deser more tricky
class PanelistsSerializer(serializers.ModelSerializer):
    date_of_birth = DOBWithAgeSerializer()
    gender = ChoiceFieldVerbose(choice_list=Panelist.GENDERS)
    qualified = serializers.BooleanField()

    class Meta:
        model = Panelist
        fields = ['id', 'qualified', 'first_name', 'last_name',
                  'gender', 'date_of_birth', 'city', 'shorthand']


class BagsSerializer(serializers.ModelSerializer):
    material = serializers.RelatedField(many=False)
    manufactured_at = serializers.DateField(format=TABLE_DATE_FORMAT)

    class Meta:
        model = Bag
        fields = ['id', 'name', 'manufactured_at', 'material']


class ContactPersonsSerializer(serializers.ModelSerializer):
    class Meta:
        model = ContactPerson
        fields = ['id', 'first_name', 'last_name', 'title']


class ClientOfficesSerializer(serializers.ModelSerializer):
    client = serializers.RelatedField(many=False)
    contact = RelatedFieldNull(many=False)

    class Meta:
        model = ClientOffice
        fields = ['id', 'city', 'client', 'contact']


class ClientsSerializer(serializers.ModelSerializer):
    category = serializers.RelatedField(many=False)

    class Meta:
        model = Client
        fields = ('id', 'name', 'country', 'city', 'category', 'reference')
        depth = 1


class ProjectsSerializer(serializers.ModelSerializer):
    client = serializers.RelatedField(many=False)

    class Meta:
        model = Project
        fields = ('id', 'name', 'reference', 'client',)


class OdourSamplesSerializer(serializers.ModelSerializer):
    contained_in = serializers.RelatedField(many=False)
    project = serializers.RelatedField(many=False)

    class Meta:
        model = Sample
        fields = ['id', 'project', 'name', 'contained_in']


class ReferenceSamplesSerializer(serializers.ModelSerializer):
    contained_in = serializers.RelatedField(many=False)
    cylinder = serializers.RelatedField(many=False)

    class Meta:
        model = Sample
        fields = ['id', 'name', 'contained_in', 'cylinder']


class AllSamplesSerializer(serializers.ModelSerializer):
    # cylinder = serializers.RelatedField(many=False)
    cylinder = RelatedFieldNull(many=False)
    contained_in = serializers.RelatedField(many=False)
    project = RelatedFieldNull(many=False)
    total_dilution = serializers.Field()

    class Meta:
        model = Sample
        fields = ['id', 'name', 'contained_in', 'project', 'cylinder', 'total_dilution']


class SamplesSerializerControlSW(serializers.ModelSerializer):
    cylinder = serializers.RelatedField(many=False)
    contained_in = serializers.RelatedField(many=False)
    project = serializers.RelatedField(many=False)
    total_dilution = serializers.FloatField()
    concentration = serializers.FloatField()

    class Meta:
        model = Sample
        fields = ['id', 'name', 'contained_in', 'project',
                  'cylinder', 'total_dilution', 'concentration']


from referencegases.models import REF_GAS_TYPES


class ReferenceGasesSerializer(serializers.ModelSerializer):
    substance = ChoiceFieldVerbose(choice_list=REF_GAS_TYPES)

    class Meta:
        model = ReferenceGas
        fields = ['id', 'name', 'number', 'substance']


class WinoseUsersSerializer(serializers.ModelSerializer):
    from users.models import USERGROUP_CHOICES

    is_superuser = MappedBooleanField(true_label='\N{CHECK MARK}', false_label='\N{BALLOT X}')

    user_group = ChoiceFieldVerbose(choice_list=USERGROUP_CHOICES)

    class Meta:
        model = WinoseUser
        fields = ['id', 'username', 'first_name', 'last_name', 'is_superuser', 'last_login', 'user_group']


class OlfactometersSerializer(serializers.ModelSerializer):
    class Meta:
        model = Olfactometer
        fields = ['id', 'name', 'serial_no', 'inventory_number']


class ClientCategoriesSerializer(serializers.ModelSerializer):
    class Meta:
        model = ClientCategory
        fields = ['id', 'name']


class BagMaterialsSerializer(serializers.ModelSerializer):
    class Meta:
        model = BagMaterial
        fields = ['id', 'name']


class MeasurementsSerializer(serializers.ModelSerializer):
    sample = serializers.RelatedField(many=False)
    used_method = ChoiceFieldVerbose(choice_list=METHOD_KEYS)
    finished_at = serializers.DateTimeField(format=TABLE_DATETIME_FORMAT)

    class Meta:
        model = Measurement
        fields = ['id', 'sample', 'used_method', 'finished_at']


class CalibrationsSerializer(serializers.ModelSerializer):
    class Meta:
        model = Calibration
        fields = ['id', 'created_for', 'valid_to']


class HistoryEntrySerializer(serializers.ModelSerializer):
    who = serializers.RelatedField(many=False)
    timestamp = serializers.DateTimeField(format='%d.%b.%y / %H:%M %Z')

    class Meta:
        model = HistoryEntry
        fields = ['old_value', 'new_value', 'field_name', 'timestamp', 'who']


from measurements.models import MeasurementRound, SingleRoundResult


class MeasurementRoundSerializer(serializers.ModelSerializer):
    # measurement = serializers.PrimaryKeyRelatedField(required=False)
    class Meta:
        model = MeasurementRound
        exclude = ['measurement']


class RoundSingleResultSerializer(serializers.ModelSerializer):
    class Meta:
        model = SingleRoundResult
        exclude = ['round']


class MeasurementSerializerWithVerboseMethod(serializers.ModelSerializer):
    started_at = serializers.Field()
    used_method = ChoiceFieldVerbose(choice_list=METHOD_KEYS)

    class Meta:
        model = Measurement


class MeasurementSerializer(serializers.ModelSerializer):
    class Meta:
        model = Measurement


class FullRoundSerializer(serializers.ModelSerializer):
    results = RoundSingleResultSerializer(many=True)

    class Meta:
        model = MeasurementRound


# used during put, updating existing parts of a measurement
class MeasurementFullSerializer(serializers.ModelSerializer):
    rounds = FullRoundSerializer(many=True)  # serialize the whole thing
    started_at = serializers.Field()

    class Meta:
        model = Measurement

    def save(self, **kwargs):
        from django.db import transaction

        try:
            # awful slow on sqlite without doing it as a transaction, since
            # it cascades down to rounds and single results and stuff...
            transaction.set_autocommit(False)
            super(MeasurementFullSerializer, self).save(**kwargs)
            transaction.commit()
            transaction.set_autocommit(True)
        except:
            raise  # throw stuff further up