# XXX this should probably be moved to something like ploneintranet.management
from plone import api
from plone.base.utils import safe_bytes
from Products.Five import BrowserView
from zope.component import getUtility
from zope.intid.interfaces import IIntIds


class ManageIntIds(BrowserView):
    """Admin view that takes care of the intid persistent utility"""

    def log(self, line):
        self.request.response.appendBody(safe_bytes(line))
        self.request.response.appendBody(b"\n")

    @property
    def intids(self):
        return getUtility(IIntIds)

    def _path(self, persistentkey):
        obj = api.content.get(UID=persistentkey.object.UID())
        try:
            return "/".join(obj.getPhysicalPath())
        except Exception:
            pass

    @property
    def keys_with_a_broken_path(self):
        return [
            key
            for key in self.intids.ids
            if not self.context.unrestrictedTraverse(key.path, None)
        ]

    @property
    def refs_with_a_broken_path(self):
        return [
            ref
            for ref in self.intids.refs.values()
            if not self.context.unrestrictedTraverse(ref.path, None)
        ]

    def fix_broken_paths(self):
        for key in self.keys_with_a_broken_path:
            proper_path = self._path(key)
            if proper_path:
                line = "Fixed key {}: {} -> {}".format(
                    key.object, key.path, proper_path
                )
                key.path = proper_path
            else:
                line = "Error key {}: {} -> {}".format(
                    key.object, key.path, proper_path
                )
            self.log(line)

        for ref in self.refs_with_a_broken_path:
            proper_path = self._path(ref)
            if proper_path:
                line = "Fixed ref {}: {} -> {}".format(
                    ref.object, ref.path, proper_path
                )
                ref.path = proper_path
            else:
                line = "Error ref {}: {} -> {}".format(
                    ref.object, ref.path, proper_path
                )
            self.log(line)

    def check(self):
        """Check the intid catalog and return a summary"""
        keys_with_a_broken_path = self.keys_with_a_broken_path
        self.log(f"Number of keys with broken path: {len(keys_with_a_broken_path)}")
        for key in keys_with_a_broken_path:
            line = f"\t{key.object}: {key.path} -> {self._path(key)}"
            self.log(line)
        refs_with_a_broken_path = self.refs_with_a_broken_path
        self.log(
            "\nNumber of references with broken path: {}".format(
                len(refs_with_a_broken_path)
            )
        )

        for ref in refs_with_a_broken_path:
            line = f"\t{ref.object}: {ref.path} -> {self._path(ref)}"
            self.log(line)

    def fix(self):
        """Fix the intid catalog and return a summary"""
        self.fix_broken_paths()
        return
