# -*- 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/>.
#
################################################################################
"""
WuttaFarm → farmOS data export
"""

from oauthlib.oauth2 import BackendApplicationClient
from requests_oauthlib import OAuth2Session

from wuttasync.importing import ImportHandler, FromWuttaHandler, FromWutta, Orientation

from wuttafarm.db import model
from wuttafarm.farmos import importing as farmos_importing


class FromWuttaFarmHandler(FromWuttaHandler):
    """
    Base class for import handler targeting WuttaFarm
    """

    source_key = "wuttafarm"


class ToFarmOSHandler(ImportHandler):
    """
    Base class for export handlers using CSV file(s) as data target.
    """

    target_key = "farmos"
    generic_target_title = "farmOS"

    # TODO: a lot of duplication to cleanup here; see FromFarmOSHandler

    def begin_target_transaction(self, client=None):
        """
        Establish the farmOS API client.
        """
        if client:
            self.farmos_client = client
        else:
            token = self.get_farmos_oauth2_token()
            self.farmos_client = self.app.get_farmos_client(token=token)
        self.farmos_4x = self.app.is_farmos_4x(self.farmos_client)

    def get_farmos_oauth2_token(self):

        client_id = self.config.get(
            "farmos.oauth2.importing.client_id", default="wuttafarm"
        )
        client_secret = self.config.require("farmos.oauth2.importing.client_secret")
        scope = self.config.get("farmos.oauth2.importing.scope", default="farm_manager")

        client = BackendApplicationClient(client_id=client_id)
        oauth = OAuth2Session(client=client)

        return oauth.fetch_token(
            token_url=self.app.get_farmos_url("/oauth/token"),
            include_client_id=True,
            client_secret=client_secret,
            scope=scope,
        )

    def get_importer_kwargs(self, key, **kwargs):
        kwargs = super().get_importer_kwargs(key, **kwargs)
        kwargs["farmos_client"] = self.farmos_client
        kwargs["farmos_4x"] = self.farmos_4x
        return kwargs


class FromWuttaFarmToFarmOS(FromWuttaFarmHandler, ToFarmOSHandler):
    """
    Handler for WuttaFarm → farmOS API export.
    """

    orientation = Orientation.EXPORT

    def define_importers(self):
        """ """
        importers = super().define_importers()
        importers["LandAsset"] = LandAssetImporter
        importers["StructureAsset"] = StructureAssetImporter
        importers["WaterAsset"] = WaterAssetImporter
        importers["EquipmentType"] = EquipmentTypeImporter
        importers["EquipmentAsset"] = EquipmentAssetImporter
        importers["AnimalType"] = AnimalTypeImporter
        importers["AnimalAsset"] = AnimalAssetImporter
        importers["GroupAsset"] = GroupAssetImporter
        importers["PlantType"] = PlantTypeImporter
        importers["Season"] = SeasonImporter
        importers["PlantAsset"] = PlantAssetImporter
        importers["Unit"] = UnitImporter
        importers["MaterialType"] = MaterialTypeImporter
        importers["MaterialQuantity"] = MaterialQuantityImporter
        importers["StandardQuantity"] = StandardQuantityImporter
        importers["ActivityLog"] = ActivityLogImporter
        importers["HarvestLog"] = HarvestLogImporter
        importers["MedicalLog"] = MedicalLogImporter
        importers["ObservationLog"] = ObservationLogImporter
        importers["SeedingLog"] = SeedingLogImporter
        return importers


class FromWuttaFarm(FromWutta):

    drupal_internal_id_field = "drupal_internal__id"

    def create_target_object(self, key, source_data):
        obj = super().create_target_object(key, source_data)
        if obj is None:
            return None

        if not self.dry_run:

            # set farmOS, Drupal key fields in WuttaFarm
            api_object = obj["_new_object"]
            wf_object = source_data["_src_object"]
            wf_object.farmos_uuid = obj["uuid"]
            wf_object.drupal_id = api_object["attributes"][
                self.drupal_internal_id_field
            ]

        return obj


class FromWuttaFarmAsset(FromWuttaFarm):
    """
    Base class for WuttaFarm → farmOS API asset exporters
    """

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

    def normalize_source_object(self, asset):
        return {
            "uuid": asset.farmos_uuid or self.app.make_true_uuid(),
            "asset_name": asset.asset_name,
            "is_location": asset.is_location,
            "is_fixed": asset.is_fixed,
            "parents": [(p.asset_type, p.farmos_uuid) for p in asset.parents],
            "notes": asset.notes,
            "archived": asset.archived,
            "_src_object": asset,
        }


class AnimalAssetImporter(
    FromWuttaFarmAsset, farmos_importing.model.AnimalAssetImporter
):
    """
    WuttaFarm → farmOS API exporter for Animal Assets
    """

    source_model_class = model.AnimalAsset

    def get_supported_fields(self):
        fields = list(super().get_supported_fields())
        fields.extend(
            [
                "animal_type_uuid",
                "sex",
                "is_sterile",
                "produces_eggs",
                "birthdate",
            ]
        )
        return fields

    def normalize_source_object(self, animal):
        data = super().normalize_source_object(animal)
        data.update(
            {
                "animal_type_uuid": animal.animal_type.farmos_uuid,
                "sex": animal.sex,
                "is_sterile": animal.is_sterile,
                "produces_eggs": animal.produces_eggs,
                "birthdate": animal.birthdate,
            }
        )
        return data


class FromWuttaFarmTaxonomy(FromWuttaFarm):
    """
    Base class for taxonomy term exporters
    """

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

    drupal_internal_id_field = "drupal_internal__tid"

    def normalize_source_object(self, term):
        return {
            "uuid": term.farmos_uuid or self.app.make_true_uuid(),
            "name": term.name,
            "description": term.description,
            "_src_object": term,
        }


class EquipmentTypeImporter(
    FromWuttaFarmTaxonomy, farmos_importing.model.EquipmentTypeImporter
):
    """
    WuttaFarm → farmOS API exporter for Equipment Types
    """

    source_model_class = model.EquipmentType


class EquipmentAssetImporter(
    FromWuttaFarmAsset, farmos_importing.model.EquipmentAssetImporter
):
    """
    WuttaFarm → farmOS API exporter for Equipment Assets
    """

    source_model_class = model.EquipmentAsset

    def get_supported_fields(self):
        fields = list(super().get_supported_fields())

        print(fields)
        fields.extend(
            [
                "manufacturer",
                "model",
                "serial_number",
                "equipment_type_uuids",
            ]
        )
        return fields

    def normalize_source_object(self, equipment):
        data = super().normalize_source_object(equipment)
        data.update(
            {
                "manufacturer": equipment.manufacturer,
                "model": equipment.model,
                "serial_number": equipment.serial_number,
                "equipment_type_uuids": [
                    etype.farmos_uuid for etype in equipment.equipment_types
                ],
            }
        )
        return data


class AnimalTypeImporter(
    FromWuttaFarmTaxonomy, farmos_importing.model.AnimalTypeImporter
):
    """
    WuttaFarm → farmOS API exporter for Animal Types
    """

    source_model_class = model.AnimalType


class MaterialTypeImporter(
    FromWuttaFarmTaxonomy, farmos_importing.model.MaterialTypeImporter
):
    """
    WuttaFarm → farmOS API exporter for Material Types
    """

    source_model_class = model.MaterialType


class UnitImporter(FromWuttaFarm, farmos_importing.model.UnitImporter):
    """
    WuttaFarm → farmOS API exporter for Units
    """

    source_model_class = model.Unit

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

    drupal_internal_id_field = "drupal_internal__tid"

    def normalize_source_object(self, unit):
        return {
            "uuid": unit.farmos_uuid or self.app.make_true_uuid(),
            "name": unit.name,
            "_src_object": unit,
        }


class GroupAssetImporter(FromWuttaFarmAsset, farmos_importing.model.GroupAssetImporter):
    """
    WuttaFarm → farmOS API exporter for Group Assets
    """

    source_model_class = model.GroupAsset

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

    def normalize_source_object(self, group):
        data = super().normalize_source_object(group)
        data.update(
            {
                "produces_eggs": group.produces_eggs,
            }
        )
        return data


class LandAssetImporter(FromWuttaFarmAsset, farmos_importing.model.LandAssetImporter):
    """
    WuttaFarm → farmOS API exporter for Land Assets
    """

    source_model_class = model.LandAsset

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

    def normalize_source_object(self, land):
        data = super().normalize_source_object(land)
        data.update(
            {
                "land_type_id": land.land_type.drupal_id,
            }
        )
        return data


class PlantTypeImporter(FromWuttaFarm, farmos_importing.model.PlantTypeImporter):
    """
    WuttaFarm → farmOS API exporter for Plant Types
    """

    source_model_class = model.PlantType

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

    drupal_internal_id_field = "drupal_internal__tid"

    def normalize_source_object(self, plant_type):
        return {
            "uuid": plant_type.farmos_uuid or self.app.make_true_uuid(),
            "name": plant_type.name,
            "_src_object": plant_type,
        }


class SeasonImporter(FromWuttaFarm, farmos_importing.model.SeasonImporter):
    """
    WuttaFarm → farmOS API exporter for Seasons
    """

    source_model_class = model.Season

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

    drupal_internal_id_field = "drupal_internal__tid"

    def normalize_source_object(self, season):
        return {
            "uuid": season.farmos_uuid or self.app.make_true_uuid(),
            "name": season.name,
            "_src_object": season,
        }


class PlantAssetImporter(FromWuttaFarmAsset, farmos_importing.model.PlantAssetImporter):
    """
    WuttaFarm → farmOS API exporter for Plant Assets
    """

    source_model_class = model.PlantAsset

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

    def normalize_source_object(self, plant):
        data = super().normalize_source_object(plant)
        data.update(
            {
                "plant_type_uuids": [pt.farmos_uuid for pt in plant.plant_types],
                "season_uuids": [s.farmos_uuid for s in plant.seasons],
            }
        )
        return data


class StructureAssetImporter(
    FromWuttaFarmAsset, farmos_importing.model.StructureAssetImporter
):
    """
    WuttaFarm → farmOS API exporter for Structure Assets
    """

    source_model_class = model.StructureAsset

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

    def normalize_source_object(self, structure):
        data = super().normalize_source_object(structure)
        data.update(
            {
                "structure_type_id": structure.structure_type.drupal_id,
            }
        )
        return data


class WaterAssetImporter(FromWuttaFarmAsset, farmos_importing.model.WaterAssetImporter):
    """
    WuttaFarm → farmOS API exporter for Water Assets
    """

    source_model_class = model.WaterAsset


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


class FromWuttaFarmQuantity(FromWuttaFarm):
    """
    Base class for WuttaFarm -> farmOS quantity importers
    """

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

    def normalize_source_object(self, qty):
        return {
            "uuid": qty.farmos_uuid or self.app.make_true_uuid(),
            "measure": qty.measure_id,
            "value_numerator": qty.value_numerator,
            "value_denominator": qty.value_denominator,
            "label": qty.label,
            "quantity_type_uuid": qty.quantity_type.farmos_uuid,
            "unit_uuid": qty.units.farmos_uuid,
            "_src_object": qty,
        }


class MaterialQuantityImporter(
    FromWuttaFarmQuantity, farmos_importing.model.MaterialQuantityImporter
):
    """
    WuttaFarm → farmOS API exporter for Material Quantities
    """

    source_model_class = model.MaterialQuantity

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

        if "material_types" in self.fields:
            data["material_types"] = [mt.farmos_uuid for mt in quantity.material_types]

        return data


class StandardQuantityImporter(
    FromWuttaFarmQuantity, farmos_importing.model.StandardQuantityImporter
):
    """
    WuttaFarm → farmOS API exporter for Standard Quantities
    """

    source_model_class = model.StandardQuantity


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


class FromWuttaFarmLog(FromWuttaFarm):
    """
    Base class for WuttaFarm -> farmOS log importers
    """

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

    def normalize_source_object(self, log):
        return {
            "uuid": log.farmos_uuid or self.app.make_true_uuid(),
            "name": log.message,
            "timestamp": log.timestamp,
            "is_movement": log.is_movement,
            "is_group_assignment": log.is_group_assignment,
            "status": log.status,
            "notes": log.notes,
            "quick": self.config.parse_list(log.quick) if log.quick else [],
            "assets": [(a.asset_type, a.farmos_uuid) for a in log.assets],
            "locations": [(l.asset_type, l.farmos_uuid) for l in log.locations],
            "groups": [(g.asset_type, g.farmos_uuid) for g in log.groups],
            "quantities": [qty.farmos_uuid for qty in log.quantities],
            "_src_object": log,
        }


class ActivityLogImporter(FromWuttaFarmLog, farmos_importing.model.ActivityLogImporter):
    """
    WuttaFarm → farmOS API exporter for Activity Logs
    """

    source_model_class = model.ActivityLog


class HarvestLogImporter(FromWuttaFarmLog, farmos_importing.model.HarvestLogImporter):
    """
    WuttaFarm → farmOS API exporter for Harvest Logs
    """

    source_model_class = model.HarvestLog


class MedicalLogImporter(FromWuttaFarmLog, farmos_importing.model.MedicalLogImporter):
    """
    WuttaFarm → farmOS API exporter for Medical Logs
    """

    source_model_class = model.MedicalLog

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

    def normalize_source_object(self, log):
        data = super().normalize_source_object(log)
        data.update(
            {
                "vet": log.vet,
            }
        )
        return data


class ObservationLogImporter(
    FromWuttaFarmLog, farmos_importing.model.ObservationLogImporter
):
    """
    WuttaFarm → farmOS API exporter for Observation Logs
    """

    source_model_class = model.ObservationLog


class SeedingLogImporter(FromWuttaFarmLog, farmos_importing.model.SeedingLogImporter):
    """
    WuttaFarm → farmOS API exporter for Seeding Logs
    """

    source_model_class = model.SeedingLog

    def normalize_source_object(self, log):
        data = super().normalize_source_object(log)
        data.update(
            {
                "source": log.source,
                "purchase_date": log.purchase_date,
                "lot_number": log.lot_number,
            }
        )
        return data
