"""
Directory-related rendering helpers for the gallery view.
"""

# Standard library imports.
from pathlib import Path

# Django imports.
from django.http import HttpResponseNotFound
from django.shortcuts import render
from django.conf import settings

# Project imports.
from .common import (
    normalize_sort,
    normalize_theme,
    build_query,
    gallery_url,
    append_query,
    sort_images,
    build_sort_options,
    build_breadcrumbs,
    get_first_image_thumbnail_url,
    is_image_file,
    make_thumbnail,
)
from .specials import get_special_paths, special_name


def do_recursive_search(start_path, query):
    """
    Gets all images and sub-directories inside the start_path whose name matches the given query,
    and then joins the results recursively by iterating in each sub-directory.
    """

    try:
        entries = [entry for entry in start_path.iterdir() if not entry.is_symlink()]
    except OSError:
        return [], []

    all_subdirs = sorted(
        [entry for entry in entries if entry.is_dir()],
        key=lambda item: (item.name.lower(), str(item).lower()),
    )

    subdirs = [entry for entry in all_subdirs if query.lower() in entry.name.lower()]

    images = sorted(
        [
            entry
            for entry in entries
            if entry.is_file()
            and is_image_file(entry)
            and query.lower() in entry.name.lower()
        ],
        key=lambda item: (item.name.lower(), str(item).lower()),
    )

    for subdir in all_subdirs:
        rec_subdirs, rec_images = do_recursive_search(subdir, query.lower())
        subdirs.extend(rec_subdirs)
        images.extend(rec_images)

    return subdirs, images


def render_directory(request, path_text, full_path, special=None):
    """
    Renders the gallery view related to directories, be it the contents of an actual directory
    in the file system, or logical gallery directories like search result pages.
    """

    # Search remains a GET parameter. For sort and theme prefer explicit
    # GET parameters when present (so query-preserving links behave as
    # callers expect), otherwise fall back to middleware-provided settings.
    search_text = request.GET.get("search", "").strip()
    sort_key = normalize_sort(
        request.GET.get("sort") or getattr(request, "sort", None) or "abc"
    )
    theme = normalize_theme(
        request.GET.get("theme") or getattr(request, "theme", None) or "dark"
    )
    query_state = build_query(search_text)

    # If rendering a logical special gallery, obtain the image list from the
    # Image model and skip filesystem subdir enumeration.
    if special is not None:
        # build images using the helper that returns Path objects
        images = get_special_paths(request.user, special)
        # Respect the client's sort_key only if the special is favorites
        # otherwise the ordering comes from the DB query (most-visited/recent).
        if special == "favorites":
            images = sort_images(images, sort_key)
        current_subdirs = []
    else:
        try:
            current_entries = [
                entry for entry in full_path.iterdir() if not entry.is_symlink()
            ]
        except OSError:
            return HttpResponseNotFound("Not found")

        current_subdirs = sorted(
            [entry for entry in current_entries if entry.is_dir()],
            key=lambda item: (
                item.name.lower(),
                str(item.relative_to(settings.GALLERY_ROOT)).lower(),
            ),
        )

        if search_text == "":
            images = [
                entry
                for entry in current_entries
                if entry.is_file() and is_image_file(entry)
            ]
        else:
            _, images = do_recursive_search(full_path, search_text)

        images = sort_images(images, sort_key)

    image_data = []
    for image in images:
        rel_path = image.relative_to(settings.GALLERY_ROOT)
        image_url = gallery_url(rel_path, False, query_state, special)

        thumbnail = None
        try:
            # use shared make_thumbnail so tests can patch viewer.common.make_thumbnail
            make_thumbnail(image)
            thumb_path = settings.THUMBNAILS_ROOT.joinpath(rel_path)
            if thumb_path.exists():
                thumbnail = "/thumbs/" + str(rel_path).replace("\\", "/")
        except Exception:
            pass

        image_data.append(
            {"path": image_url, "name": image.name, "thumbnail": thumbnail}
        )

    subdir_data = []
    for subdir in current_subdirs:
        rel_path = subdir.relative_to(settings.GALLERY_ROOT)
        subdir_data.append(
            {
                "path": gallery_url(rel_path, True, query_state),
                "name": subdir.name,
                "thumbnail": get_first_image_thumbnail_url(subdir),
            }
        )

    next_theme = "light" if theme == "dark" else "dark"

    # The theme toggle button now calls the persistent settings endpoint.
    # Include `next` (for redirect back) and also surface `sort` and `search`
    # as top-level query parameters so templates/tests can inspect them easily.
    theme_toggle_query = {
        "next": request.get_full_path(),
        "theme": next_theme,
        "sort": sort_key,
    }

    if search_text != "":
        theme_toggle_query["search"] = search_text

    search_action_query = {"sort": sort_key, "theme": theme}

    # Back (directory) and Home (root) links and thumbnails
    dir_rel = None
    try:
        # derive directory path text relative to gallery root
        dir_rel = full_path.parent.relative_to(settings.GALLERY_ROOT)
        dir_text = str(dir_rel).replace("\\", "/")
    except Exception:
        dir_text = ""

    # For special galleries hide the Back control but still present Home
    if special is not None:
        back_url = None
        back_thumb = None
    else:
        back_url = gallery_url(
            Path(dir_text) if dir_text != "" else None, True, query_state
        )
        back_thumb = get_first_image_thumbnail_url(full_path.parent)
    home_url = gallery_url(None, True, query_state)
    home_thumb = get_first_image_thumbnail_url(settings.GALLERY_ROOT)

    context = {
        "path": path_text,
        "search_text": search_text,
        "theme": theme,
        "sort_key": sort_key,
        "sort_label": "",
        "sort_options": build_sort_options(request, search_text, sort_key, theme),
        "breadcrumbs": build_breadcrumbs(path_text, query_state),
        "images": image_data,
        "subdirs": subdir_data,
        "back_url": back_url,
        "back_thumb": back_thumb,
        "home_url": home_url,
        "home_thumb": home_thumb,
        "theme_toggle_url": append_query(
            "/gallery/toggle-settings/", theme_toggle_query
        ),
        "search_action_url": gallery_url(
            Path(path_text) if path_text != "" else None, True, search_action_query
        ),
        "clear_search_url": gallery_url(
            Path(path_text) if path_text != "" else None, True, None
        ),
    }

    # When rendering a special gallery adjust breadcrumbs and hide search
    # and back controls. Use `is_special` and `special_name` in the template.
    if special is not None:
        context["is_special"] = True
        context["special_name"] = special_name(special)
        # expose which special is active so templates can highlight it
        context["active_special"] = special
        # Override breadcrumbs for special galleries to be a single label
        # and make it link to the special gallery root so templates can show
        # it as an active, clickable breadcrumb.
        from .specials import special_root_url

        context["breadcrumbs"] = [
            {
                "label": context["special_name"],
                "path": special_root_url(special, query_state),
            }
        ]
        # Hide the search box (templates use `is_special` to decide)
        context["search_text"] = ""
        context["search_action_url"] = ""
        context["clear_search_url"] = ""

    # sort_label depends on SORT_LABELS in common; import lazily to avoid circulars
    from .common import SORT_LABELS

    context["sort_label"] = SORT_LABELS.get(sort_key, "")

    return render(request, "gallery_view.html", context)
