# -*- coding: utf-8 -*-

from typing import Tuple
from ansible.module_utils.basic import AnsibleModule

DOCUMENTATION = """
module: gsettings
author:
    - Kenneth Benzie (Benie)
short_description: Ansible module for the gsettings configuration tool
options:
    schema:
        description:
            - Schema ID of the settings to configure.
        type: str
    key:
        description:
            - Key of an individaul setting to configure.
        type: str
    value:
        description:
            - Value to configure the setting with.
            - Mutually exclusive with reset.
        type: str
    reset:
        description:
            - Flag to reset the setting to the default value.
            - Mutually exclusive with value.
        type:
        default: false
"""

EXAMPLES = """
- name: get gnome color-scheme current value
  gsettings:
    schema: org.gnome.desktop.interface
    key: color-scheme
  register: color_scheme
- debug: msg={{color_scheme.value}}

- name: set gnome color-scheme to 'prefer-dark'
  gsettings:
    schema: org.gnome.desktop.interface
    key: color-scheme
    value: "'prefer-dark'"

- name: reset gnome color-scheme to default value
  gsettings:
    schema: org.gnome.desktop.interface
    key: color-scheme
    reset: true
"""

RETURN = """
value:
    description: Value of the setting.
    returned: Returned when there is a value.
    type: str
    sample: "'default'"
stderr:
    description: Error output from gsettings.
    returned: Returned when there is an error.
    type: str
    sample: No such key “doesnt-exist”
"""


class GSettingsError(Exception):
    def __init__(self, command, rc, stderr):
        self.command = command
        self.rc = (rc,)
        self.stderr = stderr


def gsettings_get(module: AnsibleModule) -> Tuple[bool, str]:
    command = [
        "gsettings",
        "get",
        module.params["schema"],
        module.params["key"],
    ]
    rc, stdout, stderr = module.run_command(command)
    if rc != 0:
        raise GSettingsError(command, rc, stderr)
    return False, stdout.rstrip()


def gsettings_set(module: AnsibleModule) -> Tuple[bool, str]:
    command = [
        "gsettings",
        "set",
        module.params["schema"],
        module.params["key"],
        module.params["value"],
    ]
    _, before = gsettings_get(module)
    rc, _, stderr = module.run_command(command)
    if rc != 0:
        raise GSettingsError(command, rc, stderr)
    _, after = gsettings_get(module)
    return before != after, after


def gsettings_reset(module: AnsibleModule) -> Tuple[bool, str]:
    command = [
        "gsettings",
        "reset",
        module.params["schema"],
        module.params["key"],
    ]
    _, before = gsettings_get(module)
    rc, stdout, stderr = module.run_command(command)
    if rc != 0:
        raise GSettingsError(command, rc, stderr)
    _, after = gsettings_get(module)
    return before != after, after


def main() -> None:
    module = AnsibleModule(
        argument_spec=dict(
            schema=dict(type="str"),
            key=dict(type="str"),
            value=dict(type="str"),
            reset=dict(type="bool", default=False),
        ),
        mutually_exclusive=[["value", "reset"]],
        required_together=[["schema", "key"]],
    )

    try:
        if module.params["value"]:
            changed, value = gsettings_set(module)
        elif module.params["reset"]:
            changed, value = gsettings_reset(module)
        else:
            changed, value = gsettings_get(module)
        module.exit_json(changed=changed, value=value)
    except GSettingsError as error:
        module.fail_json(
            f"{error.command} failed ({error.rc}): {error.stderr}", stderr=error.stderr
        )


if __name__ == "__main__":
    main()