from Acquisition import aq_inner
from plone import api
from plone.app.iterate.interfaces import ICheckinCheckoutPolicy
from plone.app.iterate.interfaces import IIterateManagedContent
from plone.memoize.view import memoize
from ploneintranet.core import _
from ploneintranet.layout.browser.base import BasePanel
from Products.CMFPlone.utils import get_installer
from Products.Five.browser import BrowserView


class EditButton(BrowserView):
    """Logic to create a proper edit button when plone.app.iterate is present

    The edit button will either be a link:
    - to a modal that allows to create a working copy
    - to the edit form of the working copy
    """

    @property
    @memoize
    def working_copy(self):
        """Check if there is an existing working copy"""
        return ICheckinCheckoutPolicy(self.context).getWorkingCopy()

    @property
    @memoize
    def iterate_control_view(self):
        return api.content.get_view("iterate_control", self.context, self.request)

    @memoize
    def can_view_working_copy(self):
        """Check if the user can see the working copy (if it exists)"""
        if not self.working_copy:
            return False
        return api.user.has_permission("View", obj=self.working_copy)

    def can_edit_original(self):
        """Check if the user can edit the original object"""
        return api.user.has_permission("Modify portal content", obj=self.context)

    @property
    @memoize
    def baseline(self):
        """Get the baseline for this working copy"""
        return ICheckinCheckoutPolicy(self.context).getBaseline()

    @property
    @memoize
    def properties(self):
        """Get the checkin/checkout properties for this context

        Usually this looks like:
        {'checkout_time': DateTime('2022/...'), 'checkout_user': 'alice_lindstrom'}
        """
        return ICheckinCheckoutPolicy(self.context).getProperties(self.context)

    def available(self):
        """Check if the edit button should be displayed"""
        installer = get_installer(self.context, self.request)
        if not installer.is_product_installed("plone.app.iterate"):
            return False

        if self.can_view_working_copy():
            # We already have an existent working copy,
            # the button will link to its edit form to whoever can see it
            return True

        if api.content.get_state(
            self.context
        ) != "published" and not IIterateManagedContent.providedBy(self.context):
            # If this object is not published and it is not a baseline or a working copy
            # we will not display the button
            return False

        # Do not allow the user to see the checkout button
        # if he is not enough permissions
        if not api.user.has_permission("iterate : Check out content", obj=self.context):
            return False
        return self.iterate_control_view.checkout_allowed()


class CheckOutPanel(BasePanel):
    title = _("label_check_out", "Check out")
    _form_data_pat_inject_parts = (
        "#global-statusmessage; loading-class: ''",
        "#document-body",
    )

    @property
    def locator(self):
        """Get a locator for the current context"""
        view = api.content.get_view("content-checkout", self.context, self.request)
        for container in view.containers():
            if container["name"] == "plone.app.iterate.parent":
                return container["locator"]

    def execute_on_post(self):
        """On post we want to create a working copy of the current context"""

        context = aq_inner(self.context)
        target = context
        iterate_control_view = api.content.get_view(
            "iterate_control", context, self.request
        )
        if not iterate_control_view.checkout_allowed():
            return self.redirect(
                f"{target.absolute_url()}/@@edit.html",
                _("Check out not allowed"),
                "error",
            )

        locator = self.locator
        if not locator:
            return self.redirect(
                f"{target.absolute_url()}/@@edit.html",
                _("Cannot find checkout location"),
                "error",
            )

        policy = ICheckinCheckoutPolicy(context)
        target = policy.checkout(locator())

        # we do this for metadata update side affects which will update
        # lock info
        context.reindexObject(idxs=["review_state"])

        return self.redirect(
            f"{target.absolute_url()}/@@edit.html", _("Check-out created"), "success"
        )


class CheckInPanel(BasePanel):
    title = _("label_check_in", "Check in")
    _form_data_pat_inject_parts = (
        "#global-statusmessage; loading-class: ''",
        "#document-body",
    )

    def execute_on_post(self):
        """On post we want to check in the working copy of the current context"""
        context = aq_inner(self.context)
        target = context

        iterate_control_view = api.content.get_view(
            "iterate_control", context, self.request
        )
        if not iterate_control_view.checkin_allowed():
            return self.redirect(
                f"{target.absolute_url()}/@@edit.html",
                _("Check in not allowed"),
                "error",
            )

        policy = ICheckinCheckoutPolicy(context)

        # plone.app.iterate allows to write a change note
        message = ""
        target = policy.checkin(message)

        return self.redirect(
            f"{target.absolute_url()}/@@edit.html", _("Checked in"), "success"
        )


class RemovePanel(BasePanel):
    title = _("Remove the working copy")
    _form_data_pat_inject_parts = (
        "#global-statusmessage; loading-class: ''",
        "#document-body",
    )

    def execute_on_post(self):
        """On post we want to remove the working copy of the current context"""
        context = aq_inner(self.context)
        target = context

        iterate_control_view = api.content.get_view(
            "iterate_control", context, self.request
        )
        if not iterate_control_view.cancel_allowed():
            return self.redirect(
                f"{target.absolute_url()}/@@edit.html",
                _("You are not allowed to remove this working copy"),
                "error",
            )

        policy = ICheckinCheckoutPolicy(context)
        target = policy.cancelCheckout()
        target.reindexObject()

        return self.redirect(
            f"{target.absolute_url()}/@@edit.html",
            _("The working copy has been removed"),
            "success",
        )
