import logging
import stat
import sys
from pathlib import Path
from typing import Any, Dict, List

from clarabot_nano_common.server.general.handler.filesystem.utility import add_disk_usage

logger = logging.getLogger(__name__)


def list_admin_roots(roots: List[str]) -> List[Dict[str, Any]]:
    """
    Create entries of root items.
    NOTE: if this is changed ls_admin_entry_size() must be modified accordingly!
    """
    rs = []
    for r in roots:
        p = Path(r)
        e = {"name": r}
        try:
            s = p.stat()
        except OSError:
            e["unresolved"] = True
        else:
            if not stat.S_ISDIR(s.st_mode):
                continue
            e["mtime"] = s.st_mtime
            if sys.platform.startswith("win") or p.is_mount():
                add_disk_usage(p, e)
        rs.append(e)
    return rs


def list_admin_directory(parent: Path) -> List[Dict[str, Any]]:
    """
    Create entries of the items in a directory for the admin to create a new drive.
    Only directories are listed and capacity info is added for mount-points (on not windows).
    NOTE: if this is changed ls_admin_entry_size() must be modified accordingly!
    """
    p_iter = iter(parent.iterdir())
    try:
        p = next(p_iter)
    except StopIteration:
        return []
    es = []
    if sys.platform.startswith("win"):
        parent_dev = None
    else:
        parent_dev = parent.stat().st_dev
    while True:
        e = {"name": p.name}
        try:
            s = p.stat()
        except OSError:
            e["unresolved"] = True
            es.append(e)
        else:
            if stat.S_ISDIR(s.st_mode):
                e["mtime"] = s.st_mtime
                if parent_dev is not None and parent_dev != s.st_dev:
                    add_disk_usage(p, e)
                es.append(e)
        try:
            p = next(p_iter)
        except StopIteration:
            break
    return es


def ls_admin_entry_size(item: dict) -> int:
    """
    To be used with items from list_admin_directory() or list_admin_roots() with _approximate_part_slicing().
    Each field is approximated: (+1 for root)
        name: 6 + actual encoded length of the name
        mtime: 15
        total+free: 29 if present
    NOTE: extra length indicating the size of name is not accounted for.
    """
    return 21 + len(item["name"].encode("utf-8")) + (29 if "total" in item else 0)
