# -*- 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/>.
#
################################################################################
"""
Base class for Asset master views
"""

import colander
import requests
from webhelpers2.html import tags

from wuttafarm.web.views.farmos import FarmOSMasterView
from wuttafarm.web.forms.schema import FarmOSRefs, FarmOSAssetRefs, FarmOSLocationRefs
from wuttafarm.web.forms.widgets import ImageWidget
from wuttafarm.web.grids import (
    ResourceData,
    StringFilter,
    IntegerFilter,
    BooleanFilter,
    SimpleSorter,
)


class AssetMasterView(FarmOSMasterView):
    """
    Base class for Asset master views
    """

    farmos_asset_type = None
    creatable = True
    editable = True
    deletable = True
    filterable = True
    sort_on_backend = True

    labels = {
        "name": "Asset Name",
        "asset_type_name": "Asset Type",
        "locations": "Location",
        "groups": "Group Membership",
        "thumbnail_url": "Thumbnail URL",
        "image_url": "Image URL",
    }

    grid_columns = [
        "thumbnail",
        "drupal_id",
        "name",
        "owners",
        "locations",
        "archived",
    ]

    sort_defaults = "name"

    filter_defaults = {
        "name": {"active": True, "verb": "contains"},
        "archived": {"active": True, "verb": "is_false"},
    }

    form_fields = [
        "name",
        "notes",
        "asset_type_name",
        "owners",
        "is_location",
        "is_fixed",
        "locations",
        "groups",
        "archived",
        "drupal_id",
        "thumbnail_url",
        "image_url",
        "thumbnail",
        "image",
    ]

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

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

        # thumbnail
        g.set_renderer("thumbnail", self.render_grid_thumbnail)
        g.set_label("thumbnail", "", column_only=True)
        g.set_centered("thumbnail")

        # drupal_id
        g.set_label("drupal_id", "ID", column_only=True)
        g.set_sorter("drupal_id", SimpleSorter("drupal_internal__id"))
        g.set_filter("drupal_id", IntegerFilter, path="drupal_internal__id")

        # name
        g.set_link("name")
        g.set_sorter("name", SimpleSorter("name"))
        g.set_filter("name", StringFilter)

        # owners
        g.set_label("owners", "Owner")
        g.set_renderer("owners", self.render_owners_for_grid)

        # locations
        g.set_renderer("locations", self.render_locations_for_grid)

        # groups
        g.set_label("groups", "Group Membership")
        g.set_renderer("groups", self.render_assets_for_grid)

        # archived
        g.set_renderer("archived", "boolean")
        g.set_sorter("archived", SimpleSorter("archived"))
        g.set_filter("archived", BooleanFilter)

    def render_grid_thumbnail(self, obj, field, value):
        if url := obj.get("thumbnail_url"):
            return tags.image(url, f"thumbnail for {self.get_model_title()}")
        return None

    def render_assets_for_grid(self, log, field, value):
        if not value:
            return ""

        assets = []
        for asset in value:
            if self.farmos_style_grid_links:
                route = f"farmos_{asset['asset_type']}_assets.view"
                url = self.request.route_url(route, uuid=asset["uuid"])
                assets.append(tags.link_to(asset["name"], url))
            else:
                assets.append(asset["name"])
        return ", ".join(assets)

    def render_locations_for_grid(self, asset, field, value):
        locations = []
        for location in value:
            if self.farmos_style_grid_links:
                asset_type = location["type"].split("--")[1]
                route = f"farmos_{asset_type}_assets.view"
                url = self.request.route_url(route, uuid=location["uuid"])
                locations.append(tags.link_to(location["name"], url))
            else:
                locations.append(location["name"])
        return ", ".join(locations)

    def grid_row_class(self, asset, data, i):
        """ """
        if asset["archived"]:
            return "has-background-warning"
        return None

    def get_farmos_api_includes(self):
        return {"asset_type", "location", "group", "owner", "image"}

    def get_instance(self):
        try:
            result = self.farmos_client.asset.get_id(
                self.farmos_asset_type,
                self.request.matchdict["uuid"],
                params={"include": ",".join(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", [])}
        return self.normalize_asset(result["data"], included)

    def get_instance_title(self, asset):
        return asset["name"]

    def normalize_asset(self, asset, included):

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

        if self.farmos_4x:
            archived = asset["attributes"]["archived"]
        else:
            archived = asset["attributes"]["status"] == "archived"

        asset_type_object = {}
        asset_type_name = None
        owner_objects = []
        owner_names = []
        location_objects = []
        location_names = []
        group_objects = []
        thumbnail_url = None
        image_url = None
        if relationships := asset.get("relationships"):

            if asset_type := relationships.get("asset_type"):
                if asset_type := included.get(asset_type["data"]["id"]):
                    asset_type_object = {
                        "uuid": asset_type["id"],
                        "name": asset_type["attributes"]["label"],
                    }
                    asset_type_name = asset_type_object["name"]

            if owners := relationships.get("owner"):
                for user in owners["data"]:
                    if user := included.get(user["id"]):
                        user = {
                            "uuid": user["id"],
                            "name": user["attributes"]["name"],
                        }
                        owner_objects.append(user)
                        owner_names.append(user["name"])

            if locations := relationships.get("location"):
                for location in locations["data"]:
                    if location := included.get(location["id"]):
                        location = {
                            "uuid": location["id"],
                            "type": location["type"],
                            "name": location["attributes"]["name"],
                        }
                        location_objects.append(location)
                        location_names.append(location["name"])

            if groups := relationships.get("group"):
                for group in groups["data"]:
                    if group := included.get(group["id"]):
                        group = {
                            "uuid": group["id"],
                            "name": group["attributes"]["name"],
                            "asset_type": "group",
                        }
                        group_objects.append(group)

            if images := relationships.get("image"):
                for image in images["data"]:
                    if image := included.get(image["id"]):
                        thumbnail_url = image["attributes"]["image_style_uri"][
                            "thumbnail"
                        ]
                        image_url = image["attributes"]["image_style_uri"]["large"]

        return {
            "uuid": asset["id"],
            "drupal_id": asset["attributes"]["drupal_internal__id"],
            "name": asset["attributes"]["name"],
            "asset_type": asset_type_object,
            "asset_type_name": asset_type_name,
            "is_location": asset["attributes"]["is_location"],
            "is_fixed": asset["attributes"]["is_fixed"],
            "notes": notes or colander.null,
            "owners": owner_objects,
            "owner_names": owner_names,
            "locations": location_objects,
            "location_names": location_names,
            "groups": group_objects,
            "archived": archived,
            "thumbnail_url": thumbnail_url or colander.null,
            "image_url": image_url or colander.null,
        }

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

        # asset_type_name
        if self.creating or self.editing:
            f.remove("asset_type_name")

        # locations
        if self.creating or self.editing:
            f.remove("locations")
        else:
            f.set_label("locations", "Current Location")
            f.set_node("locations", FarmOSLocationRefs(self.request))

        # groups
        if self.creating or self.editing:
            f.remove("groups")  # TODO
        else:
            f.set_node("groups", FarmOSAssetRefs(self.request))

        # owners
        if self.creating or self.editing:
            f.remove("owners")  # TODO
        else:
            f.set_node("owners", FarmOSRefs(self.request, "farmos_users"))

        # notes
        f.set_widget("notes", "notes")
        f.set_required("notes", False)

        # is_location
        f.set_node("is_location", colander.Boolean())

        # is_fixed
        f.set_node("is_fixed", colander.Boolean())

        # groups
        if self.creating or self.editing:
            f.remove("groups")  # TODO: add support for this?

        # archived
        f.set_node("archived", colander.Boolean())

        # thumbnail_url
        if self.creating or self.editing:
            f.remove("thumbnail_url")

        # image_url
        if self.creating or self.editing:
            f.remove("image_url")

        # thumbnail
        if self.creating or self.editing:
            f.remove("thumbnail")
        elif asset.get("thumbnail_url"):
            f.set_widget("thumbnail", ImageWidget("asset thumbnail"))
            f.set_default("thumbnail", asset["thumbnail_url"])

        # image
        if self.creating or self.editing:
            f.remove("image")
        elif asset.get("image_url"):
            f.set_widget("image", ImageWidget("asset image"))
            f.set_default("image", asset["image_url"])

    def persist(self, asset, session=None):
        payload = self.get_api_payload(asset)
        if self.editing:
            payload["id"] = asset["uuid"]

        result = self.farmos_client.asset.send(self.farmos_asset_type, payload)

        if self.creating:
            asset["uuid"] = result["data"]["id"]

    def get_api_payload(self, asset):

        attrs = {
            "name": asset["name"],
            "notes": {"value": asset["notes"] or None},
            "archived": asset["archived"],
        }

        if "is_location" in asset:
            attrs["is_location"] = asset["is_location"]

        if "is_fixed" in asset:
            attrs["is_fixed"] = asset["is_fixed"]

        return {"attributes": attrs}

    def delete_instance(self, asset):
        self.farmos_client.asset.delete(self.farmos_asset_type, asset["uuid"])

    def get_xref_buttons(self, asset):
        return [
            self.make_button(
                "View in farmOS",
                primary=True,
                url=self.app.get_farmos_url(f"/asset/{asset['drupal_id']}"),
                target="_blank",
                icon_left="external-link-alt",
            ),
        ]
