/+
- Name: SisuDoc Spine, Doc Reform [a part of]
  - Description: documents, structuring, processing, publishing, search
    - static content generator

  - Author: Ralph Amissah
    [ralph.amissah@gmail.com]

  - Copyright: (C) 2015 - 2025 Ralph Amissah, All Rights Reserved.

  - License: AGPL 3 or later:

    Spine (SiSU), a framework for document structuring, publishing and
    search

    Copyright (C) Ralph Amissah

    This program is free software: you can redistribute it and/or modify it
    under the terms of the GNU AFERO General Public License as published by the
    Free Software Foundation, either version 3 of the License, or (at your
    option) any later version.

    This program is distributed in the hope that it will be useful, but WITHOUT
    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
    more details.

    You should have received a copy of the GNU General Public License along with
    this program. If not, see [https://www.gnu.org/licenses/].

    If you have Internet connection, the latest version of the AGPL should be
    available at these locations:
    [https://www.fsf.org/licensing/licenses/agpl.html]
    [https://www.gnu.org/licenses/agpl.html]

  - Spine (by Doc Reform, related to SiSU) uses standard:
    - docReform markup syntax
      - standard SiSU markup syntax with modified headers and minor modifications
    - docReform object numbering
      - standard SiSU object citation numbering & system

  - Homepages:
    [https://www.sisudoc.org]
    [https://www.doc-reform.org]

  - Git
    [https://git.sisudoc.org/]

+/
module sisudoc.meta.metadoc;
@safe:
template spineAbstraction() {
  import
    std.datetime,
    std.digest.crc,
    std.digest.sha;
  import
    sisudoc.meta,
    sisudoc.meta.metadoc_from_src,
    sisudoc.meta.conf_make_meta_structs,
    sisudoc.meta.conf_make_meta_json,
    sisudoc.meta.defaults,
    sisudoc.io_in.paths_source,
    sisudoc.io_in.read_config_files,
    sisudoc.io_in.read_source_files,
    sisudoc.io_out.hub;
  mixin spineBiblio;
  mixin outputHub;
  enum makeMeta { make, meta }
  enum docAbst  { doc_abstract_obj, doc_has }
  @system auto spineAbstraction(E,P,O,Cfg,M)(
    E             _env,
    P             program_info,
    O             _opt_action,
    Cfg           _cfg,
    M             _manifest,
    ConfComposite _make_and_meta_struct
  ){
    { /+ document config/make file +/
      auto _config_document_struct = readConfigDoc!()(_manifest, _env);
      import sisudoc.meta.conf_make_meta_yaml;
      _make_and_meta_struct = _config_document_struct.configParseYAMLreturnSpineStruct!()(_make_and_meta_struct, _manifest, _opt_action, _cfg);
    }
    /+ ↓ read file (filename with path) +/
    /+ ↓ file tuple of header and content +/
    if ((_opt_action.debug_do)
      || (_opt_action.debug_do_stages)
    ) {
      writeln("step1 commence → (get document header & body & insert file list & if needed image list) [", _manifest.src.filename, "]");
    }
    auto _header_body_insertfilelist_imagelist
      = spineRawMarkupContent!()(_opt_action, _manifest.src.path_and_fn);
    auto doc_digests = _header_body_insertfilelist_imagelist.doc_digest; // CHECK, REVIEW, discard likely, other route taken
    if ((_opt_action.debug_do)
      || (_opt_action.debug_do_stages)
    ) {
      writeln("- step1 complete for [", _manifest.src.filename, "]");
    }
    debug(header_and_body) {
      writeln(header);
      writeln(_header_body_insertfilelist_imagelist.length);
      // writeln(_header_body_insertfilelist_imagelist.length.body_content[0]);
    }
    /+ ↓ split header into make and meta +/
    if ((_opt_action.debug_do)
      || (_opt_action.debug_do_stages)
    ) {
      writeln("step2 commence → (read document header (yaml) return struct) [", _manifest.src.filename, "]");
    }
    import sisudoc.meta.conf_make_meta_yaml;
    _make_and_meta_struct =
      docHeaderMakeAndMetaTupYamlExtractAndConvertToStruct!()(
        _header_body_insertfilelist_imagelist.header_raw,
        _make_and_meta_struct,
        _manifest,
        _opt_action,
        _cfg,
      );
    if ((_opt_action.debug_do)
      || (_opt_action.debug_do_stages)
    ) {
      writeln("- step2 complete for [", _manifest.src.filename, "]");
    }
    /+ ↓ document abstraction: process document, return abstraction as tuple +/
    if ((_opt_action.debug_do)
      || (_opt_action.debug_do_stages)
    ) {
      writeln("step3 commence → (document abstraction (da); da keys; segnames; doc_matters) [", _manifest.src.filename, "]");
    }
    auto da = docAbstraction!()(
      _header_body_insertfilelist_imagelist.sourcefile_body_content,
      _make_and_meta_struct,
      _opt_action,
      _manifest,
      true,
    );
    auto doc_abstraction = da.document_the;
    auto _doc_has_struct = da.doc_has;
    if ((_opt_action.debug_do)
      || (_opt_action.debug_do_stages)
    ) {
      writeln("- step3 complete for [", _manifest.src.filename, "]");
    }
    if ((_opt_action.debug_do)
      || (_opt_action.debug_do_stages)
    ) {
      writeln("step4 commence → (doc.matters) [", _manifest.src.filename, "]");
    }
    struct ST_DocumentMatters {
      auto generator_program() {
        struct Prog_ {
          string project_name() {
            return "spine";
          }
          string name() {
            return program_info.name;
          }
          string ver() {
            return program_info.ver;
          }
          @trusted string name_and_version() {
            return program_info.name_and_version;
          }
          @trusted string name_version_and_compiler() {
            return program_info.name_version_and_compiler;
          }
          string url_home() {
            return "https://sisudoc.org";
          }
          string url_git() {
            return "https://git.sisudoc.org/projects/";
          }
          auto compiler() {
            return program_info.compiler;
          }
          auto time_output_generated() {
            return program_info.time_output_generated;
          }
        }
        return Prog_();
      }
      auto generated_time() {
        auto _st = Clock.currTime(UTC());
        auto _time = _st.year.to!string
          ~ "-" ~ _st.month.to!int.to!string // prefer as month number
          ~ "-" ~ _st.day.to!string
          ~ " [" ~ _st.isoWeek.to!string ~ "/" ~ _st.dayOfWeek.to!int.to!string ~ "]"
          ~ " " ~ _st.hour.to!string
          ~ ":" ~ _st.minute.to!string
          ~ ":" ~ _st.second.to!string;
        return _time;
      }
      ConfComposite conf_make_meta() {
        return _make_and_meta_struct;
      }
      auto doc_digest() {
        return doc_digests;
      }
      auto has() {
        return _doc_has_struct;
      }
      auto env() {
        struct Env_ {
          auto pwd() {
            return _manifest.env.pwd;
          }
          auto home() {
            return _manifest.env.home;
          }
        }
        return Env_();
      }
      auto opt() {
        struct Opt_ {
          auto action() {
            /+ getopt options, commandline instructions, raw
             - processing instructions --epub --html etc.
             - command line config instructions --output
            +/
            return _opt_action;
          }
        }
        return Opt_();
      }
      auto src() {
        return _manifest.src;
      }
      auto src_path_info() {
        return spinePathsSRC!()(_manifest.env.pwd, _manifest.src.file_with_absolute_path); // would like (to have and use) relative path
      }
      auto pod() {
        return _manifest.pod;
      }
      auto sqlite() {
        struct SQLite_ {
          string filename() {
            string _fn = "";
            string _pth = "";
            if (_opt_action.sqliteDB_filename.length > 0) {
              _fn = _opt_action.sqliteDB_filename;
            } else if (_make_and_meta_struct.conf.w_srv_db_sqlite_filename.length > 0) {
              _fn = _make_and_meta_struct.conf.w_srv_db_sqlite_filename;
            }
            return _fn;
          }
          string path() {
            string _pth = "";
            if (_opt_action.sqliteDB_path.length > 0) {
              _pth = _opt_action.sqliteDB_path;
            } else if (_make_and_meta_struct.conf.w_srv_db_sqlite_path.length > 0) {
              _pth = _make_and_meta_struct.conf.w_srv_db_sqlite_path;
            }
            return _pth;
          }
          string cgi_filename() {
            string _fn = "";
            if (_opt_action.cgi_sqlite_search_filename.length > 0) {
              _fn = _opt_action.cgi_sqlite_search_filename;
            } else if (_make_and_meta_struct.conf.w_srv_cgi_search_script.length > 0) {
              _fn = _make_and_meta_struct.conf.w_srv_cgi_search_script;
            }
            return _fn;
          }
          string cgi_filename_d() {
            string _fn = "";
            if (_opt_action.cgi_sqlite_search_filename_d.length > 0) {
              _fn = _opt_action.cgi_sqlite_search_filename_d;
            } else if (_make_and_meta_struct.conf.w_srv_cgi_search_script_raw_fn_d.length > 0) {
              _fn = _make_and_meta_struct.conf.w_srv_cgi_search_script_raw_fn_d;
            }
            return _fn;
          }
        }
        return SQLite_();
      }
      auto output_path() {
        return _make_and_meta_struct.conf.output_path;
      }
      auto srcs() {
        struct SRC_ {
          auto file_insert_list() {
            return _header_body_insertfilelist_imagelist.insert_file_list;
          }
          auto image_list() {
            return _doc_has_struct.imagelist;
          }
        }
        return SRC_();
      }
    }
    auto doc_matters = ST_DocumentMatters();
    if ((_opt_action.debug_do)
      || (_opt_action.debug_do_stages)
    ) {
      writeln("- step4 complete for [", _manifest.src.filename, "]");
    }
    auto theDOC() {
      struct ST_DOC {
        const auto abstraction() {
          return doc_abstraction;
        }
        auto matters() {
          return doc_matters;
        }
      }
      return ST_DOC();
    }
    auto the_doc = theDOC();
    return the_doc;
  }
}