##########################################################################
#
#  Copyright (c) 2026 - Datatailr Inc.
#  All Rights Reserved.
#
#  This file is part of Datatailr and subject to the terms and conditions
#  defined in 'LICENSE.txt'. Unauthorized copying and/or distribution
#  of this file, in parts or full, via any medium is strictly prohibited.
##########################################################################

from __future__ import annotations
from typing import Optional

from datatailr.wrapper import dt__Kv
from datatailr import ACL


__client__ = dt__Kv()


class KV:
    """
    A distributed key-value store for storing and retrieving configuration data, application settings, and other key-value pairs.

    Note that different environments (dev/pre/prod) have separate key-value stores.

    Each key-value pair can have its own access control list (ACL) to manage permissions for reading and writing.

    Example:
    ```python
    from datatailr import KV, ACL, User, Group, Permission
    kv = KV()
    kv.put("db_url", "postgresql://user:password@host:port/dbname")
    acls = ACL({Permission.READ: [User.get("user1"), Group.get("group1")],
                Permission.WRITE: [User.get("user2")]})
    kv.add_acl("db_url", acls)
    db_url = kv.get("db_url")
    all_keys = kv.ls()
    kv.delete("db_url")
    ```
    """

    def get(self, key: str) -> str:
        """
        Retrieve a value by its key from the key-value store. Note that different environments (dev/pre/prod) have separate key-value stores.

        Args:
            key (str): The key of the value to retrieve.

        Returns:
            str: The value associated with the key.

        Example:
        ```python
        from datatailr import KV
        kv = KV()
        db_url = kv.get("db_url")
        ```
        """
        return __client__.get(key)

    def put(self, key: str, value: str, acl: Optional[ACL] = None) -> None:
        """
        Store a key-value pair in the key-value store. Note that different environments (dev/pre/prod) have separate key-value stores.

        Args:
            key (str): The key under which to store the value.
            value (str): The value to store.
            acl (ACL): The access control list for the key-value pair.

        Returns:
            None

        Example:
        ```python
        from datatailr import KV, ACL, Permission, User, Group
        kv = KV()
        acls = ACL({Permission.READ: [User.get("user1"), Group.get("group1")],
                    Permission.WRITE: [User.get("user2")]})
        kv.put("db_url", "postgresql://user:password@host:port/dbname", acls)
        ```
        """
        if acl is None:
            __client__.put(key, value)
        else:
            __client__.put(key, value, **acl.to_cli_command())
        return None

    def ls(self) -> list[dict[str, str | ACL]]:
        """
        List all keys stored in the key-value store for the current environment (dev/pre/prod).

        Returns:
            list[dict[str, str|ACL]]: A list of all keys in the key-value store along with their ACLs.
        Example:
        ```python
        from datatailr import KV
        kv = KV()
        all_keys = kv.ls()
        ```
        """
        records = __client__.ls(acls=True) or []
        return [
            record | {"acl": ACL.from_dict(record.get("acl", {}))} for record in records
        ]

    def delete(self, key: str) -> None:
        """
        Delete a key-value pair from the key-value store by its key.

        Args:
            key (str): The key of the value to delete.
        Returns:
            None
        Example:
        ```python
        from datatailr import KV
        kv = KV()
        kv.delete("db_url")  # Deletes the key-value pair with key "db_url"
        ```
        """
        __client__.rm(key)
        return None

    def acls(self, key: str) -> ACL:
        """
        Retrieve the access control list (ACL) for a specific key in the key-value store.

        Args:
            key (str): The key for which to retrieve the ACL.

        Returns:
            dict[str, list[str]]: A dictionary containing lists of users/groups with 'read' and 'write' permissions.

        Example:
        ```python
        from datatailr import KV
        kv = KV()
        acl = kv.acls("db_url")
        ```
        """
        acl: dict[str, list[int]] = __client__.acls(key) or {}
        return ACL.from_dict(acl)

    def add_acl(self, key: str, acls: ACL) -> None:
        """
        Add an entry to the access control list (ACL) for a specific key in the key-value store.

        Args:
            key (str): The key for which to add the ACL entry.
            entity (str): The user or group to which the permission is granted.
            permission (str): The permission to grant ('read' or 'write').

        Returns:
            None

        Example:
        ```python
        from datatailr import KV, ACL
        kv = KV()
        acls = ACL(read=["user1", "group1"], write=["user2"])
        kv.add_acl("db_url", acls)
        ```
        """
        __client__.add_acls(key, **acls.to_cli_command())
        return None

    def set_acls(self, key: str, acls: ACL) -> None:
        """
        Set the access control list (ACL) for a specific key in the key-value store, replacing any existing ACL entries.

        Args:
            key (str): The key for which to set the ACL.
            entity (str): The user or group for which to set the permission.
            permission (str): The permission to set ('read' or 'write').

        Returns:
            None

        Example:
        ```python
        from datatailr import KV, ACL
        kv = KV()
        acls = ACL(read=["user1", "group1"], write=["user2"])
        kv.set_acls("db_url", acls)
        ```
        """
        __client__.set_acls(key, **acls.to_cli_command())
        return None
