# -*- coding: utf-8; -*-
################################################################################
#
#  WuttaFarm --Web app to integrate with and extend farmOS
#  Copyright © 2026 Lance Edgar
#
#  This file is part of WuttaFarm.
#
#  WuttaFarm is free software: you can redistribute it and/or modify it under
#  the terms of the GNU General Public License as published by the Free Software
#  Foundation, either version 3 of the License, or (at your option) any later
#  version.
#
#  WuttaFarm is distributed in the hope that it will be useful, but WITHOUT ANY
#  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
#  A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License along with
#  WuttaFarm.  If not, see <http://www.gnu.org/licenses/>.
#
################################################################################
"""
Importer models targeting farmOS
"""

import datetime
from uuid import UUID

import requests

from wuttasync.importing import Importer


class ToFarmOS(Importer):
    """
    Base class for data importer targeting the farmOS API.
    """

    key = "uuid"
    caches_target = True

    def format_datetime(self, dt):
        """
        Convert a WuttaFarm datetime object to the format required for
        pushing to the farmOS API.
        """
        if dt is None:
            return None
        dt = self.app.localtime(dt)
        return dt.timestamp()

    def normalize_datetime(self, dt):
        """
        Convert a farmOS datetime value to naive UTC used by
        WuttaFarm.

        :param dt: Date/time string value "as-is" from the farmOS API.

        :returns: Equivalent naive UTC ``datetime``
        """
        if dt is None:
            return None
        dt = datetime.datetime.fromisoformat(dt)
        return self.app.make_utc(dt)


class ToFarmOSTaxonomy(ToFarmOS):

    farmos_taxonomy_type = None

    supported_fields = [
        "uuid",
        "name",
        "description",
    ]

    def get_target_objects(self, **kwargs):
        return list(
            self.farmos_client.resource.iterate(
                "taxonomy_term", self.farmos_taxonomy_type
            )
        )

    def get_target_object(self, key):

        # fetch from cache, if applicable
        if self.caches_target:
            return super().get_target_object(key)

        # okay now must fetch via API
        if self.get_keys() != ["uuid"]:
            raise ValueError("must use uuid key for this to work")
        uuid = key[0]

        try:
            result = self.farmos_client.resource.get_id(
                "taxonomy_term", self.farmos_taxonomy_type, str(uuid)
            )
        except requests.HTTPError as exc:
            if exc.response.status_code == 404:
                return None
            raise
        return result["data"]

    def normalize_target_object(self, obj):
        if description := obj["attributes"]["description"]:
            description = description["value"]
        return {
            "uuid": UUID(obj["id"]),
            "name": obj["attributes"]["name"],
            "description": description,
        }

    def get_term_payload(self, source_data):

        attrs = {}
        if "name" in self.fields:
            attrs["name"] = source_data["name"]
        if "description" in self.fields:
            attrs["description"] = {"value": source_data["description"]}

        payload = {"attributes": attrs}
        return payload

    def create_target_object(self, key, source_data):
        if source_data.get("__ignoreme__"):
            return None
        if self.dry_run:
            return source_data

        payload = self.get_term_payload(source_data)
        result = self.farmos_client.resource.send(
            "taxonomy_term", self.farmos_taxonomy_type, payload
        )
        normal = self.normalize_target_object(result["data"])
        normal["_new_object"] = result["data"]
        return normal

    def update_target_object(self, term, source_data, target_data=None):
        if self.dry_run:
            return term

        payload = self.get_term_payload(source_data)
        payload["id"] = str(source_data["uuid"])
        result = self.farmos_client.resource.send(
            "taxonomy_term", self.farmos_taxonomy_type, payload
        )
        return self.normalize_target_object(result["data"])


class ToFarmOSAsset(ToFarmOS):
    """
    Base class for asset data importer targeting the farmOS API.
    """

    farmos_asset_type = None

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.normal = self.app.get_normalizer(self.farmos_client)

    def get_target_objects(self, **kwargs):
        return list(self.farmos_client.asset.iterate(self.farmos_asset_type))

    def get_target_object(self, key):

        # fetch from cache, if applicable
        if self.caches_target:
            return super().get_target_object(key)

        # okay now must fetch via API
        if self.get_keys() != ["uuid"]:
            raise ValueError("must use uuid key for this to work")
        uuid = key[0]

        try:
            asset = self.farmos_client.asset.get_id(self.farmos_asset_type, str(uuid))
        except requests.HTTPError as exc:
            if exc.response.status_code == 404:
                return None
            raise
        return asset["data"]

    def create_target_object(self, key, source_data):
        if source_data.get("__ignoreme__"):
            return None
        if self.dry_run:
            return source_data

        payload = self.get_asset_payload(source_data)
        result = self.farmos_client.asset.send(self.farmos_asset_type, payload)
        normal = self.normalize_target_object(result["data"])
        normal["_new_object"] = result["data"]
        return normal

    def update_target_object(self, asset, source_data, target_data=None):
        if self.dry_run:
            return asset

        payload = self.get_asset_payload(source_data)
        payload["id"] = str(source_data["uuid"])
        result = self.farmos_client.asset.send(self.farmos_asset_type, payload)
        return self.normalize_target_object(result["data"])

    def normalize_target_object(self, asset):
        normal = self.normal.normalize_farmos_asset(asset)
        return {
            "uuid": UUID(normal["uuid"]),
            "asset_name": normal["asset_name"],
            "is_location": normal["is_location"],
            "is_fixed": normal["is_fixed"],
            # nb. this is only used for certain asset types
            "produces_eggs": normal["produces_eggs"],
            "parents": [(p["asset_type"], UUID(p["uuid"])) for p in normal["parents"]],
            "notes": normal["notes"],
            "archived": normal["archived"],
        }

    def get_asset_payload(self, source_data):

        attrs = {}
        if "asset_name" in self.fields:
            attrs["name"] = source_data["asset_name"]
        if "is_location" in self.fields:
            attrs["is_location"] = source_data["is_location"]
        if "is_fixed" in self.fields:
            attrs["is_fixed"] = source_data["is_fixed"]
        if "produces_eggs" in self.fields:
            attrs["produces_eggs"] = source_data["produces_eggs"]
        if "notes" in self.fields:
            attrs["notes"] = {"value": source_data["notes"]}
        if "archived" in self.fields:
            attrs["archived"] = source_data["archived"]

        rels = {}
        if "parents" in self.fields:
            rels["parent"] = {"data": []}
            for asset_type, uuid in source_data["parents"]:
                rels["parent"]["data"].append(
                    {
                        "id": str(uuid),
                        "type": f"asset--{asset_type}",
                    }
                )

        payload = {"attributes": attrs, "relationships": rels}
        return payload


class UnitImporter(ToFarmOSTaxonomy):

    model_title = "Unit"
    farmos_taxonomy_type = "unit"


class AnimalAssetImporter(ToFarmOSAsset):

    model_title = "AnimalAsset"
    farmos_asset_type = "animal"

    supported_fields = [
        "uuid",
        "asset_name",
        "animal_type_uuid",
        "sex",
        "is_sterile",
        "produces_eggs",
        "birthdate",
        "is_location",
        "is_fixed",
        "notes",
        "archived",
    ]

    def normalize_target_object(self, animal):
        data = super().normalize_target_object(animal)
        data.update(
            {
                "animal_type_uuid": UUID(
                    animal["relationships"]["animal_type"]["data"]["id"]
                ),
                "sex": animal["attributes"]["sex"],
                "is_sterile": animal["attributes"]["is_sterile"],
                "birthdate": self.normalize_datetime(animal["attributes"]["birthdate"]),
            }
        )
        return data

    def get_asset_payload(self, source_data):
        payload = super().get_asset_payload(source_data)

        attrs = {}
        if "sex" in self.fields:
            attrs["sex"] = source_data["sex"]
        if "is_sterile" in self.fields:
            attrs["is_sterile"] = source_data["is_sterile"]
        if "birthdate" in self.fields:
            attrs["birthdate"] = self.format_datetime(source_data["birthdate"])

        rels = {}
        if "animal_type_uuid" in self.fields:
            rels["animal_type"] = {
                "data": {
                    "id": str(source_data["animal_type_uuid"]),
                    "type": "taxonomy_term--animal_type",
                }
            }

        payload["attributes"].update(attrs)
        if rels:
            payload.setdefault("relationships", {}).update(rels)

        return payload


class AnimalTypeImporter(ToFarmOSTaxonomy):

    model_title = "AnimalType"
    farmos_taxonomy_type = "animal_type"


class EquipmentTypeImporter(ToFarmOSTaxonomy):

    model_title = "EquipmentType"
    farmos_taxonomy_type = "equipment_type"


class EquipmentAssetImporter(ToFarmOSAsset):

    model_title = "EquipmentAsset"
    farmos_asset_type = "equipment"

    supported_fields = [
        "uuid",
        "asset_name",
        "manufacturer",
        "model",
        "serial_number",
        "equipment_type_uuids",
        "is_location",
        "is_fixed",
        "notes",
        "archived",
    ]

    def normalize_target_object(self, equipment):
        data = super().normalize_target_object(equipment)
        data.update(
            {
                "manufacturer": equipment["attributes"]["manufacturer"],
                "model": equipment["attributes"]["model"],
                "serial_number": equipment["attributes"]["serial_number"],
                "equipment_type_uuids": [
                    UUID(etype["id"])
                    for etype in equipment["relationships"]["equipment_type"]["data"]
                ],
            }
        )
        return data

    def get_asset_payload(self, source_data):
        payload = super().get_asset_payload(source_data)

        attrs = {}
        if "manufacturer" in self.fields:
            attrs["manufacturer"] = source_data["manufacturer"]
        if "model" in self.fields:
            attrs["model"] = source_data["model"]
        if "serial_number" in self.fields:
            attrs["serial_number"] = source_data["serial_number"]

        rels = {}
        if "equipment_type_uuids" in self.fields:
            rels["equipment_type"] = {"data": []}
            for uuid in source_data["equipment_type_uuids"]:
                rels["equipment_type"]["data"].append(
                    {
                        "id": str(uuid),
                        "type": "taxonomy_term--equipment_type",
                    }
                )

        payload["attributes"].update(attrs)
        if rels:
            payload.setdefault("relationships", {}).update(rels)

        return payload


class MaterialTypeImporter(ToFarmOSTaxonomy):

    model_title = "MaterialType"
    farmos_taxonomy_type = "material_type"


class GroupAssetImporter(ToFarmOSAsset):

    model_title = "GroupAsset"
    farmos_asset_type = "group"

    supported_fields = [
        "uuid",
        "asset_name",
        "produces_eggs",
        "notes",
        "archived",
    ]


class LandAssetImporter(ToFarmOSAsset):

    model_title = "LandAsset"
    farmos_asset_type = "land"

    supported_fields = [
        "uuid",
        "asset_name",
        "land_type_id",
        "is_location",
        "is_fixed",
        "notes",
        "archived",
    ]

    def normalize_target_object(self, land):
        data = super().normalize_target_object(land)
        data.update(
            {
                "land_type_id": land["attributes"]["land_type"],
            }
        )
        return data

    def get_asset_payload(self, source_data):
        payload = super().get_asset_payload(source_data)

        attrs = {}
        if "land_type_id" in self.fields:
            attrs["land_type"] = source_data["land_type_id"]

        if attrs:
            payload["attributes"].update(attrs)

        return payload


class PlantTypeImporter(ToFarmOSTaxonomy):

    model_title = "PlantType"
    farmos_taxonomy_type = "plant_type"


class SeasonImporter(ToFarmOSTaxonomy):

    model_title = "Season"
    farmos_taxonomy_type = "season"


class PlantAssetImporter(ToFarmOSAsset):

    model_title = "PlantAsset"
    farmos_asset_type = "plant"

    supported_fields = [
        "uuid",
        "asset_name",
        "plant_type_uuids",
        "season_uuids",
        "notes",
        "archived",
    ]

    def normalize_target_object(self, plant):
        data = super().normalize_target_object(plant)
        data.update(
            {
                "plant_type_uuids": [
                    UUID(p["id"]) for p in plant["relationships"]["plant_type"]["data"]
                ],
                "season_uuids": [
                    UUID(p["id"]) for p in plant["relationships"]["season"]["data"]
                ],
            }
        )
        return data

    def get_asset_payload(self, source_data):
        payload = super().get_asset_payload(source_data)

        attrs = {}
        if "sex" in self.fields:
            attrs["sex"] = source_data["sex"]
        if "is_sterile" in self.fields:
            attrs["is_sterile"] = source_data["is_sterile"]
        if "birthdate" in self.fields:
            attrs["birthdate"] = self.format_datetime(source_data["birthdate"])

        rels = {}
        if "plant_type_uuids" in self.fields:
            rels["plant_type"] = {"data": []}
            for uuid in source_data["plant_type_uuids"]:
                rels["plant_type"]["data"].append(
                    {
                        "id": str(uuid),
                        "type": "taxonomy_term--plant_type",
                    }
                )
        if "season_uuids" in self.fields:
            rels["season"] = {"data": []}
            for uuid in source_data["season_uuids"]:
                rels["season"]["data"].append(
                    {
                        "id": str(uuid),
                        "type": "taxonomy_term--season",
                    }
                )

        payload["attributes"].update(attrs)
        if rels:
            payload.setdefault("relationships", {}).update(rels)

        return payload


class StructureAssetImporter(ToFarmOSAsset):

    model_title = "StructureAsset"
    farmos_asset_type = "structure"

    supported_fields = [
        "uuid",
        "asset_name",
        "structure_type_id",
        "is_location",
        "is_fixed",
        "notes",
        "archived",
    ]

    def normalize_target_object(self, structure):
        data = super().normalize_target_object(structure)
        data.update(
            {
                "structure_type_id": structure["attributes"]["structure_type"],
            }
        )
        return data

    def get_asset_payload(self, source_data):
        payload = super().get_asset_payload(source_data)

        attrs = {}
        if "structure_type_id" in self.fields:
            attrs["structure_type"] = source_data["structure_type_id"]

        if attrs:
            payload["attributes"].update(attrs)

        return payload


class WaterAssetImporter(ToFarmOSAsset):

    model_title = "WaterAsset"
    farmos_asset_type = "water"

    supported_fields = [
        "uuid",
        "asset_name",
        "is_location",
        "is_fixed",
        "notes",
        "archived",
    ]


##############################
# quantity importers
##############################


class ToFarmOSQuantity(ToFarmOS):
    """
    Base class for quantity data importer targeting the farmOS API.
    """

    farmos_quantity_type = None

    supported_fields = [
        "uuid",
        "measure",
        "value_numerator",
        "value_denominator",
        "label",
        "quantity_type_uuid",
        "unit_uuid",
    ]

    def get_target_objects(self, **kwargs):
        return list(
            self.farmos_client.resource.iterate("quantity", self.farmos_quantity_type)
        )

    def get_target_object(self, key):

        # fetch from cache, if applicable
        if self.caches_target:
            return super().get_target_object(key)

        # okay now must fetch via API
        if self.get_keys() != ["uuid"]:
            raise ValueError("must use uuid key for this to work")
        uuid = key[0]

        try:
            qty = self.farmos_client.resource.get_id(
                "quantity", self.farmos_quantity_type, str(uuid)
            )
        except requests.HTTPError as exc:
            if exc.response.status_code == 404:
                return None
            raise
        return qty["data"]

    def create_target_object(self, key, source_data):
        if source_data.get("__ignoreme__"):
            return None
        if self.dry_run:
            return source_data

        payload = self.get_quantity_payload(source_data)
        result = self.farmos_client.resource.send(
            "quantity", self.farmos_quantity_type, payload
        )
        normal = self.normalize_target_object(result["data"])
        normal["_new_object"] = result["data"]
        return normal

    def update_target_object(self, quantity, source_data, target_data=None):
        if self.dry_run:
            return quantity

        payload = self.get_quantity_payload(source_data)
        payload["id"] = str(source_data["uuid"])
        result = self.farmos_client.resource.send(
            "quantity", self.farmos_quantity_type, payload
        )
        return self.normalize_target_object(result["data"])

    def normalize_target_object(self, qty):

        result = {
            "uuid": UUID(qty["id"]),
            "measure": qty["attributes"]["measure"],
            "value_numerator": qty["attributes"]["value"]["numerator"],
            "value_denominator": qty["attributes"]["value"]["denominator"],
            "label": qty["attributes"]["label"],
            "quantity_type_uuid": UUID(
                qty["relationships"]["quantity_type"]["data"]["id"]
            ),
            "unit_uuid": None,
        }

        if unit := qty["relationships"]["units"]["data"]:
            result["unit_uuid"] = UUID(unit["id"])

        return result

    def get_quantity_payload(self, source_data):

        attrs = {}
        if "measure" in self.fields:
            attrs["measure"] = source_data["measure"]
        if "value_numerator" in self.fields and "value_denominator" in self.fields:
            attrs["value"] = {
                "numerator": source_data["value_numerator"],
                "denominator": source_data["value_denominator"],
            }
        if "label" in self.fields:
            attrs["label"] = source_data["label"]

        rels = {}
        if "quantity_type_uuid" in self.fields:
            rels["quantity_type"] = {
                "data": {
                    "id": str(source_data["quantity_type_uuid"]),
                    "type": "quantity_type--quantity_type",
                }
            }
        if "unit_uuid" in self.fields:
            rels["units"] = {
                "data": {
                    "id": str(source_data["unit_uuid"]),
                    "type": "taxonomy_term--unit",
                }
            }

        payload = {"attributes": attrs, "relationships": rels}

        return payload


class MaterialQuantityImporter(ToFarmOSQuantity):

    model_title = "MaterialQuantity"
    farmos_quantity_type = "material"

    def get_supported_fields(self):
        fields = list(super().get_supported_fields())
        fields.extend(
            [
                "material_types",
            ]
        )
        return fields

    def normalize_target_object(self, quantity):
        data = super().normalize_target_object(quantity)

        if "material_types" in self.fields:
            data["material_types"] = [
                UUID(mtype["id"])
                for mtype in quantity["relationships"]["material_type"]["data"]
            ]

        return data

    def get_quantity_payload(self, source_data):
        payload = super().get_quantity_payload(source_data)

        rels = {}
        if "material_types" in self.fields:
            rels["material_type"] = {"data": []}
            for uuid in source_data["material_types"]:
                rels["material_type"]["data"].append(
                    {
                        "id": str(uuid),
                        "type": "taxonomy_term--material_type",
                    }
                )

        payload.setdefault("relationships", {}).update(rels)
        return payload


class StandardQuantityImporter(ToFarmOSQuantity):

    model_title = "StandardQuantity"
    farmos_quantity_type = "standard"


##############################
# log importers
##############################


class ToFarmOSLog(ToFarmOS):
    """
    Base class for log data importer targeting the farmOS API.
    """

    farmos_log_type = None

    supported_fields = [
        "uuid",
        "name",
        "timestamp",
        "is_movement",
        "is_group_assignment",
        "status",
        "notes",
        "quick",
        "assets",
        "locations",
        "groups",
        "quantities",
    ]

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.normal = self.app.get_normalizer(self.farmos_client)

    def get_target_objects(self, **kwargs):
        return list(self.farmos_client.log.iterate(self.farmos_log_type))

    def get_target_object(self, key):

        # fetch from cache, if applicable
        if self.caches_target:
            return super().get_target_object(key)

        # okay now must fetch via API
        if self.get_keys() != ["uuid"]:
            raise ValueError("must use uuid key for this to work")
        uuid = key[0]

        try:
            log = self.farmos_client.log.get_id(self.farmos_log_type, str(uuid))
        except requests.HTTPError as exc:
            if exc.response.status_code == 404:
                return None
            raise
        return log["data"]

    def create_target_object(self, key, source_data):
        if source_data.get("__ignoreme__"):
            return None
        if self.dry_run:
            return source_data

        payload = self.get_log_payload(source_data)
        result = self.farmos_client.log.send(self.farmos_log_type, payload)
        normal = self.normalize_target_object(result["data"])
        normal["_new_object"] = result["data"]
        return normal

    def update_target_object(self, asset, source_data, target_data=None):
        if self.dry_run:
            return asset

        payload = self.get_log_payload(source_data)
        payload["id"] = str(source_data["uuid"])
        result = self.farmos_client.log.send(self.farmos_log_type, payload)
        return self.normalize_target_object(result["data"])

    def normalize_target_object(self, log):
        normal = self.normal.normalize_farmos_log(log)
        return {
            "uuid": UUID(normal["uuid"]),
            "name": normal["name"],
            "timestamp": self.app.make_utc(normal["timestamp"]),
            "is_movement": normal["is_movement"],
            "is_group_assignment": normal["is_group_assignment"],
            "status": normal["status"],
            "notes": normal["notes"],
            "quick": normal["quick"],
            "assets": [(a["asset_type"], UUID(a["uuid"])) for a in normal["assets"]],
            "locations": [
                (l["asset_type"], UUID(l["uuid"])) for l in normal["locations"]
            ],
            "groups": [(g["asset_type"], UUID(g["uuid"])) for g in normal["groups"]],
            "quantities": [UUID(uuid) for uuid in normal["quantity_uuids"]],
        }

    def get_log_payload(self, source_data):

        attrs = {}
        if "name" in self.fields:
            attrs["name"] = source_data["name"]
        if "timestamp" in self.fields:
            attrs["timestamp"] = self.format_datetime(source_data["timestamp"])
        if "is_movement" in self.fields:
            attrs["is_movement"] = source_data["is_movement"]
        if "is_group_assignment" in self.fields:
            attrs["is_group_assignment"] = source_data["is_group_assignment"]
        if "status" in self.fields:
            attrs["status"] = source_data["status"]
        if "notes" in self.fields:
            attrs["notes"] = {"value": source_data["notes"]}
        if "quick" in self.fields:
            attrs["quick"] = source_data["quick"]

        rels = {}
        if "assets" in self.fields:
            assets = []
            for asset_type, uuid in source_data["assets"]:
                assets.append(
                    {
                        "type": f"asset--{asset_type}",
                        "id": str(uuid),
                    }
                )
            rels["asset"] = {"data": assets}
        if "locations" in self.fields:
            locations = []
            for asset_type, uuid in source_data["locations"]:
                locations.append(
                    {
                        "type": f"asset--{asset_type}",
                        "id": str(uuid),
                    }
                )
            rels["location"] = {"data": locations}
        if "groups" in self.fields:
            groups = []
            for asset_type, uuid in source_data["groups"]:
                groups.append(
                    {
                        "type": f"asset--{asset_type}",
                        "id": str(uuid),
                    }
                )
            rels["group"] = {"data": groups}
        if "quantities" in self.fields:
            quantities = []
            for uuid in source_data["quantities"]:
                quantities.append(
                    {
                        # TODO: support other quantity types
                        "type": "quantity--standard",
                        "id": str(uuid),
                    }
                )
            rels["quantity"] = {"data": quantities}

        payload = {"attributes": attrs, "relationships": rels}
        return payload


class ActivityLogImporter(ToFarmOSLog):

    model_title = "ActivityLog"
    farmos_log_type = "activity"


class HarvestLogImporter(ToFarmOSLog):

    model_title = "HarvestLog"
    farmos_log_type = "harvest"


class MedicalLogImporter(ToFarmOSLog):

    model_title = "MedicalLog"
    farmos_log_type = "medical"

    def get_supported_fields(self):
        fields = list(super().get_supported_fields())
        fields.extend(
            [
                "vet",
            ]
        )
        return fields

    def normalize_target_object(self, log):
        data = super().normalize_target_object(log)
        data.update(
            {
                "vet": log["attributes"]["vet"],
            }
        )
        return data

    def get_log_payload(self, source_data):
        payload = super().get_log_payload(source_data)

        if "vet" in self.fields:
            payload["attributes"]["vet"] = source_data["vet"]

        return payload


class ObservationLogImporter(ToFarmOSLog):

    model_title = "ObservationLog"
    farmos_log_type = "observation"


class SeedingLogImporter(ToFarmOSLog):

    model_title = "SeedingLog"
    farmos_log_type = "seeding"

    def get_supported_fields(self):
        fields = list(super().get_supported_fields())
        fields.extend(
            [
                "source",
                "purchase_date",
                "lot_number",
            ]
        )
        return fields

    def normalize_target_object(self, log):
        data = super().normalize_target_object(log)
        data.update(
            {
                "source": log["attributes"]["source"],
                "purchase_date": self.normalize_datetime(
                    log["attributes"]["purchase_date"]
                ),
                "lot_number": log["attributes"]["lot_number"],
            }
        )
        return data

    def get_log_payload(self, source_data):
        payload = super().get_log_payload(source_data)

        attrs = {}
        if "source" in self.fields:
            attrs["source"] = source_data["source"]
        if "purchase_date" in self.fields:
            attrs["purchase_date"] = self.format_datetime(source_data["purchase_date"])
        if "lot_number" in self.fields:
            attrs["lot_number"] = source_data["lot_number"]

        if attrs:
            payload["attributes"].update(attrs)
        return payload
