import random
import factory.fuzzy
import datetime
import pytz
from grandchallenge.annotations.models import (
    AbstractImageAnnotationModel,
    AbstractNamedImageAnnotationModel,
    ETDRSGridAnnotation,
    MeasurementAnnotation,
    BooleanClassificationAnnotation,
    IntegerClassificationAnnotation,
    CoordinateListAnnotation,
    PolygonAnnotationSet,
    SinglePolygonAnnotation,
    LandmarkAnnotationSet,
    SingleLandmarkAnnotation,
)
from tests.cases_tests.factories import ImageFactory
from tests.factories import UserFactory


def create_fake_coordinate_list(size=10):
    c_list = []
    for i in range(size):
        c_list.append(
            [random.uniform(0.0, 1000.0), random.uniform(0.0, 1000.0)]
        )
    return c_list


class DefaultImageAnnotationModelFactory(factory.DjangoModelFactory):
    class Meta:
        model = AbstractImageAnnotationModel
        abstract = True

    image = factory.SubFactory(ImageFactory)
    grader = factory.SubFactory(UserFactory)
    created = factory.fuzzy.FuzzyDateTime(
        datetime.datetime(1950, 1, 1, 0, 0, 0, 0, pytz.UTC)
    )


class ETDRSGridAnnotationFactory(DefaultImageAnnotationModelFactory):
    class Meta:
        model = ETDRSGridAnnotation

    fovea = [random.uniform(0.0, 50.0), random.uniform(0.0, 50.0)]
    optic_disk = [random.uniform(0.0, 50.0), random.uniform(0.0, 50.0)]


class MeasurementAnnotationFactory(DefaultImageAnnotationModelFactory):
    class Meta:
        model = MeasurementAnnotation

    start_voxel = [random.uniform(0.0, 50.0), random.uniform(0.0, 50.0)]
    end_voxel = [random.uniform(0.0, 50.0), random.uniform(0.0, 50.0)]


class DefaultNamedImageAnnotationModelFactory(
    DefaultImageAnnotationModelFactory
):
    class Meta:
        model = AbstractNamedImageAnnotationModel
        abstract = True

    name = factory.fuzzy.FuzzyText()


class BooleanClassificationAnnotationFactory(
    DefaultNamedImageAnnotationModelFactory
):
    class Meta:
        model = BooleanClassificationAnnotation

    value = factory.fuzzy.FuzzyChoice([True, False])


class IntegerClassificationAnnotationFactory(
    DefaultNamedImageAnnotationModelFactory
):
    class Meta:
        model = IntegerClassificationAnnotation

    value = factory.fuzzy.FuzzyInteger(1000)


class CoordinateListAnnotationFactory(DefaultNamedImageAnnotationModelFactory):
    class Meta:
        model = CoordinateListAnnotation

    value = create_fake_coordinate_list()


class PolygonAnnotationSetFactory(DefaultNamedImageAnnotationModelFactory):
    class Meta:
        model = PolygonAnnotationSet


class SinglePolygonAnnotationFactory(factory.DjangoModelFactory):
    class Meta:
        model = SinglePolygonAnnotation

    annotation_set = factory.SubFactory(PolygonAnnotationSetFactory)

    value = create_fake_coordinate_list()


class LandmarkAnnotationSetFactory(factory.DjangoModelFactory):
    class Meta:
        model = LandmarkAnnotationSet

    grader = factory.SubFactory(UserFactory)
    created = factory.fuzzy.FuzzyDateTime(
        datetime.datetime(1950, 1, 1, 0, 0, 0, 0, pytz.UTC)
    )


class SingleLandmarkAnnotationFactory(factory.DjangoModelFactory):
    class Meta:
        model = SingleLandmarkAnnotation

    image = factory.SubFactory(ImageFactory)
    annotation_set = factory.SubFactory(LandmarkAnnotationSetFactory)

    landmarks = create_fake_coordinate_list()


def create_batch_landmarks():
    landmark_annotation_set = LandmarkAnnotationSet()
    landmark_annotations = []
    for i in range(3):
        landmark_annotations.append(
            SingleLandmarkAnnotationFactory(
                registration=landmark_annotation_set
            )
        )

    return landmark_annotation_set, landmark_annotations

@@ -56,16 +56,17 @@
 rt pytz%0A
+%0A
 from gra
@@ -547,55 +547,306 @@
 y%0A%0A%0A
-def create_fake_coordinate_list(size=10)
+class FuzzyFloatCoordinatesList(factory.fuzzy.BaseFuzzyAttribute):%0A    def __init__(self, size=None):%0A        self.size = size%0A%0A    def fuzz(self):%0A        if self.size is None:%0A            size = factory.fuzzy.random.randgen.randint(1, 30)%0A        else
 :%0A    
+ 
-c
+       size = self.size%0A%0A        fuzzy
 _lis
@@ -848,24 +848,28 @@
 y_list = %5B%5D%0A
+    
     for i in
@@ -890,17 +890,25 @@
         
-c
+    fuzzy
 _list.ap
@@ -929,77 +929,192 @@
     
-%5Brandom.uniform(0.0, 1000.0), random.uniform(0.0, 1000.0)%5D%0A        )%0A
+    %5B%0A                    factory.fuzzy.random.randgen.uniform(0.0, 1000.0),%0A                    factory.fuzzy.random.randgen.uniform(0.0, 1000.0),%0A                %5D%0A            )%0A    
     
@@ -1120,17 +1120,21 @@
  return 
-c
+fuzzy
 _list%0A%0A%0A
@@ -2810,37 +2810,35 @@
     value = 
-create_fake_c
+FuzzyFloatC
 oordinate_li
@@ -2826,34 +2826,34 @@
 yFloatCoordinate
-_l
+sL
 ist()%0A%0A%0Aclass Po
@@ -3180,29 +3180,27 @@
 value = 
-create_fake_c
+FuzzyFloatC
 oordinat
@@ -3192,34 +3192,34 @@
 yFloatCoordinate
-_l
+sL
 ist()%0A%0A%0Aclass La
@@ -3746,21 +3746,19 @@
 s = 
-create_fake_c
+FuzzyFloatC
 oord
@@ -3762,18 +3762,18 @@
 ordinate
-_l
+sL
 ist()%0A%0A%0A

Add custom Fuzzy field for annotation factories