require 'fileutils'
class Theme < ApplicationRecord
  belongs_to :user, required: false

  attr_accessor :archive_update_required
  enum day_frame: {white: '@builtin/white', black: '@builtin/black'}, _prefix: 'day_frame'

  preview_opts = {styles: {}}
  %w(png webp).each do |fmt|
    [500, 300, 100].each do |size|
      preview_opts[:styles]["#{fmt}#{size}".to_sym] =
        {geometry: "#{size}x#{size}>", format: fmt}
      fmt == "webp" and
        preview_opts[:styles]["#{fmt}#{size}".to_sym][:convert_options] = "-quality 75"
    end
  end

  4.times do |idx|
    has_attached_file "preview#{idx+1}", preview_opts
  end

  archive_opts = {
    path: ':rails_root/data/attachments/:class/:attachment/:id_partition/:style/:filename',
    processors: [],
  }
  has_attached_file :orig_archive, archive_opts
  has_attached_file :theme_archive, archive_opts

  validates :name, :author, presence: true
  validates :name, length: {maximum: 60}
  validates :url, :license_other_url, format: { with: %r{\Ahttps?://[a-z0-9-]+(\.[a-z0-9-]+)+}i }, allow_blank: true

  validates_attachment :preview1, :preview2, :preview3, :preview4,
    content_type: {content_type: /\Aimage\//}
  validates_attachment :orig_archive, :theme_archive,
    content_type: {content_type: %w(application/zip)}

  before_save :set_archive_update_required
  after_save :auto_update_archive

  def draft=(draft)
    draft.kind_of?(Draft) or draft = Draft.find_by!(key: draft)
    %i(name author url).each do |attr|
      self.public_send "#{attr}?" and next
      self.public_send "#{attr}=", draft.public_send(attr)
    end
    self.day_frame = draft.day_frame
    [
      Forecast::WEATHER_SYM_CLEAR_D,
      Forecast::WEATHER_SYM_CLEAR_D + Forecast::WEATHER_SYM_RAIN,
      Forecast::WEATHER_SYM_SNOW + Forecast::WEATHER_SYM_CLEAR_N,
      Forecast::WEATHER_SYM_CLOUD + Forecast::WEATHER_SYM_THUNDER,
    ].each_with_index do |ic, idx|
      draft.public_send("wi_#{ic}?") or next
      File.open(draft.public_send("wi_#{ic}").path) do |f|
        self.public_send "preview#{idx+1}=", f
      end
    end
    {theme: :theme_image, orig: :orig}.each do |t_name, d_name|
      fh = nil
      begin
        path = draft.public_send("#{d_name}_archive") or next
        fh = File.open(path)
        public_send "#{t_name}_archive=", fh
      ensure
        begin
          fh && fh.close
        rescue
          # ignore
        end
      end
    end
    draft
  end
  alias_method :draft_key=, :draft=

  def update_archives
    update_orig_archive
    update_theme_archive
  end

  def update_orig_archive
    orig_archive? or return
    if new_record?
      self.archive_update_required = true
      logger.warn "update_orig_archive is called before seve. Setting update hook and ignore..."
      return
    end
    tmp_path = _zip_tmp_path('orig-archive')
    FileUtils.cp (orig_archive.dirty? ? orig_archive.staged_path : orig_archive.path), tmp_path
    readme_name = 'ThemeDetails.html'
    Tempfile.open(readme_name) do |temp|
      temp << %Q{<!DOCTYPE html>\n<script>window.location.href="#{Rails.application.routes.url_helpers.theme_url(self)}";</script>}
      temp.flush
      Zip::File.open(tmp_path) do |zf|
        if zf.find_entry readme_name
          zf.replace readme_name, temp.path
        else
          zf.add readme_name, temp.path
        end
      end
    end
    tmp_path.open do |f|
      self.orig_archive = f
    end
    save
  end

  def update_theme_archive
    theme_archive? or return
    if new_record?
      self.archive_update_required = true
      logger.warn "update_theme_archive is called before seve. Setting update hook and ignore..."
      return
    end
    tmp_path = _zip_tmp_path('theme-archive')
    FileUtils.cp theme_archive.path, tmp_path
    info_json = 'theme.json'
    Tempfile.open(info_json) do |temp|
      temp << ThemeDefinition.new(theme: self).to_json
      temp.flush
      Zip::File.open(tmp_path) do |zf|
        if zf.find_entry info_json
          zf.replace info_json, temp.path
        else
          zf.add info_json, temp.path
        end
      end
    end
    tmp_path.open do |f|
      self.theme_archive = f
    end
    save
  end

  def set_archive_update_required
    new_record? or return true
    self.archive_update_required = true
  end

  def auto_update_archive
    self.archive_update_required or return true
    self.archive_update_required = false
    update_archives
    true
  end

  def as_json(opts = {})
    ret = super
    ret["path"] = Rails.application.routes.url_helpers.theme_path(self)
    ret
  end
end
