% Maintained by Matthew Bertucci, 2024-present
% Please report all issues and feature requests at https://github.com/mbertucci47/keytheorems
% This work is licensed under the LPPL version 1.3c or later: https://www.latex-project.org/lppl.txt
\ProvidesExplFile{keythms-beamer-support}{\@keythms@date}{\@keythms@version}
  {keytheorems~support~for~the~beamer~class}

% disable \listofkeytheorems, add warning
\msg_new:nnn { keytheorems } { beamer-listof }
  {
    \protect\listofkeytheorems\space not~supported~with~beamer
  }
\RenewDocumentCommand \listofkeytheorems { +o }
  {
    \msg_warning:nn { keytheorems } { beamer-listof }
  }

% support overlays with noamsthm option, then end input
\IfClassLoadedWithOptionsT{ beamer }{ noamsthm }
  {
    \cs_new_eq:NN \__keythms_beamer_orignewkeythm:nn \keythms_thm_newkeythm:nn
    \cs_set_protected:Npn \keythms_thm_newkeythm:nn #1#2
      {
        \__keythms_beamer_orignewkeythm:nn { #1 } { #2 }
        \NewEnvironmentCopy { keythms_beamer_orig_#1 } { #1 }
        \RenewDocumentEnvironment { #1 } { d<> ={note} O{} }
          {
            \tl_if_novalue:nTF { ##1 }
              { % if on all slides, write to file for first then disable
                \int_compare:nNnT { 1 } < { \beamer@slideinframe }
                  {
                    \cs_set_eq:NN \__keythms_thm_addcontentsdata:nnnn \use_none:nnnn
                    \cs_set_eq:NN \__keythms_thm_addstoredreverseddata:nnn \use_none:nnn
                  }
              }
              {
                \begin{actionenv}<##1>
                \legacy_if:nT { beamer@anotherslide }
                  { % prevent writing to file except on last slide for overlays
                    \cs_set_eq:NN \__keythms_thm_addcontentsdata:nnnn \use_none:nnnn
                    \cs_set_eq:NN \__keythms_thm_addstoredreverseddata:nnn \use_none:nnn
                  }
              }
            \begin{keythms_beamer_orig_#1}[##2]
          }
          {
            \end{keythms_beamer_orig_#1}
            \tl_if_novalue:nF { ##1 } { \end{actionenv} }
          }
        \bool_if:NT \l__keythms_thm_numbered_bool
          { \resetcounteronoverlays{ #1 } }
      }
    \file_input_stop:
  }

\tl_new:N \g__keythms_thmstyle_example_metakeys_tl
\tl_gset:Nn \g__keythms_thmstyle_example_metakeys_tl
  {
    bodyfont = \normalfont,
    headfont = \def\inserttheoremblockenv{exampleblock},
  }

\cs_set_protected:Npn \__keythms_thm_tcbcode:nn #1#2
  { % #1 = name, #2 = tcolorbox keys
    \__keythms_thm_tcbshared:nn { #1 } { #2 }
    \tl_gput_left:cn { g__keythms_thm_preheadfromkeys_#1_tl }
      {
        \cs_set:Npn \inserttheoremblockenv { keythms_beamer_tcb }
      }
  }
\cs_set_protected:Npn \__keythms_thm_tcbnotitlebarcode:nn #1#2
  { % #1 = name, #2 = tcolorbox keys
    \__keythms_thm_tcbshared:nn { #1 } { #2 }
    \tl_gput_left:cn { g__keythms_thm_preheadfromkeys_#1_tl }
      {
        \cs_set:Npn \inserttheoremblockenv { keythms_beamer_tcbnotitlebar }
      }
  }
\cs_set_protected:Npn \__keythms_thm_tcbshared:nn #1#2
  {
    \RequirePackage{tcolorbox}
    \AddToHook{env/#1/begin}
      { % fix labels adding extra space
        \keys_define:nn { keytheorems/thmuse }
          {
            label .code:n = \tcbset{ phantom = { \label{##1} } }
          }
      }
    \tcbset
      {
        keythms_tcb_#1/.style =
          {
            savedelimiter=#1,
            #2
          }
      }
      \tl_if_empty:NTF \l__keythms_thm_style_tl
        {
          \tl_set_eq:NN \l__keythms_thm_tempstyle_tl
            \l__keythms_thm_currentthmstyle_tl
        }
        { \tl_set_eq:NN \l__keythms_thm_tempstyle_tl \l__keythms_thm_style_tl }
      \tl_gput_right:ce { g__keythms_thm_preheadfromkeys_#1_tl }
        { % don't mess with tcolorbox defaults unless explicitly asked to in style
          \exp_not:N \tl_put_right:cn { th@ \l__keythms_thm_tempstyle_tl }
            { \thm@preskip=0pt \thm@postskip=0pt }
        }
      \tl_if_exist:cT
        { g__keythms_thmstyle_ \l__keythms_thm_tempstyle_tl _tcbspaceabove_skip }
        {
          \exp_args:Ne \tcbset
            {
              keythms_tcb_#1/.prefix~style =
                {
                  before~skip =
                    \skip_use:c { g__keythms_thmstyle_ \l__keythms_thm_tempstyle_tl _tcbspaceabove_skip }
                }
            }
        }
      \tl_if_exist:cT
        { g__keythms_thmstyle_ \l__keythms_thm_tempstyle_tl _tcbspacebelow_skip }
        {
          \exp_args:Ne \tcbset
            {
              keythms_tcb_#1/.prefix~style =
                {
                  after~skip =
                    \skip_use:c { g__keythms_thmstyle_ \l__keythms_thm_tempstyle_tl _tcbspacebelow_skip }
                }
            }
        }
  }
\NewDocumentEnvironment{ keythms_beamer_tcb }{ m d<> }
  {
    \tl_if_novalue:nF { #2 } { \begin{actionenv}<#2> }
    \begin{tcolorbox}[
      title={\usebeamerfont*{block~title} #1},
      keythms_tcb_\l_keythms_thmuse_envname_tl
      ]
  }
  {
    \end{tcolorbox}
    \tl_if_novalue:nF { #2 } { \end{actionenv} }
  }
\NewDocumentEnvironment{ keythms_beamer_tcbnotitlebar }{ m d<> }
  {
    \tl_if_novalue:nF { #2 } { \begin{actionenv}<#2> }
    \begin{tcolorbox}[ keythms_tcb_\l_keythms_thmuse_envname_tl ]
      \group_begin:
      \usebeamerfont*{block~title} #1
      \thmheadnl
      \hskip\thm@headsep
      \group_end:
  }
  {
    \end{tcolorbox}
    \tl_if_novalue:nF { #2 } { \end{actionenv} }
  }

\cs_set_protected:Npn \__keythms_keyify_theorem:n #1
  { % #1 = theorem name
    \DeclareEnvironmentCopy { keythms_orig_#1 } { #1 }
    \DeclareDocumentEnvironment { keythms_beamer_grab_#1 } { m m m +b }
      { % ##1 = keys, ##2 = note, ##3 = action spec, ##4 = theorem body
        \__keythms_thm_prehead_code:n { #1 }
        \tl_if_empty:nTF { ##3 }
          { \begin{keythms_orig_#1}[{##2}] }
          { \begin{keythms_orig_#1}[{##2}]<##3> }
        \clist_map_inline:Nn \g__keythms_restatecounters_clist
          {
            \prop_gput:Nne \g__keythms_thmuse_othercounters_prop { ####1 }
              { \the\value{####1} }
          }
        \__keythms_thm_posthead_code:n { #1 }
        % below needs to come after posthead so that correct \@currentHref
        % is stored for tcolorbox theorems
        \__keythms_thm_addcontentsdata:nnnn { #1 }
          { \prop_to_keyval:N \g__keythms_thmuse_othercounters_prop }
          { ##1 } { ##4 }
        \__keythms_thm_tempstorerestatedata:nnn { #1 } { ##1 } { ##4 }
        ##4
        \__keythms_thm_prefoot_code:n { #1 }
        \end{keythms_orig_#1}
        \__keythms_thm_postfoot_code:n { #1 }
      }
      {}
    \DeclareDocumentEnvironment { keythms_beamer_grabreversed_#1 } { m m m +b }
      { % ##1 = keys, ##2 = note, ##3 = action spec, ##4 = theorem body
        \tl_if_exist:cTF
          { c__keythms_storeatbegin_ \l__keythms_thmuse_storereversed_tl _restatecounters_tl }
          {
            \bool_set_true:N \l__keythms_thmuse_restating_bool
            \prop_set_from_keyval:Ne \l__keythms_restate_counters_prop
              { \tl_use:c { c__keythms_storeatbegin_ \l__keythms_thmuse_storereversed_tl _restatecounters_tl } }
            \prop_map_inline:Nn \l__keythms_restate_counters_prop
              {
                \tl_set:ce { l__keythms_restate_current_####1_tl }
                  { \the\value{####1} }
                \setcounter { ####1 } { ####2 }
                % ^ FIX: what if eq's numbered by section, theorem, etc.? The
                %        thmtools code is opaque.... Or maybe should be up to the
                %        user to say "restate-counters={section,chapter,...}".
                \cs_set:cpn { theH ####1 }
                  { \use:c { the ####1 } . \theHkeythms_restate_dummyctr }
              }
            \tl_if_empty:cTF
              { c__keythms_storeatbegin_ \l__keythms_thmuse_storereversed_tl _label_tl }
              { \refstepcounter{keythms_restate_dummyctr} } % for unnumbered theorems
              {
                \cs_set:cpn { the #1 }
                  { \tl_use:c { c__keythms_storeatbegin_ \l__keythms_thmuse_storereversed_tl _label_tl } }
                \cs_set_eq:cN { c@ #1 } \c@keythms_restate_dummyctr
                \cs_set_eq:cN { theH #1 } \theHkeythms_restate_dummyctr
                % ^ why are the last two lines here? We shouldn't be referencing
                %   restated theorems. Think it's a remnant of thmtools
                % WRONG: needed to make numbering correct after restated theorem.
                % not sure about theH. <- this is needed to prevent duplicate anchors
              }
           }
           {
             \msg_warning:nnV { keytheorems } { store-reversed-not-got }
               \l__keythms_thmuse_storereversed_tl
           }
        \__keythms_thm_prehead_code:n { #1 }
        \hook_use:n { keytheorems/#1/restated }
        \hook_use:n { keytheorems/allthms/restated }
        \tl_if_empty:nTF { ##3 }
          { \begin{keythms_orig_#1}[{##2}] }
          { \begin{keythms_orig_#1}[{##2}]<##3> }
        \__keythms_thm_posthead_code:n { #1 }
        % below needs to come after posthead so that correct \@currentHref
        % is stored for tcolorbox theorems
        \__keythms_thm_addstoredreverseddata:nnn { #1 } { ##1 } { ##4 }
        \__keythms_thm_tempstorerestatedatareversed:nnn { #1 } { ##1 } { ##4 }
        ##4
        \__keythms_thm_prefoot_code:n { #1 }
        \end{keythms_orig_#1}
        \__keythms_thm_postfoot_code:n { #1 }
        \prop_map_inline:Nn \l__keythms_restate_counters_prop
          {
            \exp_args:Nnc \setcounter { ####1 }
              { l__keythms_restate_current_####1_tl }
          }
      }
      { }
      % NOTE: have to do a lot of shenanigans to make sure the begin/end of grabbed
      %       theorem env captures only the body and no package code.
      %       This is the price of on-the-fly redefining the env to grab body
      \RenewDocumentEnvironment { #1 } { D<>{} ={note} O{} D<>{} }
        {
          \tl_set:Nn \l_keythms_thmuse_envname_tl { #1 }
          \tl_use:N \l__keythms_thmuse_defaultkeys_tl
          \keys_set:nn { keytheorems/thmuse } { ##2 }
          \tl_if_empty:NTF \l__keythms_thmuse_store_tl
            {
              \tl_if_empty:NTF \l__keythms_thmuse_storereversed_tl
                { \__keythms_thm_prehead_code:n { #1 } }
                {
                  % \bool_gset_true:N \g__keythms_listof_writefile_bool % disable writing to file
                  \cs_set_eq:NN \__keythms_beamer_withhooks_begin:nnnn \__keythms_beamer_grabreversed_begin:nnnn
                  \cs_set_eq:NN \__keythms_beamer_withhooks_end:n \__keythms_beamer_grabreversed_end:n
                }
            }
            {
              % \bool_gset_true:N \g__keythms_listof_writefile_bool % disable writing to file
              \cs_set_eq:NN \__keythms_beamer_withhooks_begin:nnnn \__keythms_beamer_grab_begin:nnnn
              \cs_set_eq:NN \__keythms_beamer_withhooks_end:n \__keythms_beamer_grab_end:n
            }
          \tl_if_empty:nTF { ##3 }
            { % if ##3 empty, just pass ##1 and withhooks_begin will check if empty
              \__keythms_beamer_withhooks_begin:nnVn { #1 } { ##2 }
                \l__keythms_thmuse_note_tl { ##1 }
            }
            { % if ##3 nonempty, always use it (beamer defaults to second <> if both given)
              \__keythms_beamer_withhooks_begin:nnVn { #1 } { ##2 }
                \l__keythms_thmuse_note_tl { ##3 }
            }
        }
        {
          \__keythms_beamer_withhooks_end:n { #1 }
          \tl_if_empty:NF \l__keythms_thmuse_store_tl
            {
              \cs_if_exist:cF
                { __keythms_getthm_ \l__keythms_thmuse_store_tl _theorem }
                {
                  \cs_new:cpe
                    { __keythms_getthm_ \l__keythms_thmuse_store_tl _theorem }
                    {
                      \exp_not:N \keythms_getthm_theorem:nnnnn
                      \exp_not:o { \g__keythms_thmuse_temprestatedata_tl }
                    }
                  \cs_new:cpe
                    { __keythms_getthm_ \l__keythms_thmuse_store_tl _body }
                    {
                      \exp_not:N \keythms_getthm_body:nnn
                      \exp_args:No \exp_not:o
                        {
                          \exp_after:wN \__keythms_use_i_iii_v_braced:nnnnn
                            \g__keythms_thmuse_temprestatedata_tl
                        }
                    }
                }
            }
          \tl_if_empty:NF \l__keythms_thmuse_storereversed_tl
            {
              \cs_if_exist:cF
                { __keythms_getthm_ \l__keythms_thmuse_storereversed_tl _theorem }
                {
                  \cs_new:cpe
                    { __keythms_getthm_ \l__keythms_thmuse_storereversed_tl _theorem }
                    {
                      \exp_not:N \__keythms_getthmreversed_theorem:nnn
                      \exp_not:o { \g__keythms_thmuse_temprestatedatareversed_tl }
                    }
                  \cs_new:cpn
                    { __keythms_getthm_ \l__keythms_thmuse_storereversed_tl _body }
                    {
                      \textbf{??}
                      \msg_warning:nnn { keytheorems } { restate-body-never-got }
                        { #1 }
                    }
                }
            }
        }
  }

\cs_new_protected:Npn \__keythms_beamer_withhooks_begin:nnnn #1#2#3#4
  { % #1 = theorem name, #2 = keys, #3 = note, #4 = action spec
    \tl_if_empty:nTF { #4 }
      { \begin{keythms_orig_#1}[{#3}] }
      { \begin{keythms_orig_#1}[{#3}]<#4> }
    \__keythms_thm_posthead_code:n { #1 }
    \__keythms_thm_addcontentsdata:nnnn { #1 } { } { #2 } { }
    \ignorespaces % I hope this is alright
  }
\cs_generate_variant:Nn \__keythms_beamer_withhooks_begin:nnnn { nnV }
\cs_new_eq:NN \__keythms_beamer_withhooks_end:n \__keythms_withhooks_end:n

\cs_new_protected:Npn \__keythms_beamer_grab_begin:nnnn #1#2#3#4
  { % #1 = theorem name, #2 = keys, #3 = note
    \begin{keythms_beamer_grab_#1}{#2}{#3}{#4}
  }
\cs_new_protected:Npn \__keythms_beamer_grab_end:n #1 { \end{keythms_beamer_grab_#1} }

\cs_new_protected:Npn \__keythms_beamer_grabreversed_begin:nnnn #1#2#3#4
  { % #1 = theorem name, #2 = keys, #3 = note
    \begin{keythms_beamer_grabreversed_#1}{#2}{#3}{#4}
  }
\cs_new_protected:Npn \__keythms_beamer_grabreversed_end:n #1
  { \end{keythms_beamer_grabreversed_#1} }
  
% for now, just disable writing to file
\cs_set_eq:NN \__keythms_thm_addcontentsdata:nnnn \use_none:nnnn
\cs_set_eq:NN \__keythms_thm_addstoredreverseddata:nnn \use_none:nnn

\cs_new_protected:Npn \__keythms_beamer_reversedauxdata:nnnn #1#2#3#4
  {
    \iow_shipout:Ne \@auxout
      {
        \token_to_str:N \KeyThmsBeamerReversedData { \l__keythms_thmuse_storereversed_tl }
          { \@currentlabel }
          { #2 }
      }
  }
\cs_new_protected:Npn \KeyThmsBeamerReversedData #1#2#3
  {
    \tl_if_exist:cF { c__keythms_storeatbegin_#1_label_tl }
      {
        \tl_const:cn { c__keythms_storeatbegin_#1_label_tl } { #2 }
      }
    \tl_if_exist:cF { c__keythms_storeatbegin_#1_restatecounters_tl }
      {
        \tl_const:cn { c__keythms_storeatbegin_#1_restatecounters_tl } { #3 }
      }
    \bool_if_exist:cF { g__keythms_restate_#1_called_bool }
      { \bool_new:c { g__keythms_restate_#1_called_bool } }
  }
\cs_new_eq:NN \__keythms_ORIGgetthmreversed_theorem:nnn
  \__keythms_getthmreversed_theorem:nnn
\cs_set_protected:Npn \__keythms_getthmreversed_theorem:nnn #1#2#3
  {
    \group_begin:
    \cs_set_eq:NN \__keythms_thm_addcontentsdata:nnnn \__keythms_beamer_reversedauxdata:nnnn
    \__keythms_ORIGgetthmreversed_theorem:nnn { #1 } { #2 } { #3 }
    \group_end:
  }

\file_input_stop: