{{- /*
  Renders an interactive file tree structure from inline content, resources, data files, or filesystem
  See https://fixit.lruihao.cn/documentation/content-management/shortcodes/extended/file-tree/

  @param {String} [path="/"] - The path to scan in filesystem (relative to project root or contentDir)
  @param {Int} [level=1] - The expand level of the tree (expand all: -1, collapse all: 0)
  @param {Boolean} [folder_slash=false] - Whether to append a trailing "/" to folder names.
  @param {String} [file] - The path of a data file in page resources or assets. (JSON/YAML/TOML)
  @param {String} [data] - The name of the data file in data/filetree/ directory. (JSON/YAML/TOML)
  @param {String} [ignore_list=""] - List of file or folder names to ignore, separated by commas
  @param {String} [highlight_list=""] - List of file or folder names to highlight, separated by commas
  @param {String} [name] - Project name for the root node, if set to `{path}`, uses the full root path

  Priority order (highest to lowest):
  1. Inline content (shortcode body) - Parse tree data from shortcode body
  2. Resources files (file parameter) - Read data file from page bundle or asset
  3. Data files (data parameter) - Load data file from data/filetree/ directory
  4. Actual Filesystem (path parameter) - Scan actual directory structure (default)

  Fallback mechanism: If the current mode fails (e.g., file not found, invalid format),
  the shortcode will automatically fall back to the next available mode in the priority order.

  @example
  {{< file-tree "content" 2 />}}
  {{< file-tree path="content" level=2 folder_slash=true />}}
  {{< file-tree file="data/example.yml" />}}
  {{< file-tree data="example" />}}
  {{< file-tree >}}
  - name: my-project
    type: dir
    children:
      - name: src
        type: dir
      - name: package.json
        type: file
  {{< /file-tree >}}

  Data format note: YAML and JSON support direct array format, while TOML requires a root key 'filetree' due to format limitations.
  Example TOML structure:
  ```file-tree
  [[filetree]]
  name = "src"
  type = "dir"

  [[filetree.children]]
  name = "index.ts"
  type = "file"

  [[filetree]]
  name = "README.md"
  type = "file"
  ```
*/ -}}

{{- $config := dict "Page" .Page "Key" "filetree" | partial "function/param.html" -}}
{{- $root := cond .IsNamedParams (.Get "path") (.Get 0) | default "/" -}}
{{- $level := cond .IsNamedParams (.Get "level") (.Get 1) -}}
{{- $config = cond ((eq $level 0) | or $level) (dict "level" $level | merge $config) $config -}}
{{- $level = cond (isset $config "level") ($config.level | int) 1 -}}
{{- $folderSlash := cond .IsNamedParams (.Get "folder_slash" | default (.Get "folderSlash")) (.Get 2) | default $config.folder_slash | default false -}}
{{- if .IsNamedParams | and (.Get "folderSlash") -}}
  {{- warnidf "v1-deprecated-file-tree-param" "[%s]: The parameter `folderSlash` is deprecated since v1.0.0, use `folder_slash` instead. See %s" .Name .Position -}}
{{- end -}}
{{- $fileName := .Get "file" -}}
{{- $dataName := .Get "data" -}}
{{- $supportExts := slice ".yml" ".yaml" ".json" ".toml" -}}
{{- $ignoreList := union (apply (split (.Get "ignore_list" | default (.Get "ignoreList") | default "") ",") "trim" "." " ") $config.ignore_list -}}
{{- $highlightList := union (apply (split (.Get "highlight_list" | default (.Get "highlightList") | default "") ",") "trim" "." " ") $config.highlight_list -}}
{{- if .IsNamedParams | and (.Get "ignoreList") -}}
  {{- warnidf "v1-deprecated-file-tree-param" "[%s]: The parameter `ignoreList` is deprecated since v1.0.0, use `ignore_list` instead. See %s" .Name .Position -}}
{{- end -}}
{{- if .IsNamedParams | and (.Get "highlightList") -}}
  {{- warnidf "v1-deprecated-file-tree-param" "[%s]: The parameter `highlightList` is deprecated since v1.0.0, use `highlight_list` instead. See %s" .Name .Position -}}
{{- end -}}

{{- /* Shortcode body */ -}}
{{- $content := strings.TrimSpace .Inner | default "" -}}
{{- /* File Data */ -}}
{{- if $fileName | and (eq $content "") -}}
  {{- $ext := path.Ext $fileName | lower -}}
  {{- if in $supportExts $ext -}}
    {{- with dict "Path" $fileName "Resources" $.Page.Resources | partial "function/resource.html" }}
      {{- $content = .Content -}}
    {{- else -}}
      {{- warnidf "warning-file-tree" "[%s]: no such data file: %s. See %s" $.Name $fileName $.Position -}}
    {{- end -}}
  {{- else -}}
    {{- warnidf "warning-file-tree" "[%s]: Unsupported file format '%s'. Use %s. See %s" $.Name $ext (delimit $supportExts ", " " or ") $.Position -}}
  {{- end -}}
{{- end -}}

{{- /* Parse structured data from content or file */ -}}
{{- $treeData := slice -}}
{{- with $content -}}
  {{- $treeData = . | unmarshal -}}
  {{- if reflect.IsMap $treeData -}}
    {{- $treeData = $treeData.filetree -}}
  {{- end -}}
{{- end -}}

{{- /* Hugo Data: load from data/filetree/ */ -}}
{{- if $dataName | and (not $treeData) -}}
  {{- with index hugo.Data.filetree (printf "%v.%v" $dataName .Page.Language) | default (index hugo.Data.filetree $dataName) -}}
    {{- $treeData = . -}}
  {{- else -}}
    {{- $exts := delimit (apply $supportExts "trim" "." "\\.") "|" -}}
    {{- warnidf "warning-file-tree" "[%s]: Data file 'data/filetree/%s.{%s}' not found. See %s" $.Name $dataName $exts $.Position -}}
  {{- end -}}
{{- end -}}

{{- /* Filesystem mode: build structured tree data from filesystem */ -}}
{{- if not $treeData -}}
  {{- $buildOptions := dict "root" $root "ignore_list" $ignoreList "name" (.Get "name") "lang" .Page.Language -}}
  {{- with partial "function/get-file-tree.html" $buildOptions -}}
    {{- $treeData = . -}}
  {{- else -}}
    {{- warnidf "warning-file-tree" "[%s]: The root path does not exist: %s. See %s" .Name $root .Position -}}
  {{- end -}}
{{- end -}}

{{- /* Render the file tree */ -}}
{{- $options := dict
  "items" $treeData
  "level" $level
  "folder_slash" $folderSlash
  "ignore_list" $ignoreList
  "highlight_list" $highlightList
-}}
{{- partial "plugin/file-tree.html" $options -}}
