% Copyright 2026 Open-Guji (https://github.com/open-guji)
%
% Licensed under the Apache License, Version 2.0 (the "License");
% you may not use this file except in compliance with the License.
% You may obtain a copy of the License at
%
%     http://www.apache.org/licenses/LICENSE-2.0
%
% Unless required by applicable law or agreed to in writing, software
% distributed under the License is distributed on an "AS IS" BASIS,
% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
% See the License for the specific language governing permissions and
% limitations under the License.
% luatex-cn-footnote.sty
% Footnote/Jiaokan (脚注/校勘记) support for vertical typesetting
% Mode 1: Endnotes (段末注) - footnotes output at paragraph end
% Mode 2: Page footnotes (页下注) - footnotes at page left with separator
%
\RequirePackage{expl3}
\RequirePackage{xparse}
\ProvidesExplPackage {core/luatex-cn-footnote} {2026/08/07} {0.4.1} {Footnote/Jiaokan support}

% ============================================================================
% Load Lua module and set global utils
% ============================================================================
\lua_now:e {
  require('core.luatex-cn-footnote')
  vertical_utils = require('util.luatex-cn-utils')
}

% ============================================================================
% Key-value Configuration
% ============================================================================
\tl_new:N \l__luatexcn_footnote_mode_tl
\tl_new:N \l__luatexcn_footnote_number_style_tl
\tl_new:N \l__luatexcn_footnote_separator_tl
\tl_new:N \l__luatexcn_footnote_font_tl
\tl_new:N \l__luatexcn_footnote_font_size_tl
\tl_new:N \l__luatexcn_footnote_font_color_tl

\keys_define:nn { luatexcn / footnote }
  {
    mode .tl_set:N = \l__luatexcn_footnote_mode_tl,
    mode .initial:n = {endnote},
    number-style .tl_set:N = \l__luatexcn_footnote_number_style_tl,
    number-style .initial:n = {lujiao},
    separator .tl_set:N = \l__luatexcn_footnote_separator_tl,
    separator .initial:n = {blank},
    font .tl_set:N = \l__luatexcn_footnote_font_tl,
    font .initial:n = {},
    font-size .tl_set:N = \l__luatexcn_footnote_font_size_tl,
    font-size .initial:n = {0.8em},
    font-color .tl_set:N = \l__luatexcn_footnote_font_color_tl,
    font-color .initial:n = {},
    indent .int_set:N = \l__luatexcn_footnote_indent_int,
    indent .initial:n = {2},
    spacing .dim_set:N = \l__luatexcn_footnote_spacing_dim,
    spacing .initial:n = {0.5em},
    marker-height .int_set:N = \l__luatexcn_footnote_marker_height_int,
    marker-height .initial:n = {2},
    counter-start .code:n = { \int_gset:Nn \g__luatexcn_footnote_counter_int { #1 } },
  }

% ============================================================================
% Internal: Apply footnote font size (always from content base font-size)
% ============================================================================
\dim_new:N \l__luatexcn_footnote_resolved_size_dim
\cs_new_protected:Nn \__luatexcn_footnote_apply_font_size:
  {
    % First, temporarily set font to base content size so that relative units
    % (like 0.8em) resolve correctly against the base, not the current font.
    \fontsize { \l__luatexcn_content_font_size_tl } { \l__luatexcn_content_font_size_tl } \selectfont
    % Now resolve the footnote font-size (may contain em units)
    \dim_set:Nn \l__luatexcn_footnote_resolved_size_dim
      { \l__luatexcn_footnote_font_size_tl }
    % Apply the resolved absolute size
    \fontsize
      { \dim_use:N \l__luatexcn_footnote_resolved_size_dim }
      { \dim_use:N \l__luatexcn_footnote_resolved_size_dim }
    \selectfont
  }

% ============================================================================
% Global Storage (Mode 1)
% ============================================================================
\seq_new:N  \g__luatexcn_footnote_content_seq
\int_new:N  \g__luatexcn_footnote_counter_int
\box_new:N  \l__luatexcn_footnote_temp_box

% ============================================================================
% Setup Command (syncs to Lua _G.footnote)
% ============================================================================
\NewDocumentCommand{\footnoteSetup}{ m }
  {
    \keys_set:nn { luatexcn / footnote } { #1 }
    \lua_now:e {
      _G.footnote = _G.footnote~or~{}
      _G.footnote.mode = "\l__luatexcn_footnote_mode_tl"
      _G.footnote.number_style = "\l__luatexcn_footnote_number_style_tl"
      _G.footnote.font_size = "\l__luatexcn_footnote_font_size_tl"
      _G.footnote.font_color = "\l__luatexcn_footnote_font_color_tl"
      _G.footnote.font = "\l__luatexcn_footnote_font_tl"
    }
  }

% ============================================================================
% Internal: Write Footnote Marker Text (【一】 or ①)
% ============================================================================
\cs_new:Nn \__luatexcn_footnote_write_marker_text:n
  {
    \str_case:VnF \l__luatexcn_footnote_number_style_tl
      {
        {lujiao}  { 【\lua_now:e{ tex.print(vertical_utils.to_chinese_numeral(#1)) }】 }
        {circled} { \lua_now:e{ tex.print(vertical_utils.to_circled_numeral(#1)) } }
      }
      { 【\lua_now:e{ tex.print(vertical_utils.to_chinese_numeral(#1)) }】 }
  }

% ============================================================================
% Internal: Render Footnote Marker (unified for inline and flush)
% #1 = footnote number, #2 = halign (3=right for inline, 0=center for flush)
% Sets font size, ATTR_FOOTNOTE_MARKER, ATTR_HALIGN, outputs marker text,
% then clears attributes. Marker chars have no inter-char gap and are not
% stretched/compressed by the layout engine.
% ============================================================================
\cs_new_protected:Nn \__luatexcn_footnote_render_marker:nn
  {
    \group_begin:
      \tl_if_empty:NF \l__luatexcn_footnote_font_size_tl
        { \__luatexcn_footnote_apply_font_size: }
      \lua_now:e {
        local~c~=~require('core.luatex-cn-constants')
        local~fn_h~=~\dim_to_decimal_in_sp:n { \l__luatexcn_footnote_resolved_size_dim }
        local~total_sp~=~math.floor(\int_use:N \l__luatexcn_footnote_marker_height_int ~*~fn_h)
        tex.setattribute(c.ATTR_FOOTNOTE_MARKER,~total_sp)
        local~ha~=~#2
        if~ha~>~0~then~tex.setattribute(c.ATTR_HALIGN,~ha)~end
      }
      \__luatexcn_footnote_write_marker_text:n { #1 }
      \lua_now:e {
        local~c~=~require('core.luatex-cn-constants')
        tex.setattribute(c.ATTR_FOOTNOTE_MARKER,~-2147483647)
      }
    \group_end:
  }

% ============================================================================
% Internal: Separator (blank space or none)
% ============================================================================
\cs_new:Nn \__luatexcn_footnote_separator:
  {
    \str_case:VnF \l__luatexcn_footnote_separator_tl
      {
        {blank} { \hspace{1em} }
        {none}  { }
      }
      { \hspace{1em} }
  }

% ============================================================================
% \Footnote{content} - Store content + write inline marker
% Mode 1: Store in expl3 sequence
% Mode 2: Register in Lua and write WHATSIT anchor
% ============================================================================
\NewDocumentCommand{\Footnote}{ O{} +m }
  {
    \group_begin:
      \int_gincr:N \g__luatexcn_footnote_counter_int
      \str_if_eq:VnTF \l__luatexcn_footnote_mode_tl {page}
        {
          % Mode 2: Register in Lua for page rendering
          \hbox_set:Nn \l__luatexcn_footnote_temp_box { #2 }
          \lua_now:e {
            local~footnote~=~require('core.luatex-cn-footnote')
            footnote.register_footnote(
              \int_use:N \l__luatexcn_footnote_temp_box,
              \int_use:N \g__luatexcn_footnote_counter_int
            )
          }
        }
        {
          % Mode 1: Store in sequence for paragraph-end output
          \seq_gput_right:Nn \g__luatexcn_footnote_content_seq { #2 }
        }
      % Write inline marker (right-aligned, same rendering as flush marker)
      \__luatexcn_footnote_render_marker:nn
        { \int_use:N \g__luatexcn_footnote_counter_int } { 3 }
    \group_end:
  }

% ============================================================================
% \FlushFootnote - Output all footnotes and reset (Mode 1 only)
% ============================================================================
\NewDocumentCommand{\FlushFootnote}{}
  {
    \str_if_eq:VnF \l__luatexcn_footnote_mode_tl {page}
      {
        \int_compare:nNnT
          { \seq_count:N \g__luatexcn_footnote_content_seq } > { 0 }
          {
            % No separator before footnotes: the column break (from synthetic penalty
            % or \penalty -10002) already provides visual separation, and \hspace creates
            % an unwanted empty column in vertical layout.
            % Group to contain font-size change (prevent leaking to subsequent text)
            \group_begin:
            % Apply footnote font-size (absolute value from content base font-size)
            \tl_if_empty:NF \l__luatexcn_footnote_font_size_tl
              {
                \__luatexcn_footnote_apply_font_size:
              }
            \int_step_inline:nn
              { \seq_count:N \g__luatexcn_footnote_content_seq }
              {
                % Hanging indent: all sizes in footnote-grid units (= footnote font size).
                % indent (int) = leading blank cells, marker-height (int) = marker cells.
                % Convert to float content-grid-cells for the layout engine.
                \lua_now:e {
                  local~constants~=~require('core.luatex-cn-constants')~
                  local~sr~=~require('util.luatex-cn-style-registry')~
                  local~fn_grid_h~=~\dim_to_decimal_in_sp:n { \l__luatexcn_footnote_resolved_size_dim }~
                  local~content_grid_h~=~\dim_to_decimal_in_sp:n { \l__luatexcn_content_grid_height_tl }~
                  local~indent_fn~=~\int_use:N \l__luatexcn_footnote_indent_int ~
                  local~marker_fn~=~\int_use:N \l__luatexcn_footnote_marker_height_int ~
                  local~hang_fn~=~indent_fn~+~marker_fn~+~0.2~
                  local~first_float~=~indent_fn~*~fn_grid_h~/~content_grid_h~
                  local~hang_float~=~hang_fn~*~fn_grid_h~/~content_grid_h~
                  local~sid~=~sr.push_indent(hang_float,~first_float)~
                  tex.setattribute(constants.ATTR_STYLE_REG_ID,~sid)~
                  tex.setattribute(constants.ATTR_INDENT,~0)~
                  tex.setattribute(constants.ATTR_FIRST_INDENT,~-1)
                }
                \int_gincr:N \g_luatexcn_paragraph_block_id_int
                \setluatexattribute\cnverticalblockid
                  { \int_use:N \g_luatexcn_paragraph_block_id_int }
                \penalty -10002\relax
                % Render marker (center-aligned, unified with inline marker)
                \__luatexcn_footnote_render_marker:nn { ##1 } { 0 }
                \seq_item:Nn \g__luatexcn_footnote_content_seq { ##1 }
                \lua_now:e {
                  local~sr~=~require('util.luatex-cn-style-registry')
                  sr.pop()
                }
              }
            \group_end:
            \seq_gclear:N \g__luatexcn_footnote_content_seq
            \int_gzero:N  \g__luatexcn_footnote_counter_int
          }
      }
  }

% ============================================================================
% \ResetFootnoteCounter - Reset counter (for Mode 2 per-page reset)
% ============================================================================
\NewDocumentCommand{\ResetFootnoteCounter}{}
  {
    \int_gzero:N \g__luatexcn_footnote_counter_int
  }

% ============================================================================
% \FootnoteParagraph{content} - Unnumbered footnote paragraph
% Outputs content with footnote font-size and indent, but no marker/number.
% Used for standalone annotations (e.g., 索隱 notes) not referenced in main text.
% ============================================================================
\NewDocumentCommand{\FootnoteParagraph}{ +m }
  {
    \group_begin:
      % Apply footnote font-size
      \tl_if_empty:NF \l__luatexcn_footnote_font_size_tl
        { \__luatexcn_footnote_apply_font_size: }
      % Set indent = indent + marker_height (align with numbered footnotes)
      \lua_now:e {
        local~constants~=~require('core.luatex-cn-constants')~
        local~sr~=~require('util.luatex-cn-style-registry')~
        local~fn_grid_h~=~\dim_to_decimal_in_sp:n { \l__luatexcn_footnote_resolved_size_dim }~
        local~content_grid_h~=~\dim_to_decimal_in_sp:n { \l__luatexcn_content_grid_height_tl }~
        local~indent_fn~=~\int_use:N \l__luatexcn_footnote_indent_int ~
        local~marker_fn~=~\int_use:N \l__luatexcn_footnote_marker_height_int ~
        local~total_fn~=~indent_fn~+~marker_fn~+~0.2~
        local~indent_float~=~total_fn~*~fn_grid_h~/~content_grid_h~
        local~sid~=~sr.push_indent(indent_float,~indent_float)~
        tex.setattribute(constants.ATTR_STYLE_REG_ID,~sid)~
        tex.setattribute(constants.ATTR_INDENT,~0)~
        tex.setattribute(constants.ATTR_FIRST_INDENT,~-1)
      }
      % Block ID + force column break
      \int_gincr:N \g_luatexcn_paragraph_block_id_int
      \setluatexattribute\cnverticalblockid
        { \int_use:N \g_luatexcn_paragraph_block_id_int }
      \penalty -10002\relax
      % Output content (no marker)
      #1
      % Pop style
      \lua_now:e {
        local~sr~=~require('util.luatex-cn-style-registry')
        sr.pop()
      }
    \group_end:
  }

\ExplSyntaxOff%

% ============================================================
% Chinese aliases / 中文别名
% ============================================================
% Simplified Chinese / 简体
\NewCommandCopy{\脚注}{\Footnote}
\NewCommandCopy{\输出脚注}{\FlushFootnote}
\NewCommandCopy{\脚注设置}{\footnoteSetup}
\NewCommandCopy{\重置脚注计数}{\ResetFootnoteCounter}
\NewCommandCopy{\脚注段落}{\FootnoteParagraph}
% Traditional Chinese / 繁体
\NewCommandCopy{\腳注}{\Footnote}
\NewCommandCopy{\輸出腳注}{\FlushFootnote}
\NewCommandCopy{\腳注設置}{\footnoteSetup}
\NewCommandCopy{\重置腳注計數}{\ResetFootnoteCounter}
\NewCommandCopy{\腳注段落}{\FootnoteParagraph}

% ============================================================
% Chinese key aliases / 中文 Key 别名
% ============================================================
\ExplSyntaxOn
\keys_define:nn { luatexcn / footnote }
  {
    % 简体
    模式 .tl_set:N = \l__luatexcn_footnote_mode_tl,
    编号样式 .tl_set:N = \l__luatexcn_footnote_number_style_tl,
    分隔符 .tl_set:N = \l__luatexcn_footnote_separator_tl,
    字体 .tl_set:N = \l__luatexcn_footnote_font_tl,
    字号 .tl_set:N = \l__luatexcn_footnote_font_size_tl,
    字体颜色 .tl_set:N = \l__luatexcn_footnote_font_color_tl,
    缩进 .int_set:N = \l__luatexcn_footnote_indent_int,
    间距 .dim_set:N = \l__luatexcn_footnote_spacing_dim,
    序号高度 .int_set:N = \l__luatexcn_footnote_marker_height_int,
    起始编号 .code:n = { \int_gset:Nn \g__luatexcn_footnote_counter_int { #1 } },
    % 繁体（与简体不同形的）
    編號樣式 .tl_set:N = \l__luatexcn_footnote_number_style_tl,
    字體 .tl_set:N = \l__luatexcn_footnote_font_tl,
    字號 .tl_set:N = \l__luatexcn_footnote_font_size_tl,
    字體顏色 .tl_set:N = \l__luatexcn_footnote_font_color_tl,
    縮進 .int_set:N = \l__luatexcn_footnote_indent_int,
    間距 .dim_set:N = \l__luatexcn_footnote_spacing_dim,
    序號高度 .int_set:N = \l__luatexcn_footnote_marker_height_int,
    起始編號 .code:n = { \int_gset:Nn \g__luatexcn_footnote_counter_int { #1 } },
  }
\ExplSyntaxOff

\endinput%
