import json

from birds.models import Bird, BirdSightingEntry
from django import forms


class BirdSightingsWidget(forms.Widget):
    template_name = "birds/bird_sightings_widget.html"

    class Media:
        js = ("birds/bird_sightings.js",)

    def value_from_datadict(self, data, files, name):
        bird_ids = data.getlist(f"{name}_bird_id")
        quantities = data.getlist(f"{name}_quantity")
        notes = data.getlist(f"{name}_sighting_notes")
        return {
            "bird_id": bird_ids,
            "quantity": quantities,
            "sighting_notes": notes,
        }

    def get_context(self, name, value, attrs):
        context = super().get_context(name, value, attrs)
        sightings = []
        if value:
            if isinstance(value, str):
                try:
                    value = json.loads(value)
                except (json.JSONDecodeError, TypeError):
                    value = []
            for item in (value or []):
                if isinstance(item, dict):
                    sightings.append(item)
                elif isinstance(item, BirdSightingEntry):
                    sightings.append(item.asdict)
        context["widget"]["sightings"] = sightings
        context["widget"]["birds"] = Bird.objects.all().order_by("common_name")
        return context


class BirdSightingsField(forms.Field):
    widget = BirdSightingsWidget

    def clean(self, value):
        if not value:
            return None
        result = []
        bird_ids = value.get("bird_id", []) if isinstance(value, dict) else []
        quantities = value.get("quantity", []) if isinstance(value, dict) else []
        notes_list = (
            value.get("sighting_notes", []) if isinstance(value, dict) else []
        )

        if isinstance(bird_ids, list):
            for i, bird_id in enumerate(bird_ids):
                if not bird_id:
                    continue
                try:
                    bird_id = int(bird_id)
                    quantity = int(quantities[i]) if i < len(quantities) else 1
                except (ValueError, TypeError, IndexError):
                    continue
                note = notes_list[i] if i < len(notes_list) else ""
                entry = BirdSightingEntry(
                    bird_id=bird_id,
                    quantity=quantity,
                    sighting_notes=note or None,
                )
                result.append(entry.asdict)
        elif bird_ids:
            try:
                bird_id = int(bird_ids)
                quantity = int(quantities) if quantities else 1
            except (ValueError, TypeError):
                raise forms.ValidationError("Invalid bird sighting data")
            note = notes_list if notes_list else ""
            entry = BirdSightingEntry(
                bird_id=bird_id,
                quantity=quantity,
                sighting_notes=note or None,
            )
            result.append(entry.asdict)

        return result if result else None
