# -*- 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 ToFarmOSAsset(ToFarmOS):
    """
    Base class for asset data importer targeting the farmOS API.
    """

    farmos_asset_type = None

    def get_target_objects(self, **kwargs):
        assets = self.farmos_client.asset.get(self.farmos_asset_type)
        return assets["data"]

    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):

        if notes := asset["attributes"]["notes"]:
            notes = notes["value"]

        return {
            "uuid": UUID(asset["id"]),
            "asset_name": asset["attributes"]["name"],
            "is_location": asset["attributes"]["is_location"],
            "is_fixed": asset["attributes"]["is_fixed"],
            "notes": notes,
            "archived": asset["attributes"]["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 "notes" in self.fields:
            attrs["notes"] = {"value": source_data["notes"]}
        if "archived" in self.fields:
            attrs["archived"] = source_data["archived"]

        payload = {"attributes": attrs}

        return payload


class AnimalAssetImporter(ToFarmOSAsset):

    model_title = "AnimalAsset"
    farmos_asset_type = "animal"

    supported_fields = [
        "uuid",
        "asset_name",
        "animal_type_uuid",
        "sex",
        "is_sterile",
        "birthdate",
        "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(ToFarmOS):

    model_title = "AnimalType"

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

    def get_target_objects(self, **kwargs):
        result = self.farmos_client.resource.get("taxonomy_term", "animal_type")
        return result["data"]

    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", "animal_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):
        return {
            "uuid": UUID(obj["id"]),
            "name": obj["attributes"]["name"],
        }

    def get_type_payload(self, source_data):
        return {
            "attributes": {
                "name": source_data["name"],
            }
        }

    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_type_payload(source_data)
        result = self.farmos_client.resource.send(
            "taxonomy_term", "animal_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_type_payload(source_data)
        payload["id"] = str(source_data["uuid"])
        result = self.farmos_client.resource.send(
            "taxonomy_term", "animal_type", payload
        )
        return self.normalize_target_object(result["data"])


class GroupAssetImporter(ToFarmOSAsset):

    model_title = "GroupAsset"
    farmos_asset_type = "group"

    supported_fields = [
        "uuid",
        "asset_name",
        "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 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
