% 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-core-sidenote.sty
% Sidenote (侧批) support for vertical typesetting
% This is a subpackage of luatex_cn
%
\RequirePackage{core/luatex-cn-core-base}
\RequirePackage{expl3}
\RequirePackage{xparse}
\ProvidesExplPackage {core/luatex-cn-core-sidenote} {2026/08/07} {0.4.1} {Sidenote Support for Vertical Typesetting}

% Define keys for Sidenote
\bool_new:N \l__luatexcn_sidenote_on_bool
\tl_new:N \l__luatexcn_sidenote_yshift_tl
\tl_new:N \l__luatexcn_sidenote_xshift_tl
\tl_new:N \l__luatexcn_sidenote_grid_height_tl
\tl_new:N \l__luatexcn_sidenote_font_size_tl
\tl_new:N \l__luatexcn_sidenote_color_tl
\tl_new:N \l__luatexcn_sidenote_padding_top_tl
\tl_new:N \l__luatexcn_sidenote_padding_bottom_tl
\tl_new:N \l__luatexcn_sidenote_bgcolor_tl

\keys_define:nn { luatexcn / sidenote }
  {
    sidenote .bool_set:N = \l__luatexcn_sidenote_on_bool,
    sidenote .initial:n = true,
    sidenote .default:n = true,
    yshift .tl_set:N = \l__luatexcn_sidenote_yshift_tl,
    yshift .initial:n = 0pt,
    xshift .tl_set:N = \l__luatexcn_sidenote_xshift_tl,
    xshift .initial:n = 0pt,
    grid-height .tl_set:N = \l__luatexcn_sidenote_grid_height_tl,
    font-size .tl_set:N = \l__luatexcn_sidenote_font_size_tl,
    font-size .initial:n = 10pt,
    color .tl_set:N = \l__luatexcn_sidenote_color_tl,
    color .initial:n = red,
    column-padding-top .tl_set:N = \l__luatexcn_sidenote_padding_top_tl,
    column-padding-top .initial:n = 0pt,
    column-padding-bottom .tl_set:N = \l__luatexcn_sidenote_padding_bottom_tl,
    column-padding-bottom .initial:n = 0pt,
    background-color .tl_set:N = \l__luatexcn_sidenote_bgcolor_tl,
    background-color .initial:n = ,
    % Forward unknown keys: try settings first, then style
    unknown .code:n =
      {
        \exp_args:Nnx \keys_if_exist:nnTF { luatexcn / settings } { \l_keys_key_str }
          { \keys_set:nx { luatexcn / settings } { \l_keys_key_str = { \exp_not:n {#1} } } }
          {
            \exp_args:Nnx \keys_if_exist:nnTF { luatexcn / style } { \l_keys_key_str }
              { \keys_set:nx { luatexcn / style } { \l_keys_key_str = { \exp_not:n {#1} } } }
              { }
          }
      },
  }

\NewDocumentCommand{\sidenoteSetup}{ m }
  {
    \keys_set:nn { luatexcn / sidenote } { #1 }
  }

\NewDocumentCommand{\Sidenote}{ O{} +m }{%
  \bool_if:NT \l__luatexcn_sidenote_on_bool
    {
      \group_begin:
        % Process optional argument: handle positional parameter (plain number → em)
        \tl_if_empty:nTF { #1 }
          {
            % Empty argument: no special processing needed
          }
          {
            % Check if it's a plain number by attempting regex match
            \regex_match:nnTF { ^\d+(?:\.\d+)?$ } { #1 }
              {
                % Plain number: convert to em
                \tl_set:Nn \l_tmpa_tl { yshift = #1 em }
                \keys_set:nn { luatexcn / sidenote } { yshift = #1 em }
              }
              {
                % Not a plain number: check if it has '='
                \regex_match:nnTF { = } { #1 }
                  {
                    % Contains '=': use as-is (named parameter like color=red)
                    \keys_set:nn { luatexcn / sidenote } { #1 }
                  }
                  {
                    % No '=': treat as positional yshift with units
                    \keys_set:nn { luatexcn / sidenote } { yshift = #1 }
                  }
              }
          }
        % If #1 was empty, no keys to set (use defaults)
        % Use explicit font size
        \tl_if_empty:NTF \l__luatexcn_sidenote_font_size_tl
          { \dim_set:Nn \l_tmpa_dim { \f@size pt } }
          { \dim_set:Nn \l_tmpa_dim { \__luatexcn_to_dimen:n { \l__luatexcn_sidenote_font_size_tl } } }
        \fontsize{\l_tmpa_dim}{\l_tmpa_dim}\selectfont
        % DO NOT use \textcolor here - it creates pdf_colorstack nodes that cause
        % color leakage when sidenotes span across page boundaries.
        % Color is handled entirely in the Lua render layer via PDF literals.
        \hbox_set:Nn \l_tmpa_box {#2}%

        % Prepare metadata
        \dim_set:Nn \l_tmpb_dim { \__luatexcn_to_dimen:n { \l__luatexcn_sidenote_grid_height_tl } }
        % If grid-height not set, default to font size (tight packing)
        \dim_compare:nF { \l_tmpb_dim > 0pt } { \dim_set_eq:NN \l_tmpb_dim \l_tmpa_dim }

        % Pass style attributes to Lua (style registration handled in Lua layer)
        \lua_now:e { vertical_sidenote.register_sidenote(\int_value:w \l_tmpa_box, {
          yshift = vertical_constants.to_dimen([=[\luaescapestring{\tl_use:N \l__luatexcn_sidenote_yshift_tl}]=]) ~ or ~ 0,
          xshift = vertical_constants.to_dimen([=[\luaescapestring{\tl_use:N \l__luatexcn_sidenote_xshift_tl}]=]) ~ or ~ 0,
          grid_height = \int_value:w \l_tmpb_dim,
          padding_top = vertical_constants.to_dimen([=[\luaescapestring{\tl_use:N \l__luatexcn_sidenote_padding_top_tl}]=]) ~ or ~ 0,
          padding_bottom = vertical_constants.to_dimen([=[\luaescapestring{\tl_use:N \l__luatexcn_sidenote_padding_bottom_tl}]=]) ~ or ~ 0,
          font_color = [=[\luaescapestring{\tl_use:N \l__luatexcn_sidenote_color_tl}]=],
          font_size = [=[\luaescapestring{\dim_use:N \l_tmpa_dim}]=],
          background_color = [=[\luaescapestring{\tl_use:N \l__luatexcn_sidenote_bgcolor_tl}]=],
          punct_mode = [=[\luaescapestring{\tl_use:N \l__luatexcn_settings_punct_mode_tl}]=],
          punct_style = [=[\luaescapestring{\tl_use:N \l__luatexcn_settings_punct_style_tl}]=]
        })}%
      \group_end:
    }
}

\ExplSyntaxOff%

% ============================================================
% Chinese aliases / 中文别名
% ============================================================
% Simplified Chinese / 简体
\NewCommandCopy{\侧批}{\Sidenote}
\NewCommandCopy{\CePi}{\Sidenote}
\NewCommandCopy{\侧批设置}{\sidenoteSetup}
% Traditional Chinese / 繁体
\NewCommandCopy{\側批}{\Sidenote}
\NewCommandCopy{\側批設置}{\sidenoteSetup}

% ============================================================
% Chinese key aliases / 中文 Key 别名
% ============================================================
\ExplSyntaxOn
\keys_define:nn { luatexcn / sidenote }
  {
    % 简体
    侧批 .bool_set:N = \l__luatexcn_sidenote_on_bool,
    侧批 .default:n = true,
    纵移 .tl_set:N = \l__luatexcn_sidenote_yshift_tl,
    横移 .tl_set:N = \l__luatexcn_sidenote_xshift_tl,
    格高 .tl_set:N = \l__luatexcn_sidenote_grid_height_tl,
    字号 .tl_set:N = \l__luatexcn_sidenote_font_size_tl,
    颜色 .tl_set:N = \l__luatexcn_sidenote_color_tl,
    栏上填充 .tl_set:N = \l__luatexcn_sidenote_padding_top_tl,
    栏下填充 .tl_set:N = \l__luatexcn_sidenote_padding_bottom_tl,
    底色 .tl_set:N = \l__luatexcn_sidenote_bgcolor_tl,
    背景色 .tl_set:N = \l__luatexcn_sidenote_bgcolor_tl,
    % 繁体（与简体不同形的）
    側批 .bool_set:N = \l__luatexcn_sidenote_on_bool,
    側批 .default:n = true,
    縱移 .tl_set:N = \l__luatexcn_sidenote_yshift_tl,
    橫移 .tl_set:N = \l__luatexcn_sidenote_xshift_tl,
    字號 .tl_set:N = \l__luatexcn_sidenote_font_size_tl,
    顏色 .tl_set:N = \l__luatexcn_sidenote_color_tl,
    背景色 .tl_set:N = \l__luatexcn_sidenote_bgcolor_tl,
  }
\ExplSyntaxOff

\endinput%
