# -*- 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/>.
#
################################################################################
"""
View for farmOS Quantity Types
"""

import datetime

import colander
import requests

from wuttaweb.forms.schema import WuttaDateTime
from wuttaweb.forms.widgets import WuttaDateTimeWidget

from wuttafarm.web.views.farmos import FarmOSMasterView
from wuttafarm.web.forms.schema import FarmOSUnitRef, FarmOSRefs
from wuttafarm.web.grids import ResourceData


class QuantityTypeView(FarmOSMasterView):
    """
    View for farmOS Quantity Types
    """

    model_name = "farmos_quantity_type"
    model_title = "farmOS Quantity Type"
    model_title_plural = "farmOS Quantity Types"

    route_prefix = "farmos_quantity_types"
    url_prefix = "/farmOS/quantity-types"

    grid_columns = [
        "label",
        "description",
    ]

    sort_defaults = "label"

    form_fields = [
        "label",
        "description",
    ]

    def get_grid_data(self, columns=None, session=None):
        result = self.farmos_client.resource.get("quantity_type")
        return [self.normalize_quantity_type(t) for t in result["data"]]

    def configure_grid(self, grid):
        g = grid
        super().configure_grid(g)

        # label
        g.set_link("label")
        g.set_searchable("label")

        # description
        g.set_searchable("description")

    def get_instance(self):
        result = self.farmos_client.resource.get_id(
            "quantity_type", "quantity_type", self.request.matchdict["uuid"]
        )
        self.raw_json = result
        return self.normalize_quantity_type(result["data"])

    def get_instance_title(self, quantity_type):
        return quantity_type["label"]

    def normalize_quantity_type(self, quantity_type):
        return {
            "uuid": quantity_type["id"],
            "drupal_id": quantity_type["attributes"]["drupal_internal__id"],
            "label": quantity_type["attributes"]["label"],
            "description": quantity_type["attributes"]["description"],
        }

    def configure_form(self, form):
        f = form
        super().configure_form(f)

        # description
        f.set_widget("description", "notes")

    def get_xref_buttons(self, quantity_type):
        model = self.app.model
        session = self.Session()
        buttons = []

        if wf_quantity_type := (
            session.query(model.QuantityType)
            .filter(model.QuantityType.farmos_uuid == quantity_type["uuid"])
            .first()
        ):
            buttons.append(
                self.make_button(
                    f"View {self.app.get_title()} record",
                    primary=True,
                    url=self.request.route_url(
                        "quantity_types.view", uuid=wf_quantity_type.uuid
                    ),
                    icon_left="eye",
                )
            )

        return buttons


class QuantityMasterView(FarmOSMasterView):
    """
    Base class for Quantity views
    """

    farmos_quantity_type = None

    grid_columns = [
        "drupal_id",
        "as_text",
        "measure",
        "value",
        "unit",
        "label",
    ]

    sort_defaults = ("drupal_id", "desc")

    form_fields = [
        "quantity_type_name",
        "measure",
        "value",
        "units",
        "label",
        "created",
        "changed",
    ]

    def get_farmos_api_includes(self):
        return {"units"}

    def get_grid_data(self, **kwargs):
        return ResourceData(
            self.config,
            self.farmos_client,
            f"quantity--{self.farmos_quantity_type}",
            include=",".join(self.get_farmos_api_includes()),
            normalizer=self.normalize_quantity,
        )

    def configure_grid(self, grid):
        g = grid
        super().configure_grid(g)

        # drupal_id
        g.set_label("drupal_id", "ID", column_only=True)

        # as_text
        g.set_renderer("as_text", self.render_as_text_for_grid)
        g.set_link("as_text")

        # measure
        g.set_renderer("measure", self.render_measure_for_grid)

        # value
        g.set_renderer("value", self.render_value_for_grid)

        # unit
        g.set_renderer("unit", self.render_unit_for_grid)

        # changed
        g.set_renderer("changed", "datetime")

    def render_as_text_for_grid(self, qty, field, value):
        measure = qty["measure"].capitalize()
        value = qty["value"]["decimal"]
        units = qty["unit"]["name"] if qty["unit"] else "??"
        return f"( {measure} ) {value} {units}"

    def render_measure_for_grid(self, qty, field, value):
        return qty["measure"].capitalize()

    def render_unit_for_grid(self, qty, field, value):
        unit = qty[field]
        if not unit:
            return ""
        return unit["name"]

    def render_value_for_grid(self, qty, field, value):
        return qty["value"]["decimal"]

    def get_instance(self):
        # TODO: this pattern should be repeated for other views
        try:
            result = self.farmos_client.resource.get_id(
                "quantity",
                self.farmos_quantity_type,
                self.request.matchdict["uuid"],
                params={"include": self.get_farmos_api_includes()},
            )
        except requests.HTTPError as exc:
            if exc.response.status_code == 404:
                raise self.notfound()
            raise

        self.raw_json = result

        included = {obj["id"]: obj for obj in result.get("included", [])}
        assert included
        data = self.normalize_quantity(result["data"], included)

        if relationships := result["data"].get("relationships"):

            # add units
            if units := relationships.get("units"):
                if units["data"]:
                    unit = self.farmos_client.resource.get_id(
                        "taxonomy_term", "unit", units["data"]["id"]
                    )
                    data["units"] = {
                        "uuid": unit["data"]["id"],
                        "name": unit["data"]["attributes"]["name"],
                    }

        return data

    def get_instance_title(self, quantity):
        return quantity["value"]

    def normalize_quantity(self, quantity, included={}):

        if created := quantity["attributes"]["created"]:
            created = datetime.datetime.fromisoformat(created)
            created = self.app.localtime(created)

        if changed := quantity["attributes"]["changed"]:
            changed = datetime.datetime.fromisoformat(changed)
            changed = self.app.localtime(changed)

        quantity_type_object = None
        quantity_type_uuid = None
        unit_object = None
        unit_uuid = None
        if relationships := quantity["relationships"]:

            if quantity_type := relationships["quantity_type"]["data"]:
                quantity_type_uuid = quantity_type["id"]
                quantity_type_object = {
                    "uuid": quantity_type_uuid,
                    "type": "quantity_type--quantity_type",
                }

            if unit := relationships["units"]["data"]:
                unit_uuid = unit["id"]
                if unit := included.get(unit_uuid):
                    unit_object = {
                        "uuid": unit_uuid,
                        "type": "taxonomy_term--unit",
                        "name": unit["attributes"]["name"],
                    }

        return {
            "uuid": quantity["id"],
            "drupal_id": quantity["attributes"]["drupal_internal__id"],
            "quantity_type": quantity_type_object,
            "quantity_type_uuid": quantity_type_uuid,
            "measure": quantity["attributes"]["measure"],
            "value": quantity["attributes"]["value"],
            "unit": unit_object,
            "unit_uuid": unit_uuid,
            "label": quantity["attributes"]["label"] or colander.null,
            "created": created,
            "changed": changed,
        }

    def configure_form(self, form):
        f = form
        super().configure_form(f)

        # quantity_type_name
        f.set_label("quantity_type_name", "Quantity Type")
        f.set_readonly("quantity_type_name")
        f.set_default("quantity_type_name", self.farmos_quantity_type.capitalize())

        # created
        f.set_node("created", WuttaDateTime(self.request))
        f.set_widget("created", WuttaDateTimeWidget(self.request))

        # changed
        f.set_node("changed", WuttaDateTime(self.request))
        f.set_widget("changed", WuttaDateTimeWidget(self.request))

        # units
        f.set_node("units", FarmOSUnitRef())


class StandardQuantityView(QuantityMasterView):
    """
    View for farmOS Standard Quantities
    """

    model_name = "farmos_standard_quantity"
    model_title = "farmOS Standard Quantity"
    model_title_plural = "farmOS Standard Quantities"

    route_prefix = "farmos_quantities_standard"
    url_prefix = "/farmOS/quantities/standard"

    farmos_quantity_type = "standard"
    farmos_refurl_path = "/log-quantities/standard"

    def get_xref_buttons(self, standard_quantity):
        model = self.app.model
        session = self.Session()
        buttons = []

        if wf_standard_quantity := (
            session.query(model.StandardQuantity)
            .join(model.Quantity)
            .filter(model.Quantity.farmos_uuid == standard_quantity["uuid"])
            .first()
        ):
            buttons.append(
                self.make_button(
                    f"View {self.app.get_title()} record",
                    primary=True,
                    url=self.request.route_url(
                        "quantities_standard.view", uuid=wf_standard_quantity.uuid
                    ),
                    icon_left="eye",
                )
            )

        return buttons


class MaterialQuantityView(QuantityMasterView):
    """
    View for farmOS Material Quantities
    """

    model_name = "farmos_material_quantity"
    model_title = "farmOS Material Quantity"
    model_title_plural = "farmOS Material Quantities"

    route_prefix = "farmos_quantities_material"
    url_prefix = "/farmOS/quantities/material"

    farmos_quantity_type = "material"
    farmos_refurl_path = "/log-quantities/material"

    def get_farmos_api_includes(self):
        includes = super().get_farmos_api_includes()
        includes.update({"material_type"})
        return includes

    def normalize_quantity(self, quantity, included={}):
        normal = super().normalize_quantity(quantity, included)

        material_type_objects = []
        material_type_uuids = []
        if relationships := quantity["relationships"]:

            if material_types := relationships["material_type"]["data"]:
                for mtype in material_types:
                    uuid = mtype["id"]
                    material_type_uuids.append(uuid)
                    material_type = {
                        "uuid": uuid,
                        "type": mtype["type"],
                    }
                    if mtype := included.get(uuid):
                        material_type.update(
                            {
                                "name": mtype["attributes"]["name"],
                            }
                        )
                    material_type_objects.append(material_type)

        normal.update(
            {
                "material_types": material_type_objects,
                "material_type_uuids": material_type_uuids,
            }
        )
        return normal

    def configure_form(self, form):
        f = form
        super().configure_form(f)

        # material_types
        f.fields.insert_before("measure", "material_types")
        f.set_node("material_types", FarmOSRefs(self.request, "farmos_material_types"))

    def get_xref_buttons(self, material_quantity):
        model = self.app.model
        session = self.Session()
        buttons = []

        if wf_material_quantity := (
            session.query(model.MaterialQuantity)
            .join(model.Quantity)
            .filter(model.Quantity.farmos_uuid == material_quantity["uuid"])
            .first()
        ):
            buttons.append(
                self.make_button(
                    f"View {self.app.get_title()} record",
                    primary=True,
                    url=self.request.route_url(
                        "quantities_material.view", uuid=wf_material_quantity.uuid
                    ),
                    icon_left="eye",
                )
            )

        return buttons


def defaults(config, **kwargs):
    base = globals()

    QuantityTypeView = kwargs.get("QuantityTypeView", base["QuantityTypeView"])
    QuantityTypeView.defaults(config)

    StandardQuantityView = kwargs.get(
        "StandardQuantityView", base["StandardQuantityView"]
    )
    StandardQuantityView.defaults(config)

    MaterialQuantityView = kwargs.get(
        "MaterialQuantityView", base["MaterialQuantityView"]
    )
    MaterialQuantityView.defaults(config)


def includeme(config):
    defaults(config)
