import json
from typing import Any, Mapping

from django import forms
from django.core.files.uploadedfile import UploadedFile
from django.forms.renderers import BaseRenderer
from django.utils.datastructures import MultiValueDict
from django.utils.safestring import SafeString


class JSONTableWidget(forms.Widget):
    template_name = "json_table_widget.html"

    def format_value(self, value: str | dict[str, Any]) -> str | dict[str, Any]:  # type: ignore [override]
        if isinstance(value, dict):
            return value
        try:
            if isinstance(value, str):
                value = json.loads(value)
        except json.JSONDecodeError:
            value = {}
        return value

    def render(
        self,
        name: str,
        value: str | dict[str, Any],
        attrs: dict[str, Any] | None = None,
        renderer: BaseRenderer | None = None,
    ) -> SafeString:
        value = self.format_value(value)
        return super().render(name, value, attrs, renderer)

    def value_from_datadict(
        self, data: Mapping[str, Any], files: MultiValueDict[str, UploadedFile], name: str
    ) -> str | None:
        json_data = {}

        try:
            keys = data.getlist(f"{name}_key")  # type: ignore [attr-defined]
            values = data.getlist(f"{name}_value")  # type: ignore [attr-defined]
            for key, value in zip(keys, values, strict=True):
                if key.strip():
                    try:
                        json_data[key] = json.loads(value)
                    except (json.JSONDecodeError, ValueError):
                        json_data[key] = value
        except TypeError:
            pass

        return None if not json_data else json.dumps(json_data)
