# -*- 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/>.
#
################################################################################
"""
Custom form widgets for WuttaFarm
"""

import json

import colander
from deform.widget import Widget, SelectWidget
from webhelpers2.html import HTML, tags

from wuttaweb.forms.widgets import WuttaCheckboxChoiceWidget
from wuttaweb.db import Session

from wuttafarm.web.util import render_quantity_objects


class ImageWidget(Widget):
    """
    Widget to display an image URL for a record.
    """

    def __init__(self, alt_text, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.alt_text = alt_text

    def serialize(self, field, cstruct, **kw):
        """ """
        readonly = kw.get("readonly", self.readonly)
        if readonly:
            if cstruct in (colander.null, None):
                return HTML.tag("span")

            return tags.image(cstruct, self.alt_text, **kw)

        return super().serialize(field, cstruct, **kw)


class LogQuickWidget(Widget):
    """
    Widget to display an image URL for a record.
    """

    def serialize(self, field, cstruct, **kw):
        """ """
        readonly = kw.get("readonly", self.readonly)
        if readonly:
            if cstruct in (colander.null, None):
                return HTML.tag("span")

            items = []
            for quick in json.loads(cstruct):
                items.append(HTML.tag("li", c=quick))
            return HTML.tag("ul", c=items)

        return super().serialize(field, cstruct, **kw)


class FarmOSRefWidget(SelectWidget):
    """
    Generic widget to display "any reference field" - as a link to
    view the farmOS record it references.  Only used by the farmOS
    direct API views.
    """

    def __init__(self, request, route_prefix, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.request = request
        self.route_prefix = route_prefix

    def serialize(self, field, cstruct, **kw):
        """ """
        readonly = kw.get("readonly", self.readonly)
        if readonly:
            if cstruct in (colander.null, None):
                return HTML.tag("span")

            try:
                obj = json.loads(cstruct)
            except json.JSONDecodeError:
                name = dict(self.values)[cstruct]
                obj = {"uuid": cstruct, "name": name}

            return tags.link_to(
                obj["name"],
                self.request.route_url(f"{self.route_prefix}.view", uuid=obj["uuid"]),
            )

        return super().serialize(field, cstruct, **kw)


class FarmOSRefsWidget(Widget):

    def __init__(self, request, route_prefix, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.request = request
        self.route_prefix = route_prefix

    def serialize(self, field, cstruct, **kw):
        """ """
        readonly = kw.get("readonly", self.readonly)
        if readonly:
            if cstruct in (colander.null, None):
                return HTML.tag("span")

            links = []
            for obj in json.loads(cstruct):
                url = self.request.route_url(
                    f"{self.route_prefix}.view", uuid=obj["uuid"]
                )
                links.append(HTML.tag("li", c=tags.link_to(obj["name"], url)))

            return HTML.tag("ul", c=links)

        return super().serialize(field, cstruct, **kw)


class FarmOSAssetRefsWidget(Widget):
    """
    Widget to display a "Assets" field for an asset.
    """

    def __init__(self, request, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.request = request

    def serialize(self, field, cstruct, **kw):
        """ """
        readonly = kw.get("readonly", self.readonly)
        if readonly:
            if cstruct in (colander.null, None):
                return HTML.tag("span")

            assets = []
            for asset in json.loads(cstruct):
                url = self.request.route_url(
                    f"farmos_{asset['asset_type']}_assets.view", uuid=asset["uuid"]
                )
                assets.append(HTML.tag("li", c=tags.link_to(asset["name"], url)))

            return HTML.tag("ul", c=assets)

        return super().serialize(field, cstruct, **kw)


class FarmOSLocationRefsWidget(Widget):
    """
    Widget to display a "Locations" field for an asset.
    """

    def __init__(self, request, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.request = request

    def serialize(self, field, cstruct, **kw):
        """ """
        readonly = kw.get("readonly", self.readonly)
        if readonly:
            if cstruct in (colander.null, None):
                return HTML.tag("span")

            locations = []
            for location in json.loads(cstruct):
                asset_type = location["type"].split("--")[1]
                url = self.request.route_url(
                    f"farmos_{asset_type}_assets.view", uuid=location["uuid"]
                )
                locations.append(HTML.tag("li", c=tags.link_to(location["name"], url)))

            return HTML.tag("ul", c=locations)

        return super().serialize(field, cstruct, **kw)


class FarmOSQuantityRefsWidget(Widget):
    """
    Widget to display a "Quantities" field for a log.
    """

    def serialize(self, field, cstruct, **kw):
        """ """
        readonly = kw.get("readonly", self.readonly)
        if readonly:
            if cstruct in (colander.null, None):
                return HTML.tag("span")

            quantities = json.loads(cstruct)
            return render_quantity_objects(quantities)

        return super().serialize(field, cstruct, **kw)


class FarmOSUnitRefWidget(Widget):
    """
    Widget to display a "Units" field for a quantity.
    """

    def serialize(self, field, cstruct, **kw):
        """ """
        readonly = kw.get("readonly", self.readonly)
        if readonly:
            if cstruct in (colander.null, None):
                return HTML.tag("span")

            unit = json.loads(cstruct)
            return unit["name"]

        return super().serialize(field, cstruct, **kw)


class AnimalTypeWidget(Widget):
    """
    Widget to display an "animal type" field.
    """

    def __init__(self, request, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.request = request

    def serialize(self, field, cstruct, **kw):
        """ """
        readonly = kw.get("readonly", self.readonly)
        if readonly:
            if cstruct in (colander.null, None):
                return HTML.tag("span")

            animal_type = json.loads(cstruct)
            return tags.link_to(
                animal_type["name"],
                self.request.route_url(
                    "farmos_animal_types.view", uuid=animal_type["uuid"]
                ),
            )

        return super().serialize(field, cstruct, **kw)


class FarmOSPlantTypesWidget(Widget):
    """
    Widget to display a farmOS "plant types" field.
    """

    def __init__(self, request, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.request = request

    def serialize(self, field, cstruct, **kw):
        """ """
        readonly = kw.get("readonly", self.readonly)
        if readonly:
            if cstruct in (colander.null, None):
                return HTML.tag("span")

            links = []
            for plant_type in json.loads(cstruct):
                link = tags.link_to(
                    plant_type["name"],
                    self.request.route_url(
                        "farmos_plant_types.view", uuid=plant_type["uuid"]
                    ),
                )
                links.append(HTML.tag("li", c=link))
            return HTML.tag("ul", c=links)

        return super().serialize(field, cstruct, **kw)


class PlantTypeRefsWidget(WuttaCheckboxChoiceWidget):
    """
    Widget for Plant Types field (on a Plant Asset).
    """

    def serialize(self, field, cstruct, **kw):
        """ """
        model = self.app.model
        session = Session()

        readonly = kw.get("readonly", self.readonly)
        if readonly:
            plant_types = []
            for uuid in json.loads(cstruct):
                plant_type = session.get(model.PlantType, uuid)
                plant_types.append(
                    HTML.tag(
                        "li",
                        c=tags.link_to(
                            str(plant_type),
                            self.request.route_url(
                                "plant_types.view", uuid=plant_type.uuid
                            ),
                        ),
                    )
                )
            return HTML.tag("ul", c=plant_types)

        return super().serialize(field, cstruct, **kw)


class StructureWidget(Widget):
    """
    Widget to display a "structure" field.
    """

    def __init__(self, request, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.request = request

    def serialize(self, field, cstruct, **kw):
        """ """
        readonly = kw.get("readonly", self.readonly)
        if readonly:
            if cstruct in (colander.null, None):
                return HTML.tag("span")

            structure = json.loads(cstruct)
            return tags.link_to(
                structure["name"],
                self.request.route_url(
                    "farmos_structure_assets.view", uuid=structure["uuid"]
                ),
            )

        return super().serialize(field, cstruct, **kw)


class UsersWidget(Widget):
    """
    Widget to display the list of owners for an asset etc.
    """

    def __init__(self, request, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.request = request

    def serialize(self, field, cstruct, **kw):
        """ """
        readonly = kw.get("readonly", self.readonly)
        if readonly:
            if cstruct in (colander.null, None):
                return HTML.tag("span")

            items = []
            for user in json.loads(cstruct):
                link = tags.link_to(
                    user["display_name"],
                    self.request.route_url("farmos_users.view", uuid=user["uuid"]),
                )
                items.append(HTML.tag("li", c=link))

            return HTML.tag("ul", c=items)

        return super().serialize(field, cstruct, **kw)


class AssetParentRefsWidget(WuttaCheckboxChoiceWidget):
    """
    Widget for Parents field which references assets.
    """

    def serialize(self, field, cstruct, **kw):
        """ """
        model = self.app.model
        session = Session()

        readonly = kw.get("readonly", self.readonly)
        if readonly:
            parents = []
            for uuid in json.loads(cstruct):
                parent = session.get(model.Asset, uuid)
                parents.append(
                    HTML.tag(
                        "li",
                        c=tags.link_to(
                            str(parent),
                            self.request.route_url(
                                f"{parent.asset_type}_assets.view", uuid=parent.uuid
                            ),
                        ),
                    )
                )
            return HTML.tag("ul", c=parents)

        return super().serialize(field, cstruct, **kw)


class LogAssetRefsWidget(WuttaCheckboxChoiceWidget):
    """
    Widget for Assets field (on a Log record)
    """

    def serialize(self, field, cstruct, **kw):
        """ """
        model = self.app.model
        session = Session()

        readonly = kw.get("readonly", self.readonly)
        if readonly:
            assets = []
            for uuid in json.loads(cstruct):
                asset = session.get(model.Asset, uuid)
                assets.append(
                    HTML.tag(
                        "li",
                        c=tags.link_to(
                            str(asset),
                            self.request.route_url(
                                f"{asset.asset_type}_assets.view", uuid=asset.uuid
                            ),
                        ),
                    )
                )
            return HTML.tag("ul", c=assets)

        return super().serialize(field, cstruct, **kw)
