module Docx
  class Document
    include OpenXml::Docx::Elements

    def initialize
    end

    def generate
      yield(self)

      tmpfile = Tempfile.new("#{Time.current.to_f}.xlsx", Rails.root.join("tmp"))
      _document.save(tmpfile.path)
      tmpfile.path
    end

    def heading1(text)
      paragraph = create_paragraph(text)
      paragraph.paragraph_style = "Heading 1"
      _document.document << paragraph
    end

    def heading2(text)
      paragraph = create_paragraph(text)
      paragraph.paragraph_style = "Heading 2"
      _document.document << paragraph
    end

    def heading3(text)
      paragraph = create_paragraph(text)
      paragraph.paragraph_style = "Heading 3"
      _document.document << paragraph
    end

    def paragraph(text)
      html = Nokogiri::HTML5.fragment(text)
      html.search(".trix-content").each do |node|
        node.children.each do |child|
          Rails.logger.debug { "content kids: #{child.class}: #{child.name} (#{child.children.size}): #{child.text}" }
          case child
          when Nokogiri::XML::Text
            paragraph = create_paragraph(child.text)
            _document.document << paragraph
          when Nokogiri::XML::Element
            case child.name
            when "h1"
              paragraph = create_paragraph(child.text)
              paragraph.paragraph_style = "Heading 3"
            when "div"
              paragraph = Paragraph.new
              paragraph.paragraph_style = "Body Text"
              child.children.each do |node|
                Rails.logger.debug { "div kids: #{node.class}: #{node.name} (#{node.children.size}): #{node.text}" }
                case node.name
                when "strong"
                  paragraph << create_run(node.text, bold: true)
                when "em"
                  paragraph << create_run(node.text, italic: true)
                when "del"
                  paragraph << create_run(node.text, strike_through: true)
                when "br"
                  paragraph << create_run("\n")
                else
                  paragraph << create_run(node.text)
                end
              end
            when "ul"
              # paragraph = Paragraph.new
              # paragraph.paragraph_style = "Body Text"
              # # Create an abstract numbering that describes a bulleted list:
              # abstract_numbering = AbstractNumbering.new(0)

              # # Each numbering can have multiple levels. Define the first level as a bulleted list:
              # level_0 = Level.new
              # level_0.level = 0
              # level_0.start = 1
              # level_0.number_format = :bullet
              # # This is the default bullet Word uses
              # level_0.level_text = "\u00B7".encode("UTF-8")
              # level_0.alignment = :left
              # level_0.character_style.font.ascii = "Symbol"
              # level_0.character_style.font.high_ansi = "Symbol"
              # level_0.character_style.font.hint = :default
              # level_0.paragraph_style.indentation.left = 720
              # level_0.paragraph_style.indentation.hanging = 360
              # abstract_numbering << level_0

              # _document.numbering << abstract_numbering
            when "ol"
            else
              paragraph = create_paragraph(child.text)
              paragraph.paragraph_style = "Body Text"
            end

            _document.document << paragraph
          end
        end
      end
    end

    private

    def create_run(content, bold: false, italic: false, strike_through: false)
      text = Text.new(content)
      text.space = :preserve
      run = Run.new
      run.bold = bold
      run.italics = italic
      run.strikethrough = strike_through
      run << text
      run
    end

    def create_paragraph(content)
      text = case content
      when String
        Text.new(content)
      when ActionText::RichText
        Text.new(content.to_plain_text)
      else
        Text.new(content.to_s)
      end
      run = Run.new
      run << text
      paragraph = Paragraph.new
      paragraph << run
      paragraph
    end

    def _document
      @_document ||= OpenXml::Docx::Package.new
    end
  end
end
