# frozen_string_literal: true

# Redmine plugin for Document Management System "Features"
#
# Karel Pičman <karel.picman@kontron.com>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# 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, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

module RedmineDmsf
  # Macros
  module Macros
    Redmine::WikiFormatting::Macros.register do
      # dmsf - link to a document
      desc %{Wiki link to DMSF file:
               {{dmsf(file_id [, title [, revision_id]])}}
           _file_id_ / _revision_id_ can be found in the link for file/revision download.}
      macro :dmsf do |_obj, args|
        raise ArgumentError if args.empty? # Requires file id

        file = DmsfFile.visible.find_by(id: args[0])
        return "{{dmsf(#{args[0]})}}" unless file
        unless User.current&.allowed_to?(:view_dmsf_files, file.project, { id: file.id })
          raise ::I18n.t(:notice_not_authorized)
        end

        if args[2].blank?
          revision = file.last_revision
        else
          revision = DmsfFileRevision.find_by(id: args[2], dmsf_file_id: args[0])
          return "{{dmsf(#{args[0]}, #{args[1]}, #{args[2]})}" unless revision
        end
        title = args[1].presence || file.title
        title.gsub!(/\A"|"\z/, '') # Remove apostrophes
        title.gsub!(/\A'|'\z/, '')
        title = file.title if title.empty?
        url = view_dmsf_file_url(id: file.id, download: args[2])
        link_to h(title), url,
                target: '_blank',
                rel: 'noopener',
                title: h(revision.tooltip),
                'data-downloadurl' => "#{file.last_revision.detect_content_type}:#{h(file.name)}:#{url}"
      end

      # dmsff - link to a folder
      desc %{Wiki link to DMSF folder:
               {{dmsff([folder_id [, title]])}}
           _folder_id_ can be found in the link for folder opening. Without arguments return link to main folder
           'Documents'}
      macro :dmsff do |_obj, args|
        if args.empty?
          unless User.current.allowed_to?(:view_dmsf_folders, @project) && @project.module_enabled?(:dmsf)
            raise ::I18n.t(:notice_not_authorized)
          end

          return link_to ::I18n.t(:link_documents), dmsf_folder_url(@project)
        else
          folder = DmsfFolder.visible.find_by(id: args[0])
          return "{{dmsff(#{args[0]})}}" unless folder
          raise ::I18n.t(:notice_not_authorized) unless User.current&.allowed_to?(:view_dmsf_folders, folder.project)

          title = args[1].presence || folder.title
          title.gsub!(/\A"|"\z/, '') # Remove leading and trailing apostrophe
          title.gsub!(/\A'|'\z/, '')
          title = folder.title if title.empty?
          link_to h(title), dmsf_folder_url(folder.project, folder_id: folder)
        end
      end

      # dmsfd - link to the document's details
      desc %{Wiki link to DMSF document details:
               {{dmsfd(document_id [, title])}}
           _document_id_ can be found in the document's details.}
      macro :dmsfd do |_obj, args|
        raise ArgumentError if args.empty? # Requires file id

        file = DmsfFile.visible.find_by(id: args[0])
        return "{{dmsfd(#{args[0]})}}" unless file
        raise ::I18n.t(:notice_not_authorized) unless User.current&.allowed_to?(:view_dmsf_files, file.project)

        title = args[1].presence || file.title
        title.gsub!(/\A"|"\z/, '') # Remove leading and trailing apostrophe
        title.gsub!(/\A'|'\z/, '')
        link_to h(title), dmsf_file_path(id: file)
      end

      # dmsfdesc - text referring to the document's description
      desc %{Text referring to DMSF document description:
             {{dmsfdesc(document_id)}}
             _document_id_ can be found in the document's details.}
      macro :dmsfdesc do |_obj, args|
        raise ArgumentError if args.empty? # Requires file id

        file = DmsfFile.visible.find_by(id: args[0])
        return "{{dmsfdesc(#{args[0]})}}" unless file
        raise ::I18n.t(:notice_not_authorized) unless User.current&.allowed_to?(:view_dmsf_files, file.project)

        textilizable file.description
      end

      # dmsfversion - text referring to the document's version
      desc %{Text referring to DMSF document version:
             {{dmsfversion(document_id [, revision_id])}}
             _document_id_ can be found in the document's details.}
      macro :dmsfversion do |_obj, args|
        raise ArgumentError if args.empty? # Requires file id

        file = DmsfFile.visible.find_by(id: args[0])
        return "{{dmsfversion(#{args[0]})}}" unless file
        unless User.current&.allowed_to?(:view_dmsf_files, file.project, { id: file.id })
          raise ::I18n.t(:notice_not_authorized)
        end

        if args[1].blank?
          revision = file.last_revision
        else
          revision = DmsfFileRevision.find_by(id: args[1], dmsf_file_id: args[0])
          return "{{dmsfversion(#{args[0]}, #{args[1]})}}" unless revision
        end
        textilizable revision.version
      end

      # dmsflastupdate - text referring to the document's last update date
      desc %{Text referring to DMSF document last update date:
             {{dmsflastupdate(document_id)}}
             _document_id_ can be found in the document's details.}
      macro :dmsflastupdate do |_obj, args|
        raise ArgumentError if args.empty? # Requires file id

        file = DmsfFile.visible.find_by(id: args[0])
        return "{{dmsflastupdate(#{args[0]})}}" unless file
        raise ::I18n.t(:notice_not_authorized) unless User.current&.allowed_to?(:view_dmsf_files, file.project)

        textilizable format_time(file.last_revision.updated_at)
      end

      # dmsft - link to the document's content preview
      desc %{Text referring to DMSF text document content:
               {{dmsft(file_id, lines_count)}}
           _file_id_ can be found in the document's details. _lines_count_ indicates quantity of lines to show.}
      macro :dmsft do |_obj, args|
        raise ArgumentError if args.length < 2 # Requires file id and lines number

        file = DmsfFile.visible.find_by(id: args[0])
        return "{{dmsft(#{args[0]}, #{args[1]})}}" unless file
        raise ::I18n.t(:notice_not_authorized) unless User.current&.allowed_to?(:view_dmsf_files, file.project)

        content_tag :pre, file.text_preview(args[1])
      end

      # dmsf_image - link to an image
      desc %{Wiki DMSF image:
                 {{dmsf_image(file_id)}}
                 {{dmsf_image(file_id1 file_id2 file_id3)}} -- multiple images
                 {{dmsf_image(file_id, size=50%)}} -- with size 50%
                 {{dmsf_image(file_id, size=300)}} -- with size 300
                 {{dmsf_image(file_id, height=300)}} -- with height (auto width)
                 {{dmsf_image(file_id, width=300)}} -- with width (auto height)
                 {{dmsf_image(file_id, size=640x480)}} -- with size 640x480"}
      macro :dmsf_image do |_obj, args|
        raise ArgumentError if args.empty? # Requires file id

        args, options = extract_macro_options(args, :size, :width, :height, :title)
        size = options[:size]
        width = options[:width]
        height = options[:height]
        ids = args[0].split
        html = []
        ids.each do |id|
          file = DmsfFile.visible.find_by(id: id)
          unless file
            html << "{{dmsf_image(#{args[0]})}}"
            next
          end
          raise ::I18n.t(:notice_not_authorized) unless User.current&.allowed_to?(:view_dmsf_files, file.project)
          raise ::I18n.t(:error_not_supported_image_format) unless file.image?

          member = Member.find_by(user_id: User.current.id, project_id: file.project.id)
          filename = file.last_revision.formatted_name(member)
          url = static_dmsf_file_url(file, filename: filename)
          html << if size&.include?('%')
                    image_tag url, alt: filename, title: file.title, width: size, height: size
                  elsif height
                    image_tag url, alt: filename, title: file.title, width: 'auto', height: height
                  elsif width
                    image_tag url, alt: filename, title: file.title, width: width, height: 'auto'
                  else
                    image_tag url, alt: filename, title: file.title, size: size
                  end
        end
        safe_join html
      end

      # dmsf_video - link to a video
      desc %{Wiki DMSF video:
               {{dmsf_video(file_id)}}\n" +
               {{dmsf_video(file_id, size=50%)}} -- with size 50%
               {{dmsf_video(file_id, size=300)}} -- with size 300x300
               {{dmsf_video(file_id, height=300)}} -- with height (auto width)
               {{dmsf_video(file_id, width=300)}} -- with width (auto height)
               {{dmsf_video(file_id, size=640x480)}} -- with size 640x480}
      macro :dmsf_video do |_obj, args|
        raise ArgumentError if args.empty? # Requires file id

        args, options = extract_macro_options(args, :size, :width, :height, :title)
        size = options[:size]
        width = options[:width]
        height = options[:height]
        file = DmsfFile.visible.find_by(id: args[0])
        return "{{dmsf_video(#{args[0]})}}" unless file
        raise ::I18n.t(:notice_not_authorized) unless User.current&.allowed_to?(:view_dmsf_files, file.project)
        raise ::I18n.t(:error_not_supported_video_format) unless file.video?

        member = Member.find_by(user_id: User.current.id, project_id: file.project.id)
        filename = file.last_revision.formatted_name(member)
        url = static_dmsf_file_url(file, filename: filename)
        if size&.include?('%')
          video_tag url, controls: true, alt: filename, title: file.title, width: size, height: size
        elsif height
          video_tag url, controls: true, alt: filename, title: file.title, width: 'auto', height: height
        elsif width
          video_tag url, controls: true, alt: filename, title: file.title, width: width, height: 'auto'
        else
          video_tag url, controls: true, alt: filename, title: file.title, size: size
        end
      end

      # dmsftn - link to an image thumbnail
      desc %{Wiki DMSF thumbnail:
                 {{dmsftn(file_id)}} -- with default height 200 (auto width)
                 {{dmsftn(file_id1 file_id2 file_id3)}} -- multiple thumbnails
                 {{dmsftn(file_id, size=300)}} -- with size 300x300
                 {{dmsftn(file_id, height=300)}} -- with height (auto width)
                 {{dmsftn(file_id, width=300)}} -- with width (auto height)
                 {{dmsftn(file_id, size=640x480)}} -- with size 640x480}
      macro :dmsftn do |_obj, args|
        raise ArgumentError if args.empty? # Requires file id

        args, options = extract_macro_options(args, :size, :width, :height, :title)
        size = options[:size]
        width = options[:width]
        height = options[:height]
        ids = args[0].split
        html = []
        ids.each do |id|
          file = DmsfFile.visible.find_by(id: id)
          unless file
            html << "{{dmsftn(#{id})}}"
            next
          end
          raise ::I18n.t(:notice_not_authorized) unless User.current&.allowed_to?(:view_dmsf_files, file.project)
          raise ::I18n.t(:error_not_supported_image_format) unless file.image?

          member = Member.find_by(user_id: User.current.id, project_id: file.project.id)
          filename = file.last_revision.formatted_name(member)
          url = static_dmsf_file_url(file, filename: filename)
          img = if size
                  image_tag(url, alt: filename, title: file.title, size: size)
                elsif height
                  image_tag(url, alt: filename, title: file.title, width: 'auto', height: height)
                elsif width
                  image_tag(url, alt: filename, title: file.title, width: width, height: 'auto')
                else
                  image_tag(url, alt: filename, title: file.title, width: 'auto', height: 200)
                end
          html << link_to(img, url,
                          target: '_blank',
                          rel: 'noopener',
                          title: h(file.last_revision.try(:tooltip)),
                          'data-downloadurl' => "#{file.last_revision.detect_content_type}:#{h(file.name)}:#{url}")
        end
        safe_join html
      end

      # dmsfw - link to a document's approval workflow status
      desc %{Text referring to DMSF document's approval workflow status:
               {{dmsfw(file_id)}}
           _file_id_ can be found in the document's details.}
      macro :dmsfw do |_obj, args|
        raise ArgumentError if args.empty? # Requires file id

        file = DmsfFile.visible.find_by(id: args[0])
        return "{{dmsfw(#{args[0]})}}" unless file
        raise ::I18n.t(:notice_not_authorized) unless User.current&.allowed_to?(:view_dmsf_files, file.project)

        file.last_revision.workflow_str(false)
      end
    end
  end
end
