class SiteCustomization < ActiveRecord::Base
  
  CACHE_PATH = 'stylesheet-cache'
  @lock = Mutex.new 

  before_create do 
    self.position ||= (SiteCustomization.maximum(:position) || 0) + 1
    self.enabled ||= false
    self.key ||= SecureRandom.uuid
    true
  end

  before_save do 
    if self.stylesheet_changed?
      begin 
        self.stylesheet_baked = Sass.compile self.stylesheet
      rescue Sass::SyntaxError => e
        error = e.sass_backtrace_str("custom stylesheet")
        error.gsub!("\n", '\A ')
        error.gsub!("'", '\27 ')
        
        self.stylesheet_baked = 
"#main {display: none;}
footer {white-space: pre; margin-left: 100px;}
footer:after{ content: '#{error}' }"
      end
    end
  end

  after_save do
    if self.stylesheet_changed?
      if File.exists?(self.stylesheet_fullpath)  
        File.delete self.stylesheet_fullpath 
      end
    end
    self.remove_from_cache!
    if self.stylesheet_changed?
      self.ensure_stylesheet_on_disk!
      MessageBus.publish "/file-change/#{self.key}", self.stylesheet_hash
    end
    MessageBus.publish "/header-change/#{self.key}", self.header if self.header_changed?

  end

  after_destroy do 
    if File.exists?(self.stylesheet_fullpath)  
      File.delete self.stylesheet_fullpath 
    end
    self.remove_from_cache!
  end


  def self.custom_stylesheet(preview_style)
    style = lookup_style(preview_style)
    style.stylesheet_link_tag.html_safe if style
  end

  def self.custom_header(preview_style)
    style = lookup_style(preview_style)
    style.header.html_safe if style
  end

  def self.override_default_style(preview_style)
    style = lookup_style(preview_style)
    style.override_default_style if style
  end

  def self.lookup_style(key)

    return if key.blank?
    
    # cache is cross site resiliant cause key is secure random 
    @cache ||= {}
    ensure_cache_listener
    style = @cache[key]
    return style if style
    
    @lock.synchronize do 
      style = self.where(key: key).first
      @cache[key] = style
    end
  end

  def self.ensure_cache_listener
    unless @subscribed
      klass = self
      MessageBus.subscribe("/site_customization") do |msg|
        message = msg.data
        klass.remove_from_cache!(message["key"], false) 
      end

      @subscribed = true
    end
  end

  def self.remove_from_cache!(key, broadcast=true)
    MessageBus.publish('/site_customization', {key: key}) if broadcast
    if @cache
      @lock.synchronize do 
        @cache[key] = nil
      end
    end
  end

  def remove_from_cache!
    self.class.remove_from_cache!(self.key)
  end

  def stylesheet_hash
    Digest::MD5.hexdigest(self.stylesheet)
  end

  def ensure_stylesheet_on_disk!
    path = stylesheet_fullpath
    dir = "#{Rails.root}/public/#{CACHE_PATH}"
    FileUtils.mkdir_p(dir)
    unless File.exists?(path)
      File.open(path, "w") do |f|
        f.puts self.stylesheet_baked
      end
    end
  end

  def stylesheet_filename
    file = ""
    dir = "#{Rails.root}/public/#{CACHE_PATH}"
    path = dir + file

    "/#{CACHE_PATH}/#{self.key}.css"
  end

  def stylesheet_fullpath
    "#{Rails.root}/public#{self.stylesheet_filename}"
  end

  def stylesheet_link_tag
    return "" unless self.stylesheet.present?
    return @stylesheet_link_tag if @stylesheet_link_tag
    ensure_stylesheet_on_disk!
    @stylesheet_link_tag = "<link class=\"custom-css\" rel=\"stylesheet\" href=\"#{self.stylesheet_filename}?#{self.stylesheet_hash}\" type=\"text/css\" media=\"screen\">"
  end


end