# frozen_string_literal: true

#
# Copyright (C) 2011 - present Instructure, Inc.
#
# This file is part of Canvas.
#
# Canvas is free software: you can redistribute it and/or modify it under
# the terms of the GNU Affero General Public License as published by the Free
# Software Foundation, version 3 of the License.
#
# Canvas 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 Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
#

module CC
  module WebResources
    def file_or_folder_restricted?(obj)
      obj.hidden? || obj.locked || obj.unlock_at || obj.lock_at
    end

    def content_zipper
      @zipper ||= ContentZipper.new
      @zipper.user = @user
      @zipper
    end

    def add_course_files
      return if for_course_copy

      referenced_folders = {}
      media_folder_name = Folder.media_folder(@course).name
      @html_exporter.referenced_files.each do |att_id, att|
        add_item_to_export("attachment_#{att_id}", "attachments")
        next if att.context_type == "Course"

        path = if att.context_type == "User"
                 referenced_folders[media_folder_name] ||= Folder.media_folder(@course)
                 "#{CCHelper::WEB_RESOURCES_FOLDER}/#{media_folder_name}/#{att.display_name}"
               elsif att.context_type == "AssessmentQuestion"
                 referenced_folders["assessment_questions"] ||= Folder.new(name: "assessment_questions", full_name: "assessment_questions", hidden: true)
                 "#{CCHelper::WEB_RESOURCES_FOLDER}/assessment_questions#{att.full_display_path}"
               end
        add_file_to_manifest(att, path, create_key(att))
        content_zipper.add_attachment_to_zip(att, @zip_file, path)
      end

      @added_attachments = {}

      course_folder = Folder.root_folders(@course).first
      folders = referenced_folders.map { |name, folder| [folder, name] }
      files_with_metadata = { folders:, files: [] }
      content_zipper.process_folder(
        course_folder,
        @zip_file,
        [CCHelper::WEB_RESOURCES_FOLDER],
        exporter: @manifest.exporter,
        referenced_files: @html_exporter.referenced_files
      ) do |file, folder_names|
        next if file.display_name.blank?

        if file.is_a? Folder
          dir = File.join(folder_names[1..])
          files_with_metadata[:folders] << [file, dir] if file_or_folder_restricted?(file) && export_symbol?(nil) # hacky way of checking selective exports
          next
        end

        path = File.join(folder_names, file.display_name)
        @added_attachments[file.id] = path
        migration_id = create_key(file)
        if file_or_folder_restricted?(file) || file.usage_rights || file.display_name != file.unencoded_filename || file.category == Attachment::ICON_MAKER_ICONS
          files_with_metadata[:files] << [file, migration_id]
        end
        add_file_to_manifest(file, path, migration_id)
      rescue
        title = file.try(:unencoded_filename) || I18n.t("course_exports.unknown_titles.file", "Unknown file")
        add_error(I18n.t("course_exports.errors.file", "The file \"%{file_name}\" failed to export", file_name: title), $!)
      end

      add_meta_info_for_files(files_with_metadata)
    end

    def add_file_to_manifest(file, path, migration_id)
      @resources.resource(
        "type" => CCHelper::WEBCONTENT,
        :identifier => migration_id,
        :href => path
      ) do |res|
        if file.locked || file.usage_rights
          res.metadata do |meta_node|
            meta_node.lom :lom do |lom_node|
              if file.locked
                lom_node.lom :educational do |edu_node|
                  edu_node.lom :intendedEndUserRole do |role_node|
                    role_node.lom :source, "IMSGLC_CC_Rolesv1p1"
                    role_node.lom :value, "Instructor"
                  end
                end
              end
              if file.usage_rights
                lom_node.lom :rights do |rights_node|
                  rights_node.lom :copyrightAndOtherRestrictions do |node|
                    node.lom :value, (file.usage_rights.license == "public_domain") ? "no" : "yes"
                  end
                  description = []
                  description << file.usage_rights.legal_copyright if file.usage_rights.legal_copyright.present?
                  description << file.usage_rights.license_name unless file.usage_rights.license == "private"
                  rights_node.lom :description do |desc|
                    desc.lom :string, description.join('\n')
                  end
                end
              end
            end
          end
        end
        res.file(href: path)
      end
    end

    def files_meta_path
      File.join(CCHelper::COURSE_SETTINGS_DIR, CCHelper::FILES_META)
    end

    def add_meta_info_for_files(files)
      files_file = File.new(File.join(@canvas_resource_dir, CCHelper::FILES_META), "w")
      rel_path = files_meta_path
      document = Builder::XmlMarkup.new(target: files_file, indent: 2)

      document.instruct!
      document.fileMeta(
        "xmlns" => CCHelper::CANVAS_NAMESPACE,
        "xmlns:xsi" => "http://www.w3.org/2001/XMLSchema-instance",
        "xsi:schemaLocation" => "#{CCHelper::CANVAS_NAMESPACE} #{CCHelper::XSD_URI}"
      ) do |root_node|
        unless files[:folders].empty?
          root_node.folders do |folders_node|
            files[:folders].each do |folder, path|
              folders_node.folder(path:) do |folder_node|
                folder_node.locked "true" if folder.locked
                folder_node.hidden "true" if folder.hidden?
                folder_node.lock_at CCHelper.ims_datetime(folder.lock_at) if folder.lock_at
                folder_node.unlock_at CCHelper.ims_datetime(folder.unlock_at) if folder.unlock_at
              end
            end
          end
        end

        unless files[:files].empty?
          root_node.files do |files_node|
            files[:files].each do |file, migration_id|
              files_node.file(identifier: migration_id) do |file_node|
                file_node.locked "true" if file.locked
                file_node.hidden "true" if file.hidden?
                file_node.lock_at CCHelper.ims_datetime(file.lock_at) if file.lock_at
                file_node.unlock_at CCHelper.ims_datetime(file.unlock_at) if file.unlock_at
                file_node.display_name file.display_name if file.display_name != file.unencoded_filename
                file_node.category file.category
                if file.usage_rights
                  file_node.usage_rights(use_justification: file.usage_rights.use_justification) do |node|
                    node.legal_copyright file.usage_rights.legal_copyright if file.usage_rights.legal_copyright.present?
                    node.license file.usage_rights.license if file.usage_rights.license.present?
                  end
                end
              end
            end
          end
        end
      end

      files_file&.close
      rel_path
    end

    def attachments_for_export(folder)
      opts = { exporter: @manifest.exporter, referenced_files: @html_exporter.referenced_files, ignore_updated_at: true }
      attachments_for_export = []
      attachments_for_export += content_zipper.folder_attachments_for_export(folder, opts)
      folder.active_sub_folders.each do |sub_folder|
        attachments_for_export += attachments_for_export(sub_folder)
      end
      attachments_for_export
    end

    def process_media_tracks
      attachments = attachments_for_export(Folder.root_folders(@course).first)
      attachments += Attachment.where(context: @course, media_entry_id: @html_exporter.used_media_objects.map(&:media_id))
      attachments += Attachment.where(context: @course, id: @html_exporter.referenced_files.keys).where.not(media_entry_id: nil)

      att_map = attachments.index_by(&:id)
      Attachment.media_tracks_include_originals(attachments).each_with_object({}) do |mt, tracks|
        file = att_map[mt.for_att_id]
        migration_id = create_key(file)
        tracks[migration_id] ||= []
        tracks[migration_id] << {
          kind: mt.kind,
          locale: mt.locale,
          identifierref: create_key(mt.content),
          content: mt.content
        }
        add_exported_asset(mt)
      end
    end

    def add_tracks(track_map)
      tracks_file = File.new(File.join(@canvas_resource_dir, CCHelper::MEDIA_TRACKS), "w")
      document = Builder::XmlMarkup.new(target: tracks_file, indent: 2)
      document.instruct!
      document.media_tracks(
        "xmlns" => CCHelper::CANVAS_NAMESPACE,
        "xmlns:xsi" => "http://www.w3.org/2001/XMLSchema-instance",
        "xsi:schemaLocation" => "#{CCHelper::CANVAS_NAMESPACE} #{CCHelper::XSD_URI}"
      ) do |root_node|
        track_map.each do |file_id, track_list|
          # <media identifierref='(media file resource id)'>
          root_node.media(identifierref: file_id) do |media_node|
            track_list.each do |track|
              # <track identifierref='(srt resource id)' kind='subtitles' locale='en'/>
              media_node.track(track[:content], track.slice(:kind, :locale, :identifierref))
            end
          end
        end
      end
      tracks_file.close
    end

    def add_media_tracks
      track_map = process_media_tracks
      add_tracks(track_map)
    end

    def export_media_objects?
      CanvasKaltura::ClientV3.config && !for_course_copy
    end
  end
end
