# -*- coding: utf-8 -*-
# Copyright (c) 2024, Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later

from __future__ import absolute_import, division, print_function

__metaclass__ = type

DOCUMENTATION = """
    name: run0
    short_description: Systemd's run0
    description:
        - This become plugins allows your remote/login user to execute commands as another user via the C(run0) utility.
    author:
        - Thomas Sjögren (@konstruktoid)
    version_added: '9.0.0'
    options:
        become_user:
            description: User you 'become' to execute the task.
            default: root
            ini:
              - section: privilege_escalation
                key: become_user
              - section: run0_become_plugin
                key: user
            vars:
              - name: ansible_become_user
              - name: ansible_run0_user
            env:
              - name: ANSIBLE_BECOME_USER
              - name: ANSIBLE_RUN0_USER
            type: string
        become_exe:
            description: The C(run0) executable.
            default: run0
            ini:
              - section: privilege_escalation
                key: become_exe
              - section: run0_become_plugin
                key: executable
            vars:
              - name: ansible_become_exe
              - name: ansible_run0_exe
            env:
              - name: ANSIBLE_BECOME_EXE
              - name: ANSIBLE_RUN0_EXE
            type: string
        become_flags:
            description: Options to pass to run0.
            default: ''
            ini:
              - section: privilege_escalation
                key: become_flags
              - section: run0_become_plugin
                key: flags
            vars:
              - name: ansible_become_flags
              - name: ansible_run0_flags
            env:
              - name: ANSIBLE_BECOME_FLAGS
              - name: ANSIBLE_RUN0_FLAGS
            type: string
    notes:
      - This plugin will only work when a polkit rule is in place.
"""

EXAMPLES = r"""
# An example polkit rule that allows the user 'ansible' in the 'wheel' group
# to execute commands using run0 without authentication.
/etc/polkit-1/rules.d/60-run0-fast-user-auth.rules: |
  polkit.addRule(function(action, subject) {
    if(action.id == "org.freedesktop.systemd1.manage-units" &&
      subject.isInGroup("wheel") &&
      subject.user == "ansible") {
        return polkit.Result.YES;
    }
  });
"""

from re import compile as re_compile

from ansible.plugins.become import BecomeBase
from ansible.module_utils._text import to_bytes

ansi_color_codes = re_compile(to_bytes(r"\x1B\[[0-9;]+m"))


class BecomeModule(BecomeBase):

    name = "community.general.run0"

    prompt = "Password: "
    fail = ("==== AUTHENTICATION FAILED ====",)
    success = ("==== AUTHENTICATION COMPLETE ====",)
    require_tty = (
        True  # see https://github.com/ansible-collections/community.general/issues/6932
    )

    @staticmethod
    def remove_ansi_codes(line):
        return ansi_color_codes.sub(b"", line)

    def build_become_command(self, cmd, shell):
        super().build_become_command(cmd, shell)

        if not cmd:
            return cmd

        become = self.get_option("become_exe")
        flags = self.get_option("become_flags")
        user = self.get_option("become_user")

        return (
            f"{become} --user={user} {flags} {self._build_success_command(cmd, shell)}"
        )

    def check_success(self, b_output):
        b_output = self.remove_ansi_codes(b_output)
        return super().check_success(b_output)

    def check_incorrect_password(self, b_output):
        b_output = self.remove_ansi_codes(b_output)
        return super().check_incorrect_password(b_output)

    def check_missing_password(self, b_output):
        b_output = self.remove_ansi_codes(b_output)
        return super().check_missing_password(b_output)